楼主: dana.quant
7079 15

[交易策略] 【量化策略】配对交易策略及其在RiceQuant量化交易平台上的实现(二) [推广有奖]

  • 0关注
  • 7粉丝

已卖:3份资源

硕士生

52%

还不是VIP/贵宾

-

威望
0
论坛币
1030 个
通用积分
0
学术水平
8 点
热心指数
14 点
信用等级
8 点
经验
3609 点
帖子
103
精华
1
在线时间
55 小时
注册时间
2015-8-30
最后登录
2016-5-17

楼主
dana.quant 企业认证  发表于 2015-9-22 12:07:11 |AI写论文

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币
第一部分在这里https://bbs.pinggu.org/thread-3906746-1-1.html
第三部分在这里~~~~https://bbs.pinggu.org/thread-3906762-1-1.html


ricequant,致力于打造亚太最出色的量化交易平台,www.ricequant.com
量化策略交流群:
Ricequant 量化策略社区 429907369  
Ricequant高校量化交流群 484490463

策略的研究与执行策略研究

我们首先用Python来选择适合交易的股票对。 用于选取的股票池为:

600815 厦工股份 机械行业
600841 上柴股份 机械行业
600855 航天长峰 机械行业
600860 京城股份 机械行业
600984 *ST建机 机械行业
601038 一拖股份 机械行业
601002 晋亿实业 机械行业
601100 恒立油缸 机械行业
601106 中国一重 机械行业
601177 XD杭齿前 机械行业

计算所用历史数据为2012年全年的日线数据。

  1. import operator
  2. import numpy as np
  3. import statsmodels.tsa.stattools as sts
  4. import matplotlib.pyplot as plt
  5. import tushare as ts
  6. import pandas as pd
  7. from datetime import datetime
  8. from scipy.stats.stats import pearsonr

  9. > sector = pd.read_csv('sector.csv', index_col=0)
  10. sector_code = sector['code'][100:110]
  11. resectorcode = sector_code.reset_index(drop=True)
  12. stockPool = []
  13. rank = {}
  14. Rank = {}
  15. for i in range(10):
  16.     stockPool.append(str(resectorcode[i])
复制代码
  1. for i in range(10):
  2.     for j in range(i+1,10):
  3.         if i != j:
  4.                 # get the price of stock from TuShare
  5.                 price_of_i = ts.get_hist_data(stockPool[i], start='2012-01-01', end='2013-01-01')
  6.                 price_of_j = ts.get_hist_data(stockPool[j], start='2012-01-01', end='2013-01-01')
  7.                 # combine the close price of the two stocks and drop the NaN
  8.                 closePrice_of_ij = pd.concat([price_of_i['close'], price_of_j['close']], axis = 1)
  9.                 closePrice_of_ij = closePrice_of_ij.dropna()
  10.                 # change the column name in the dataFrame
  11.                 closePrice_of_ij.columns = ['close_i', 'close_j']
  12.                 # calculate the daily return and drop the return of first day cause it is NaN.
  13.                 ret_of_i = ((closePrice_of_ij['close_i'] - closePrice_of_ij['close_i'].shift())/closePrice_of_ij['close_i'].shift()).dropna()
  14.                 ret_of_j = ((closePrice_of_ij['close_j'] - closePrice_of_ij['close_j'].shift())/closePrice_of_ij['close_j'].shift()).dropna()
  15.                 # calculate the correlation and store them in rank1
  16.                 if len(ret_of_i) == len(ret_of_j):
  17.                     correlation = np.corrcoef(ret_of_i.tolist(), ret_of_j.tolist())
  18.                     m = stockPool[i] + '+' + stockPool[j]
  19.                     rank[m] = correlation[0,1]
  20.     rank1 = sorted(rank.items(), key=operator.itemgetter(1))
  21.     potentialPair = [list(map(int, item[0].split('+'))) for item in rank1]
  22.     potentialPair = potentialPair[-5:]
  23.    
  24. # 选出的相关系数最高的五对股票。 比如 ('600815+601177', 0.59753123459010704),600815+601177为两只股票的代码, 0.59753123459010704为它们之间的相关系数。
  25. [('600815+601177', 0.59753123459010704), ('601100+601106', 0.60006268751560954), ('601106+601177', 0.66441434941650324), ('600815+601100', 0.6792572923561927), ('600815+601106', 0.76303679456471019)]
复制代码

以上为策略研究部分的第二部分代码。我们从股票池中选取两只股票,计算它们的回报然后算出它们之间的相关系数,最后取相关系数最高的五对股票来进行下一步的协整检验。

  1. for i in range(len(potentialPair)):
  2.     m = str(potentialPair[i][0])
  3.     n = str(potentialPair[i][1])
  4.     price_of_1 = ts.get_hist_data(m, start='2012-01-01', end='2013-01-01')
  5.     price_of_2 = ts.get_hist_data(n, start='2012-01-01', end='2013-01-01')

  6.     closeprice_of_1 = price_of_1['close']
  7.     closeprice_of_2 = price_of_2['close']

  8.     if len(closeprice_of_1) != 0 and len(closeprice_of_2) != 0:
  9.         model = pd.ols(y=closeprice_of_2, x=closeprice_of_1, intercept=True)   # perform ols on these two stocks
  10.         spread = closeprice_of_2 - closeprice_of_1*model.beta['x']
  11.         spread = spread.dropna()
  12.         sta = sts.adfuller(spread, 1)
  13.         pair = m + '+' + n
  14.         Rank[pair] = sta[0]
  15.         rank2 = sorted(Rank.items(), key=operator.itemgetter(1))
复制代码

以上为策略研究部分的第三部分代码。我们对选取出来的相关系数高的股票对进行协整检验,即检验它们的价差是否为稳定序列。 比如的对于股票对600815和601002,我们进行Augumented Dickey-Fuller test 得到结果如下

  1. (-3.34830942527566, 0.0128523914172048, 0, 115, {'5%': -2.8870195216569412, '1%': -3.4885349695076844, '10%': -2.5803597920604915}, -11.392077815567461)
复制代码

现在来解释一下几个比较重要的结果。第一个值-3.34830942527566为T-统计量,第二个值0.0128523914172048为p-value。字典里面包含的内容为置信度为5%,1%和10%时的T-统计量的值。比如对于我们所选择的股票对600815和601002, T-统计量为-3.34830942527566,小于5%所对应的-2.8870195216569412,那么很大可能我们发现了一个平稳的时间序列。

通过以上策略研究部分,我们发现最适合做配对交易的股票对为厦工股份(600815), 晋亿实业(601002).接下来我们用RiceQuant量化交易平台来执行我们的策略,回测时间为2014年全年,初始资金为100000.0。在计算价差时,我们对价差时间序列进行了归一化处理,处理后的价差用zScore来表示,具体计算方式如下:

zScore=spread−spreadmeanspreadvariance


其他【量化策略帖子】:【内部数据】超级干净准确的历史股票数据
有人听说过【Jython】吗?Python&Java在Ricequant的完美结合
【量化投资】不懂量化策略就不要炒股了!看了量化这个你就懂了!
【原创】【量化策略】海龟交易体系的小白构建(一)之交易法则
【原创】【量化策略】海龟交易体系的小白构建(二)之交易实现
【原创】【量化策略】海龟交易体系的小白构建(三)之完全体系构建
【量化策略】【原创】如何使用策略研究在股灾中扭亏为盈,净赚500w(一)
【量化策略】【原创】如何使用策略研究在股灾中扭亏为盈,净赚500w(二) [推广有奖]

二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

关键词:ricequant 量化交易平台 quant 量化策略 交易平台 交易平台 量化策略 python java 量化投资

回帖推荐

dnq 发表于4楼  查看完整内容

如何使用ricequant 平台进行落单和回测 在上个教程中,我们学习了写交易策略必不可少的两个部分init和handle_bar,并且开始着手写我们的第一个金叉策略,已经有了基本思路和写了以下的基本代码 def init(context): context.s1 = "000001.XSHE" update_universe([context.s1]) def handle_bar(context, bar_dict): MA_short= bar_dict[context.s1].mavg(20,frequency='day') MA_long = bar ...
已有 2 人评分经验 论坛币 收起 理由
xddlovejiao1314 + 100 精彩帖子
fantuanxiaot + 100 + 100 精彩帖子

总评分: 经验 + 200  论坛币 + 100   查看全部评分

本帖被以下文库推荐

沙发
lee_d_x 发表于 2015-9-22 21:35:14
很好的东西

藤椅
shzhy1989 学生认证  发表于 2015-9-23 09:37:51
学习了!

板凳
dnq 发表于 2015-9-24 08:47:28
如何使用ricequant 平台进行落单和回测

在上个教程中,我们学习了写交易策略必不可少的两个部分init和handle_bar,并且开始着手写我们的第一个金叉策略,已经有了基本思路和写了以下的基本代码
def init(context):

    context.s1 = "000001.XSHE"
    update_universe([context.s1])
   
def handle_bar(context, bar_dict):
     
    MA_short= bar_dict[context.s1].mavg(20,frequency='day')
    MA_long = bar_dict[context.s1].mavg(50,frequency ='day')

    curPosition =context.portfolio.positions[context.s1].quantity
    shares = context.portfolio.cash/bar_dict[context.s1].close


准备工作完成,接下来我们的目标是建立起交易落单的逻辑,以便于我们使用历史数据进行回测。金叉的交易思路我们在上一篇教程中已经分析,如果短期均线从底部突破长期均线,是买入信号,我们把思路转化为python代码。
    if MA_short > MA_long and curPosition == 0:
       order_shares(context.s1,shares)        


在这里我们接触到了新的api,就是落单功能order_shares,这里有两个参数,第一个是股票代码,第二个代表买多少share,如果数值为负数就代表卖出。在这个例子里,我们满仓买入。

Ricequant提供了强大而灵活的各种order的方法,除了最基本的order_shares之外,还可以使用order_target_value,order_lot,order_percent等等。在上面这个例子中,满仓买入我们使用order_target_percent会更加方便,在这里传入的第二个参数不再是购买(卖出)的数量,而是购买(卖出)后该股票占到投资组合的百分比,0代表0%,1代表100%。
   if MA_short > MA_long and curPosition == 0:  
       order_target_percent(context.s1,1)


如果短期均线从顶部跌破,那么出现一个清仓的信号。
    if MA_short < MA_long and curPosition != 0:      
        order_target_percent(context.s1,0)


好啦,整个可以用来回测的交易程序就基本写完了,是不是很简单呢?在进行回测前,我们还有最后一个步骤要完成,只要是交易策略不免会涉及到手续费,印花税和滑点费用。目前ricequant的默认设置如下

•固定印花税: 0.1%,


•手续费: 0.08% - 可以用context.commission手动修改


•滑点: 0.246% - 可以用context.slippage手动修改


在认为默认设置不符合实际需求的情况下,手续费和滑点可以手动在init 模块中进行修改。比如在这个回测中,我准备用的起始资金少,股票交易量较大,我认为滑点小于预设默认数值。
def init(context):
    context.slippage = 0.05
    context.commission = 0.08 #和默认数值相同,可以省略代码   


大功告成,让我们来看一看我们完成的第一个完整回测策略吧,是不是非常简单呢!
def init(context):
    context.s1 = "000001.XSHE"
    context.slippage = 0.05
    update_universe([context.s1])
   
   
def handle_bar(context, bar_dict):
     
    MA_short= bar_dict[context.s1].mavg(20,frequency ='day')
    MA_long = bar_dict[context.s1].mavg(50,frequency ='day')

    curPosition =context.portfolio.positions[context.s1].quantity
    shares = context.portfolio.cash/bar_dict[context.s1].close
   
    if MA_short > MA_long and curPosition == 0:  
       order_target_percent(context.s1,1)
      
    if MA_short < MA_long and curPosition != 0:
       order_target_percent(context.s1,0)


P2.png

除了策略表现以外,我们经常希望直观的看到一些历史数据以图表的方式展现出来,以上面金叉策略为例,我们想画出短均线,长均线和股票价格,可是直观地看出产生金叉的时候是不是一个交易的好的信号。

这时候就可以使用Ricequant的plot 功能来实现,在上述策略中的handle_bar function下面加入这几行代码
plot('close', bar_dict[context.s1].close)
plot('short_avg',MA_short)
plot('long_avg',MA_long)


这段code的意义是在每个handle_bar的时间切片上绘制下该时间的数值,这个数值可以是bar_dict当中存储的股票价格,也可以是任意我们赋值的参数,比如当前的N日均价,或者当天的某个技术指标(之后的教程中会降到),等等。

P3.png

如何解读回测结果数据

Ricequant的回测结果中,我们比较关心的回测数据主要是

回测收益 & 基准收益

这是最直观的收益对比。其他风险数据相似的情况下,回测收益相对基准收益越高,策略表现越好。

Beta

Beta 主要是衡量策略相对于大盘的系统风险性。比较优秀稳健的量化策略通常追求较低的beta值,降低策略的系统风险。也就是说无论大盘是熊是牛都能保证稳定的收益。

降低策略的beta值有几种方法,1)在策略中加入对冲部分 2)在只能做单边的情况下,增加股票数量,选择相关性较低的一篮子股票。

最大回撤和波动率

这两个数据主要是体现策略的风险性。波动率越高,最大回撤越高,策略的风险性就越大。最大回撤的数值尤为重要,如果看到过大的最大回撤,通常要考虑策略的可行性,增加止损或者其他有效的仓位控制方式。

夏普比率

Sharpe Ratio,和Sortino Ratio一样,是把风险和收益综合起来的数据,可以看成是一种考虑风险因素之后的调整收益率 。夏普指数越高,相当于每多承担一份风险,获得的额外收益越高。这是我们在策略调试中,综合衡量评定一个策略价值的重要标准。

如何使用ricequant中的回测历史功能来优化策略

为何需要查看回测历史?
•参数优化:设计交易策略中,常常会需要做一些参数的优化。比如我们写的金叉策略中,根据回测时间段的长度的不同和思路的差别,最优长短均线的设置就是需要不断优化测试,trial and error的策略参数。
•市场行情选择:某类交易策略表现和市场行情关系较大,我们希望能分别观察它们在熊市和牛市,在risk on 和 risk off 市场中的不同表现,从而把策略选择和市场动向结合起来。

为了让大家更方便的看到同一策略使用不同参数和不同时间段的回测表现,我们开发了查看回测历史的功能,在每一个策略下面,都能看到所有的历史回测表现。

P4.png

比如我们可以选择在14-15年的牛市段和13-14年的熊市段分别运行金叉这样的动量策略

对比结果

Screen Shot 2015-09-22 at 6.59.05 pm.png

当然值得注意的是,不管是参数优化还是市场行情相关,我们在优化策略的时候仍然需要以理论框架为出发点,不然单纯追求回报率,很容易造成历史数据过度拟合的情况。
已有 1 人评分经验 论坛币 收起 理由
fantuanxiaot + 20 + 20 精彩帖子

总评分: 经验 + 20  论坛币 + 20   查看全部评分

报纸
ydb8848 发表于 2015-9-24 10:29:30

地板
supersy9 发表于 2015-9-24 10:56:53
python学习中,很好的帖子,谢谢楼主分享,留个言记录下,以后好继续能查到

7
dana.quant 企业认证  发表于 2015-9-24 11:31:12
supersy9 发表于 2015-9-24 10:56
python学习中,很好的帖子,谢谢楼主分享,留个言记录下,以后好继续能查到
thx!~~互相学习

8
丹心永驻思华年 发表于 2015-9-24 12:30:27
多谢楼主分享!

9
yuan.ying 发表于 2015-9-24 21:46:56
收藏了,多谢楼主

10
honghudu 发表于 2015-9-25 08:18:13

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
加好友,备注jr
拉您进交流群
GMT+8, 2025-12-9 10:13