本章主要讲述构建海龟组合的痛点和解决方案
构建海龟组合痛点
在追求策略稳健性前提下,通过传统的滚动测试的方法不能筛选出盈利组合,即这种适用于日内CTA策略的检验方法针对海龟组合是无效的。
构建海龟组合困难表现为以下几点:
a. 历史数据过于少
从2014年到2018年这5年间,其日线数据仅仅是1,200根。其数据过少导致调整回望周期的灵活性降低,即最多回望周期只能设置为2年、3年、4年;同时数据少很难检验出策略的稳健性和有效性。(原版海龟策略历史回测周期是10年)
反观传统日内CTA策略,该策略是基于分钟级别的,1年的分钟K线就接近6,000根。用传统的筛选品种的方法,2年回望周期K线达到12,000根,在数据足够大的情况下更易于体现出策略的稳健性。
b. 回撤过大
海龟策略属于高风险高收益的中低频策略,夸张的比喻就是“3年不开张,开张吃3年”,在设定回测区间可能表现出持续的亏损,但也有可能在之后出现一波大行情,短期的盈利能够快速覆盖长期的亏损。但是滚动回测筛选品种时因为夏普过低而剔除该品种,导致错过隐含策略收益。
c. 筛选指标不稳健
本次滚动回测筛选标准是夏普比率,但是夏普比率对于策略回测时间区间起始点和终点非常敏感,对于趋势的把握不足。举例说明:在2年时间区间夏普比率是1.3,若整体回测区间向后移动3个月,得到的夏普比率可能是0.9。
故夏普比率不适应于海龟策略这种波动性大的类型,必须找到一种指标可以预测其趋势,比如“新式夏普比率”,在2年间比值是1.3,整体向前或者向后滚动3个月,其比值也接近1.3。
d. 样品数量噪音过大
尽管通过历史行情,其2014年前上市品种,已经把检测样本从51个降低到35个。但是对巨大的样品数量检验也造成很大的操作负担。例如一些低流动性或者持续走震荡行数的品种,没有必要来进行海龟策略的测试。
海龟组合筛选的解决方案
1. 重新进行初步筛选
从新对“流动性强”进行定义,在统计意义上,可以指行情波动巨大和具有大趋势,故通过2个指标来专门对35个品种重新进行筛选,这2个指标分别是:
a. 调整后波动率比值:
计算公式是收盘价的标准差/(合约最小价格变动 *100),调整后波动率比值越大,代表其品种的相对波动幅度越大,趋势跟踪策略的盈利能力越强。
举个例子说明,假设趋势跟踪策略正确预测行情的概率是x%,其固定交易成本为c,那么收益率r = (x% * 波动幅度) - 固定成本。所以当波动幅度足够大时,交易才有利可图,否则交易盈利覆盖不了交易成本,导致单子做得越多,亏的也越多。
b. ADF值
这是推论统计学概念,通过ADF检验来得出其ADF值,然后与10%进行比较,若ADF值要大于10%,证明完全不能拒绝原假设,即原假设成立。
原假设为存在单位根,有单位根代表着品种自相关性强,具有趋势行情。
总结一下,增加了两个初步筛选的标准,分别是
- 调整后波动率比值>1
- ADF值>10%
代码实现步骤
在jupter notebook上运行下面脚本代码,逐个测试样本
import numpy as np
import pandas as pd
import statsmodels.tsa.stattools as ts
#################################################
def volPriceTick (SYM, PT):
c=pymongo.MongoClient()
symbol = SYM #合约代号
col = c['VnTrader_Daily_Db'][symbol]
cx = col.find()
l = list(cx)
d = {}
for key in l[0].keys():
d[key] = []
for data in l:
for k, v in data.items():
d[k].append(v)
df = pd.DataFrame.from_dict(d)
PriceTick = PT #最小价格变动
close = df['close']
var = np.std(close) #收盘价的标准差
ratio = var/(PriceTick*100) # 定义调整后波动率比值
adfresult = ts.adfuller(close) # 得到ADF值
return ratio,adfresult
调用定义好的函数进行测试,如图所示,品种是沪深300股指期货(IF99),其最小价格变动是0.02。
得到的调整后波动率比值为342.19,比值远大于1说明品种价格变化挺活跃的;然后ADF值是0.36,同样大于10%说明其自相关性强,适用于趋势跟踪类型策略。
2 回测时使用新的指标
在上面已经提到,夏普比率不稳健的特点,导致其很难去识别一些行情趋势,而且对于回撤承受度不高,难于应用于像海龟策略这种高风险高收益的策略。所以产生了新筛选指标的需求。
新的指标应该具有3方面特点:
- 稳健性强
- 能够判断出整体趋势
- 对回撤容忍度高
故开发“回归夏普比率”用于品种筛选,其步骤如下:
- 用最小二乘法对累计资金曲线求得线性回归方程,得到斜率slope 和截距intercept。斜率为平均每天的盈亏资金,截距为回归起始资金(注意,仅仅是数学概念,可以大于或者少于1千万,资金曲线表现得特别好的时候截距可以为负数)
- 通过斜率,截距与时间求得期末的回归资金RegendBalance
- 通过期末回归资金和截距的比值得到回归年化收益RegtotalReturn
- 把单利转换为复利,得到回归年化收益
- 直接除以年化系数annualDays(240天)转化为回归日收益
- 在计算夏普比率公式中,把标准的日收益换成回归日收益,得到回归夏普比率(注意,由于回归线是笔直的,无标准差,故以原始标准差计算)
在海龟策略回测引擎的calculateResult中加入上面逻辑即可,其代码如下:
#计算回归总收益
daysList = range(1,totalDays+1)
#slope , intercept = np.polyfit (changduList , balanceList , 1) #numpy方法
slope, intercept, r_value, p_value, slope_std_error = stats.linregress(daysList , balanceList) #scipy方法
RegendBalance = intercept + totalDays * slope
RegtotalReturn = (RegendBalance / intercept - 1) * 100
计算回归年化收益
if RegtotalReturn > 0:
RegannualizedReturn = (((1+RegtotalReturn/100) **(annualDays/totalDays) )-1)*100
else:
RegannualizedReturn = -(((1-RegtotalReturn/100) **(annualDays/totalDays) )-1)*100
#计算回归日收益
RegdailyReturn = RegannualizedReturn/annualDays
#计算回归夏普比率
if returnStd:
sharpeRatio = dailyReturn / returnStd * np.sqrt(annualDays)
RegsharpeRatio = RegdailyReturn / returnStd * np.sqrt(annualDays)
else:
sharpeRatio = 0
RegsharpeRatio = 0
新指标的缺点:
- 高估资金低估表现非常好的品种:资金曲线非常好,其回归线的截距(即回归起始资金)可能远远少于1千万,其斜率变大,故标准夏普率可能是1.3,回归夏普比率可以达到3.3。
- 低估资金曲线表现非常差的品种:资金曲线在某个时间段剧烈向下移动,其回归线的截取可能远远大于1千万,其斜率变小,故标准夏普比率可能是-3,其回归夏普比率可以达-0.6。
综合回归夏普比率的优势和缺点,我们得知其对回撤的容忍度高,可以摒弃噪声从而捕捉到趋势,故适用于作为一个筛选标准;另一方面有时候会出现高估或者低估行情表现,故不能作为判断业绩表现的指标(如标准的夏普比率)。
3.多种回望周期测试
把回望周期分别设置为2年,3年和4年。
理论上较短回测周期使用较为宽松的筛选标准(如回归夏普比率大于0.4),较长回测周期使用较为苛刻的筛选标准(如回归夏普比率大于0.8)。
当然为了测试的全面新,通过3个不同的回望周期(如:2年、3年、4年),通过不同的回归夏普比率(如:0.4、0.6、0.8)进行筛选,力求新的海龟组合能够较好地预测2018年行情。(即表现出较高的稳健性)