精选研报复现---牛熊线BBCurve


(anaiw) #1

当然首先定义问题,

“精选”的定义(逻辑或):

  • 结果美丽
  • 理论美丽
  • 和ML/DL/RL相关

“研报”的定义:市面上可得的券商的研报,就是16年之后的吧

“复现”的定义:在数据可得的情况下,对研报策略进行回测,有如下约定

  • 双边手续费6点
  • 策略不要求的情况下不止损止盈止回撤
  • 回测框架自写的,各大“矿”平台懒得去学
  • 基本都会进行参数优化
  • 只写关键代码

牛熊线BBCurve

出处:

《新量化择时指标之三 BBCurve—牛熊线实现完美择时》—2011.1.10 国海证券 程志田

垃圾话:

这其实是鹏哥的《量化投资》书中引用的一个策略,结果还不错。上课的时候交大作业,就想复现一下,以为公式还算美应该挺简单的,其实是个巨坑。git上面有人写了一个回测框架,francinexue/xuefu,其中写了一下牛熊线,我借鉴了一下自由度的写法。

理论背景:

我们知道,股价的走势符合几何布朗运动(《应用随机过程》),则有结论(具体过程可以看随机过程,布朗运动,伊藤引理那部分自己推),

\Delta S=\mu S\Delta t+\sigma S\varepsilon \sqrt{\Delta t} ,\varepsilon \sim N(0,1)

其中S表示**对数价格,**μ表示单位时间内的期望对数收益率,σ表示单位时间内的股票价格的对数波动率。

公式的意义为**:股价 \Delta t 时间内的对数收益率等于收益率的连续复利加随机波动**,而ε控制的是你所定义的波动程度分位数的系数,就像正态分布下正负一倍标准差包含68.3%的数据一样,系数越高则会包含更多波动。

但,研报中验证得出收益率符合t分布而非正态分布,因此有

\Delta S=\mu S\Delta t+\sigma S\varepsilon \sqrt{\Delta t} ,\varepsilon \sim t-分布

t分布是一个小样本估计正态分布的分布,其ε除了需要分位数之外还需要自由度,且自由度大于100多的时候和正态分布的差不多。

这个策略就是画出一条线,股价上穿这条线意味着牛市开始,下穿这条线意味这牛市结束。

平常没行情的股价都是在一定框框内(分位数)波动,如果价格的波动比我们预想的波动(分位数)还大,那么就意味着不是昙花一现的行情而是趋势。

研报结果:

研报结果从来都是十分美丽的,

![](data:image/svg+xml;utf8,<svg%20xmlns=‘http://www.w3.org/2000/svg’%20width=‘1366’%20height='768’>)

研报中牛熊线策略在上证综指的回测结果

从研报结论的图形中猜测大概是从2001年一直到2011年左右。年化其实一般吧,但是抓大趋势的能力挺好的。

公式:

公式一: BULL_{∆t}=CLOSE_{0}*e^{μ∆t+εσ\sqrt{\Delta t}}

公式二: BULL_{∆t}=CLOSE_{0}*e^{(μ-σ^2/2)∆t+εσ\sqrt{\Delta t}}

公式三: BULL_{∆t}=CLOSE_{0}*((1+μ)^{∆t}+εσ\sqrt{\Delta t})

公式四: BULL_{∆t}=MEANCLOSE_{0}*e^{μ∆t+εσ\sqrt{\Delta t}}

公式五: BULL_{∆t}=MEANCLOSE_{0}*((1+μ)^{∆t}+εσ\sqrt{\Delta t})

公式一是按照研报中写的,公式二到五是我改进的。

公式的意思是,今天的牛线是用 \Delta t 天之前的收盘价和计算出的μ,σ,ε计算得到。这意味最近 \Delta t 天的数据我们是一点都没用到的(计算μ,σ是可以用到 前\Delta t 天的数据的,但是在上证综指跑出来的结果差别并没有太大)。

因为计算ε需要自由度和分位数,分位数是个超参需要调,自由度的处理方法如下:我们要用 \Delta t 天之前的对数收益率的期望来做连续复利,那么用了多少个 \Delta t 天的数据,自由度就应该是多少。

记自由度为N, \Delta t 为T,则μ应该求的是N*T天的均值,然后再向前推T天(推不推都行,跑出来的结果差别没有太大);σ同理;ε用N和分位数来求。(这个逻辑是git作者的,我不是很苟同,但是这么做也还行吧)。

复现(20010101-20180101):

没有仔细遍历参数,怕数据迁就(过拟合)。

公式一:

较优参数为T=41,n=27,分位数=80%。

胜率37.9%,收益率881.5%,交易66次,sharp0.29,平均持有时长19天,最大回撤25%。(如果要算年化收益率的话是要去掉T*n个交易日的,41*27=240*4.6,只算14年,人家不都是这么骗人的么,余下同理。)

![](data:image/svg+xml;utf8,<svg%20xmlns=‘http://www.w3.org/2000/svg’%20width=‘2282’%20height='590’>)

![](data:image/svg+xml;utf8,<svg%20xmlns=‘http://www.w3.org/2000/svg’%20width=‘595’%20height='306’>)

看得出来从15年牛市之后效果变差,当然这不是优化回撤最优的参数,如果不在意50%的收益还有一个43-24-70%的组合的回撤挺好看的(胜率40.7%,收益833.4%,交易59次,最大回撤15%)。

关键代码:

@jit
def cal_bull(close,mu,sigma,T,epsilon):
    return close * np.exp(T*mu + np.sqrt(T)*sigma*epsilon)

epsilon = scipy.stats.t.ppf(1-alpha/2,n) #ε
ripesd['logreturn'] = ripesd['close'].map(lambda x: np.log(x)).diff() #对数收益率
ripesd['mu'] = ripesd['logreturn'].rolling(n*T).mean() #μ
ripesd['sigma'] = ripesd['logreturn'].rolling(n*T).std() #σ
ripesd['close_-t'] = ripesd['close'].shift(T)
ripesd['bull'] = ripesd.apply(lambda x: cal_bull(x['close_-t'],x['mu'],x['sigma'],T,epsilon),axis=1)
ripesd = ripesd.dropna()

#上穿下穿买卖点
ripesd['buy'] = ripesd.apply(lambda x: True if x['close'] >= x['bull'] and x['close_-1'] <= x['bull_-1'] else False,axis=1)
ripesd['sell'] = ripesd.apply(lambda x: True if x['close'] <= x['bull'] and x['close_-1'] >= x['bull_-1'] else False,axis=1)

公式二:

因为纯理论公式就是要减去一项,所以我改了一下,效果改进不大,就不上图了。

公式三:

因为公式一理论是连续复利,与现实不符,所以我改了一下理论基础,用推布朗运动公式一开始时候的离散形式得到了公式三。神奇的是这个公式中的最优参数是公式一控制回撤不错的43-24-70%。胜率45.7%,收益894%,交易59次)

![](data:image/svg+xml;utf8,<svg%20xmlns=‘http://www.w3.org/2000/svg’%20width=‘2282’%20height='590’>)

![](data:image/svg+xml;utf8,<svg%20xmlns=‘http://www.w3.org/2000/svg’%20width=‘589’%20height='306’>)

只看最优参数看不出这一改进究竟有没有提高。但至少没变差,就很开心。

关键代码

@jit
def cal_bull_3ver(close,mu,sigma,T,epsilon):
    return close * ((1+mu)**T + np.sqrt(T)*sigma*epsilon)

epsilon = scipy.stats.t.ppf(1-alpha/2,n)
ripesd['return'] = ripesd['close'].pct_change() #算术收益率
ripesd['mu'] = ripesd['return'].rolling(n*T).mean()
ripesd['sigma'] = ripesd['return'].rolling(n*T).std()
ripesd['close_-t'] = ripesd['close'].shift(T)
ripesd['bull'] = ripesd.apply(lambda x: cal_bull_3ver(x['close_-t'],x['mu'],x['sigma'],T,epsilon),axis=1)

公式四、五:

仔细观察公式一、三与研报中的牛线,可以看出研报中的牛线更平滑,为啥?我不知道,可能是人家的μ、σ、ε都是时变的,但是没说出来。

但最常见的把线变平滑的方式就是MA,故进行尝试。对牛线做MA会使信号延迟,因此我将公式中的收盘价变为前T日的收盘价均价得到公式四、五(不知道以收盘价为中心的两边T日会不会更好)。最大收益还是增加了50%的,但是最优参数的区间也发生了改变。

公式四的较优参数31-17-60%,胜率38.5%,收益率931%,交易次数39次,平均持有时长35天。

![](data:image/svg+xml;utf8,<svg%20xmlns=‘http://www.w3.org/2000/svg’%20width=‘2282’%20height='590’>)

![](data:image/svg+xml;utf8,<svg%20xmlns=‘http://www.w3.org/2000/svg’%20width=‘589’%20height='306’>)

回撤控制的超好,惊了。当然这个公式是为了平滑牛线,看的出来平滑的效果是不错的。

结论及评价:

最后还是可以在2011年达到研报中的500%左右的收益率的,但是研报中收益率曲线图是100%开始的,我的框架是从0开始的。复现成功。

程志田先生曾供职多家券商,现在是创金合信量化投资总监,还是比较有实力的。这个策略应该没啥容量限制。虽然到现在我也不知道这么平滑的牛线是怎么画出来的,用了trick是肯定的吧,反正就很强咯。

牛熊线的核心是“突破波动限制”,说到突破限制,其他常用指标中也有和限制有关的,效果和这个很相似,但是没这个好,能猜到吗?