策略思想

均值回归策略的思想在弁言中已有所先容, 此处不详细展开。
实在,大家熟知的巴菲特代价投资策略和索罗斯的“反身”交易策略,从实质上来看都是均值回归理论的运用,所不同的是前者是基于代价低点向高点回归做多得到收益,后者则是通过泡沫破灭代价从高点向低点回归时做空进行投契获利。
均值回归策略的思想很随意马虎理解,实际操作中有很多构建的方法,比较常见的利用股价收益率偏离某段期间均值的多少个标准为阈值作为均值回归策略的买入卖出旗子暗记。
下面将基于该事理,打算股价收益率的Zscore值,即以标准差为单位来衡量某一日收益率与均匀收益率之间的离差情形。
Talk is cheap, show your code!下面直接给出利用Python构建量化回测框架的过程和回测结果。

利用Python进行策略回测

01数据准备与探索剖析

全文利用tushare获取股票数据,在Jupyter notebook上运行代码。
长期关注本"大众号的朋友不难创造,第一段代码基本上在每篇文章中都会涌现,引入可能用到的库以及从tushare高下载数据,这一段可以作为数据剖析的模板,在往后的文章中可能会省略掉,直接上核心代码。

#先引入后面可能用到的包(package)import pandas as pd import numpy as npimport matplotlib.pyplot as pltimport seaborn as sns sns.set() %matplotlib inline #正常显示画图时涌现的中文和负号from pylab import mplmpl.rcParams['font.sans-serif']=['SimHei']mpl.rcParams['axes.unicode_minus']=False#利用tushare获取交易数据#设置tokenimport tushare as ts token='输入在tushare.pro上获取的token'ts.set_token(token)pro=ts.pro_api(token)#pro=ts.pro_api(token)index={'上证综指': '000001.SH','深证成指': '399001.SZ', '沪深300': '000300.SH','创业板指': '399006.SZ', '上证50': '000016.SH','中证500': '000905.SH', '中小板指': '399005.SZ','上证180': '000010.SH'}#获取当前交易的股票代码和名称def get_code(): df = pro.stock_basic(exchange='', list_status='L') codes=df.ts_code.values names=df.name.values stock=dict(zip(names,codes)) #合并指数和个股成一个字典 stocks=dict(stock,index) return stocks #获取行情数据def get_data(stock,start='20151009',end=''): #如果代码在字典index里,则取的是指数数据 code=get_code()[stock] if code in index.values(): df=ts.pro_bar(ts_code=code,asset='I',start_date=start, end_date=end) #否则取的是个股数据 else: df=ts.pro_bar(ts_code=code, adj='qfq',start_date=start, end_date=end) #将交易日期设置为索引值 df.index=pd.to_datetime(df.trade_date) df=df.sort_index() return df

手把手教你用Python搭建自己的量化回测框架均值回归策略

从中国安然的股价走势来看,其单边趋势强于震荡趋势,因此均值回归策略可能不是中国安然在这段期间的最优策略,下面的回测结果将进一步展示。
下面先来看看中国安然股票日收益率的颠簸及对标准差的偏离情形。
日收益率图显示存在明显颠簸集聚的情形。
日收益率标准化图是打算日收益率的滚动20日Zscore值,即当前收益率对其20日均值的标准差偏离度,此时颠簸集聚的情形不存在了。
图中设定1.5倍标准差为阈值,偏离绿色线的点将作为买入卖出旗子暗记。

df=get_data('中国安然')#df.tail()returns=df.close.pct_change().dropna()returns.plot(figsize=(14,6),label='日收益率')plt.title('中国安然日收益图',fontsize=15)my_ticks = pd.date_range('2015-10-1','2019-10-11',freq='q')plt.xticks(my_ticks,fontsize=12)plt.yticks(fontsize=12)plt.xlabel('',fontsize=12)# 将右边、上边的两条边颜色设置为空 实在就相称于抹掉这两条边plt.axhline(returns.mean(), color='r',label='日收益均值')plt.axhline(returns.mean()+1.5returns.std(), color='g',label='正负1.5倍标准差')plt.axhline(returns.mean()-1.5returns.std(), color='g')plt.legend()ax = plt.gca() ax.spines['right'].set_color('none') ax.spines['top'].set_color('none') plt.show()

ret_20=returns.rolling(20).mean()std_20=returns.rolling(20).std()score=((returns-ret_20)/std_20)score.plot(figsize=(14,6),label='20日收益率标准化')plt.title('中国安然日收益标准化图',fontsize=15)my_ticks = pd.date_range('2015-10-1','2019-10-11',freq='q')plt.xticks(my_ticks,fontsize=12)plt.yticks(fontsize=12)plt.xlabel('',fontsize=12)plt.axhline(score.mean(), color='r',label='日收益均值')plt.axhline(score.mean()+1.5score.std(), color='g',label='正负1.5倍标准差')plt.axhline(score.mean()-1.5score.std(), color='g')plt.legend()ax = plt.gca() ax.spines['right'].set_color('none') ax.spines['top'].set_color('none') plt.show()

02 策略设计与回测

加载数据

这里加载了open、close、low、high和vol数据紧张是为了后面的可视化剖析。
数据获取中以沪深300指数作为参考基准,读者可以根据须要进行修正。

#获取数据def data_feed(stock,start='20151009',end=''): #获取个股数据 df=get_data(stock,start,end)[['open','close','low','high','vol']] #指数数据,作为参照指标 df['hs300']=get_data('沪深300',start,end).close.pct_change() #打算收益率 df['rets']=df.close.pct_change().dropna() return df.dropna()

交易策略

打算日收益率的滚动20日Zscore值,当Zscore小于-1.5并且第二天开盘没有涨停时,在第二天开盘买入;当Zscore大于1.5且第二天开盘没有跌停时,在第二天开盘卖出,每次都是全仓买卖。

def MR_Strategy(df,lookback=20,buy_threshold=-1.5,sell_threshold=1.5,cost=0.0): '''输入参数: df为数据表: 包含open,close,low,high,vol,标的收益率rets,指数收益率数据hs300 lookback为均值回归策略参数,设置统计区间长度,默认20天 buy_threshold:买入参数,均值向下偏离标准差的倍数,默认-1.5 sell_threshold:卖出参数,均值向上偏离标准差的倍数,默认1.5 cost为手续费+滑点价差,可以根据须要进行设置,默认为0.0 ''' #打算均值回归策略的Zscore值 ret_lb=df.rets.rolling(lookback).mean() std_lb=df.rets.rolling(lookback).std() df['score']=(df.rets-ret_lb)/std_lb df.dropna(inplace=True) #设计买卖旗子暗记,为只管即便贴近实际,加入涨跌停不能买卖的限定 #当Zscore值小于-1.5且第二天开盘没有涨停发出买入旗子暗记设置为1 df.loc[(df.score<buy_threshold) &(df['open'] < df['close'].shift(1) 1.097), 'signal'] = 1 #当Zscore值大于1.5且第二天开盘没有跌停发出卖入旗子暗记设置为0 df.loc[(df.score>sell_threshold) &(df['open'] > df['close'].shift(1) 0.903), 'signal'] = 0 df['position']=df['signal'].shift(1) df['position'].fillna(method='ffill',inplace=True) df['position'].fillna(0,inplace=True) #根据交易旗子暗记和仓位打算策略的逐日收益率 df.loc[df.index[0], 'capital_ret'] = 0 #本日开盘新买入的position在本日的涨幅(扣除手续费) df.loc[df['position'] > df['position'].shift(1), 'capital_ret'] = \ (df['close'] / df['open']-1) (1- cost) #卖出同理 df.loc[df['position'] < df['position'].shift(1), 'capital_ret'] = \ (df['open'] / df['close'].shift(1)-1) (1-cost) # 当仓位不变时,当天的capital是当天的change position df.loc[df['position'] == df['position'].shift(1), 'capital_ret'] = \ df['rets'] df['position'] #打算标的、策略、指数的累计收益率 df['capital_line']=(df.capital_ret+1.0).cumprod() df['rets_line']=(df.rets+1.0).cumprod() df['hs300_line']=(df.hs300+1.0).cumprod() return df

打算策略的评价指标

完全代码只在知识星球上分享,可扫描最下方二维码加入。

# 根据每次买入的结果,打算干系指标def trade_indicators(df): 由于篇幅所限,此处代码省略 #df为策略返回的数据框,包含策略的收益率 # 打算资金曲线 # 记录买入或者加仓时的日期和初始资产 # 输出账户交易各项指标def performance(df): 由于篇幅所限,此处代码省略 #df为策略返回的数据框,包含策略的收益率 # 打算每一年(月,周)股票,资金曲线的收益 # 打算策略的年(月,周)胜率 #打算总收益率、年化收益率和风险指标#对策略和标的股票累计收益率进行可视化def plot_performance(df,stock): 由于篇幅所限,此处代码省略 #df为策略返回的数据框,包含策略的收益率 #stock为回测的股票简称def plot_strategy_signal(df,trade,stock): 由于篇幅所限,此处代码省略 #对K线图和买卖旗子暗记进行可视化 #利用pyecharts 0.5.11版本 #将上述函数整合成一个实行函数def main(stock,start,end): d0=data_feed(stock,start,end) d1=MR_Strategy(d0) print(f'回测标的:{stock}') print(f'回测期间:{start}—{end}') trade=trade_indicators(d1) performance(d1) plot_performance(d1,stock) return d1,trade03回测结果剖析下面分别选择中国安然、奥马电器和九州通股票进行均值回归策略回测,韶光区间为2015年10月9日至2019年10月11日,跨度四年旁边。
结果显示出均值回归策略对不同标的表现差异较大。
值得把稳的是奥马电器由于2018年涌现19亿巨亏的黑天鹅事宜,股价从16.53跌至3.19,最大回撤高达86%,回测期间总收益-29%;策略回撤也达到56%,但是总收益为正2.4%。
总体而言,均值回归策略运用了股市投资中经典的高抛低吸思想,该类型策略一样平常在震荡市中表现精良(九州通);但是在单边趋势行情中一样平常表现糟糕(中国安然),每每会大幅跑输市场(奥马电器)。
#对中国安然股票进行策略回测stock='中国安然'd1,trade=main(stock,'20151009','20191011')plot_strategy_signal(d1,trade,stock)

输出回测结果

回测标的:中国安然

回测期间:20151009—20191011

==============每笔交易收益率及同期股票涨跌幅===============

start_date end_date trade_return stock_return

16 2015-11-30 2015-12-03 0.054617 0.062943

21 2015-12-07 2015-12-15 0.014286 0.008871

37 2015-12-29 2016-02-01 -0.155182 -0.172830

74 2016-02-26 2016-03-03 0.031370 0.049032

123 2016-05-09 2016-05-13 0.005099 0.010190

156 2016-06-27 2016-07-13 0.046194 0.040052

180 2016-07-29 2016-08-10 0.001848 0.002772

193 2016-08-17 2016-09-20 0.033013 0.033413

220 2016-09-27 2016-10-31 0.004965 0.006689

242 2016-11-03 2016-11-22 0.035270 0.043629

262 2016-12-01 2017-01-17 -0.007703 -0.009634

303 2017-02-06 2017-02-21 0.030497 0.032285

346 2017-04-10 2017-04-26 0.000273 0.024861

365 2017-05-08 2017-05-11 0.068169 0.067365

391 2017-06-15 2017-07-06 0.068447 0.088540

418 2017-07-24 2017-08-02 0.052418 0.040032

502 2017-11-24 2017-12-11 -0.039784 -0.014396

526 2017-12-28 2018-01-16 0.104979 0.106040

548 2018-01-30 2018-02-14 -0.074074 -0.060932

582 2018-03-26 2018-04-11 -0.013005 -0.037411

604 2018-04-27 2018-05-09 -0.007082 -0.002692

626 2018-05-31 2018-06-01 0.013092 0.016323

639 2018-06-20 2018-07-02 -0.058481 -0.110647

648 2018-07-03 2018-07-10 0.061150 0.053605

670 2018-08-02 2018-08-08 0.002356 -0.022110

680 2018-08-16 2018-09-05 0.142426 0.101175

695 2018-09-06 2018-09-25 0.077294 0.080475

712 2018-10-09 2018-10-22 0.021354 0.048627

727 2018-10-30 2018-11-05 0.108334 0.073872

799 2019-02-18 2019-02-19 0.026291 0.038420

806 2019-02-27 2019-04-01 0.109530 0.122698

851 2019-05-07 2019-05-13 -0.030937 -0.031403

912 2019-08-01 2019-08-13 -0.017714 -0.034963

930 2019-08-27 2019-09-16 0.057058 0.052755

====================账户交易的各项指标=====================

交易次数为:34 最长持有天数为:47

每次均匀涨幅为:0.022540

单次最大盈利为:0.142426 单次最大亏损为:-0.155182

年均买卖次数为:8.953824

最大连续盈利次数为:8 最大连续亏损次数为:3

策略年胜率为:80.0%

策略月胜率为:77.5%

策略周胜率为:59.26%

总收益率: 策略102.33%,股票177.87%, 指数5.55%

年化收益率:策略20.19%, 股票30.56%,指数1.42%

最大回撤: 策略19.17%, 股票28.54%,指数32.46%

策略Alpha: 0.2, Beta:0.43,夏普比率:1.92

stock='奥马电器'd1,trade=main(stock,'20151009','20191011')plot_strategy_signal(d1,trade,stock)回测标的:奥马电器回测期间:20151009—20191011==============每笔交易收益率及同期股票涨跌幅===============略====================账户交易的各项指标=====================交易次数为:24 最长持有天数为:65每次均匀涨幅为:0.014195单次最大盈利为:0.491054 单次最大亏损为:-0.452403年均买卖次数为:6.522710最大连续盈利次数为:4 最大连续亏损次数为:2策略年胜率为:40.0%策略月胜率为:65.0%策略周胜率为:51.89%总收益率: 策略8.18%,股票-68.03%, 指数22.43%年化收益率:策略2.46%, 股票-29.7%,指数6.45%最大回撤: 策略56.72%, 股票86.1%,指数26.39%策略Alpha: -0.01, Beta:0.59,夏普比率:0.37

stock='九州通'd1,trade=main(stock,'20151009','20191011')plot_strategy_signal(d1,trade,stock)回测标的:九州通回测期间:20151009—20191011==============每笔交易收益率及同期股票涨跌幅===============略====================账户交易的各项指标=====================交易次数为:33 最长持有天数为:50每次均匀涨幅为:0.006272单次最大盈利为:0.103585 单次最大亏损为:-0.142085年均买卖次数为:8.665468最大连续盈利次数为:6 最大连续亏损次数为:3策略年胜率为:60.0%策略月胜率为:58.54%策略周胜率为:51.69%总收益率: 策略16.93%,股票-27.96%, 指数1.57%年化收益率:策略4.21%, 股票-8.28%,指数0.41%最大回撤: 策略25.56%, 股票49.51%,指数32.46%策略Alpha: 0.04, Beta:0.39,夏普比率:0.31

结语

本文紧张先容了均值回测策略的基本思想,以及利用Pandas构建基于研究的量化回测框架对策略进行回测,回测结果比较直不雅观(感兴趣的朋友可以把交易用度和滑点价差考虑进去,文中设置为0了)。
当然,上述回测框架还存在一些细节问题须要完善,而且基于研究的回测框架和基于pandas的向量式编程存在一定的局限性,只管随意马虎理解,但不适宜用于处理更繁芜的交易环境。
往后有机会将为大家先容利用面向工具编程(Class类)的方法构建基于事宜驱动的量化回测框架,可以借鉴backtrader、zipline等开源框架。
只管均值回归非常普遍,但要准确回测一个盈利的均值回归策略却存在很多陷阱。
比如,许多历史金融数据库中都包含报价缺点,而这些缺点可能会抬高均值回归策略的古迹。
其余,存活偏差也会影响均值回归策略的回测,即那些股价一贯下跌最退却撤退市而没有涌现均值回归的股票早已从数据库中剔除。
对付均值回归策略而言,范例的结果便是套利机会的逐步消逝,从而使得收益率逐渐降落至零。
当套利机会消逝殆尽时,均值回归策略就变得没那么有效,由于越来越多的交易旗子暗记来自于股票估值的基本面变革,而这并不会均值回归。

关于Python金融量化

专注于分享Python在金融量化领域的运用。
加入知识星球,可以免费获取量化投资视频资料、量化金融干系PDF资料、"大众年夜众号文章Python完全源码、量化投资前沿剖析框架,与博主直接互换、结识圈内朋友等。