FangQuant › Strategies

均值回归策略

Fang submitted 2017-12-21 18:09:12

策略思路:
由于残差不平稳,就无法满足均值和方差在时间过程上都是常数,但残差会以它的均线为中心进行波动。也就是说,当残差由于波动而偏离移动均线时,它将调整并重新归于均线。那么如果我们如果能捕捉偏离均线价格的回归,就可以从此获利。
策略指标:
我们可以构造一种利用标准差来测量当日残差波动幅度的方法。取过去 N天收盘价,并取其标准差 σ(N),设今日残差为E并且 N日均线值为 MA(N),计算:
N日偏离倍数p=(E – MA(N)) / σ(N)

策略优化:
加入胜率的概念:
1)对于N日偏离倍数 ρ。另外,我们只记录 ρ<−1和ρ>1 的情况,因为如果 -1,那说明价格偏离不大,则不构成回归信号。
2)定义胜率:
设定观测输赢的天数 T,止盈的 σ倍数 u,止损的 σ倍数 d。
如果p<-1,则执行买入残差的操作,如果在未来的 T天里,残差先上涨 σ⋅u,则记作“赢”;先下跌 σ⋅d,则记作“输”;如果 T 天残差都没离开这个区间,则记作“平”。
如果p>1,则执行卖出残差的操作,如果在未来的 T天里,残差先下跌 σ⋅u,则记作“赢”;先上涨 σ⋅d,则记作“输”;如果 T 天残差都没离开这个区间,则记作“平”。
3) 求出最优胜率区间:
观察所有长度为1的区间,计算p取值在各个区间内时的“赢”、“输”、“平”的次数。用“赢”的比例最高的p值的区间作为开仓的信号。

交易策略:
1)用当前残差价格减去前N天的均值,除以前N天的波动率计算p。
1. 计算在历史交易中|p|(p的绝对值)在所有长度为1的区间的胜率,求出胜率最高的|p|,将区间记为(|pbest|, |pbest|+1)。
2. 如果当天的p的绝对值|p|属于区间(|pbest|, |pbest|+1),就开仓:
a) 如果p是负数就买入残差
b) 如果p是正数就卖出残差
2) 开仓后,跟踪之后T天内的价格。
1. 对于买入的开仓(p<0),如果之后T天出现价格先高于u*前N天的波动率的条件就止盈平仓。如果出现价格低于d*前N天的波动率就止损平仓。如果连续T天都在这个区间内则算平局,也平仓。
2. 对于卖出的开仓(p>0),如果之后T天出现价格先高于d*前N天的波动率的条件就止损平仓。如果出现价格高于u*前N天的波动率就止盈平仓。如果连续T天都在这个区间内则算平局,也平仓。

u=1.5
d=1
N=10
T0=60
start_money=1e+07
w=int(1/0.1)
least_percentage=0.15
wx = 3
wy = 5
wz = 94

price=wx*x+wy*y-wz*z
onecosts=0.21*(wx*x+wy*y)+wz*(550*7)
c1=price[(T0+N):len(price)]
c2=buys[(T0+N):len(e)]
c3=sells[(T0+N):len(e)]
c4=exitbuys[(T0+N):len(e)]
c5=exitsells[(T0+N):len(e)]
c6=sigmas[(T0+N):len(e)]
c7=mas[(T0+N):len(e)]
c8=daily_sigma[(T0+N):len(e)]
c9=onecosts[(T0+N):len(onecosts)]
c10=np.cumsum(c2+c5-c3-c4)#buy+exitb-sell-exitsell
c11=e[(T0+N):len(e)]
c12=lowerp[(T0+N):len(e)]
c13=upperp[(T0+N):len(e)]

datas=pd.DataFrame({"price":c1,"buy":c2,"sell":c3,"exitb":c4,"exits":c5,"sigmasN":c6,
                    "masN":c7,"p":c8,"onecosts":c9,"positions":c10,"e":c11,
                    "lowerp":c12,"upperp":c13})
dates=rt.Date[(T0+N):len(price)].as_matrix()
xs = [datetime.strptime(d, '%Y/%m/%d').date() for d in dates]

num,_=datas.shape

moneys = np.zeros(num)
moneys[0] = start_money

for i in range(1, num):
    earn = (datas["price"][i] - datas["price"][i-1])*datas["positions"][i-1]
    moneys[i] = moneys[i-1] + earn

drawDownRatios=np.zeros(num)
drawDownRatios[0]=(1-moneys[0]/start_money)
for i in range(1,num):
  maxprev=max(max(moneys[0:i]),start_money)
  drawDownRatios[i]=max((1-moneys[i]/ maxprev),0)
last_money=moneys[num-1]
annual_return=(last_money/start_money - 1)/num*250


Currently no Comments.