原创文章第79篇,专注“个人成长与财富自由、世界运作的逻辑, AI量化投资”。
量化最直观的切入点是时间序列分析,也就是价量分析。而价量信息里,以动量策略最为直观且有效。
01 大小盘轮动策略
沪深300ETF510300代表大盘,而创业板ETF代表小盘。
20日动量>0.02时入场,而20日动量<-0.02时平仓。
如果都合适,取动量大者。
“轮动策略”其实有通用的“模板”。
即买入规则,可以复合成一个buy_signal,卖出规则,也可以复合成一个sell_signal。然后有一个order_by排序字段。
而机器学习模型,则不需要bug和sell信号,直接根据order_by取top K的轮动即可(qlib的topK就是这么做的)。
动量+0.02,-0.02,K=1(年化24.8,mdd=37.1%,夏普1.06)。
K=2,其余条件不变。
收益少了一点,回撤也小了一点,不明显。
入场条件更严格,改为0.08,出场-0.02不变,K=1。
年化降为21.9%,但回撤降至23.9%。就是更严格的入场条件,“小动量“的机会不操作了。
出场条件改为0.0,回撤降至21%。
K=2的时候,回撤降至19.78%,当然收益也略降。
其实,这个对比,容易看出来,”盈亏同源“,风险收益并存。
但是请注意,风险收益是不对称的,我们没必要为了2-3个点,冒10%个点的回撤风险。这里需要寻求一种平衡。
或者反过来想,我们是有意增加可以承受的风险,去追求超额收益。
# encoding:utf-8 from datetime import datetime from engine.bt_engine import BacktraderEngine from engine.strategy.strategy_base import StrategyBase import backtrader as bt from loguru import logger class StrategyRoc(StrategyBase): def __init__(self): self.inds = {} for data in self.datas: self.inds[data] = bt.ind.RateOfChange(data, period=20) def next(self): # 判断当前已经持仓 to_buy = [] to_sell = [] holding = [] for data, roc in self.inds.items(): if roc[0] > 0.08: to_buy.append(data) if roc[0] < -0.: to_sell.append(data) if self.getposition(data).size > 0: holding.append(data) for sell in to_sell: if self.getposition(sell).size > 0: logger.debug('清仓' + sell.p.name) self.close(sell) new_hold = list(set(to_buy + holding)) for data in to_sell: if data in new_hold: new_hold.remove(data) K = 2 if len(new_hold) > K: data_roc = {} for item in new_hold: data_roc[item] = self.inds[item][0] #排序 new_hold = sorted(data_roc.items(), key=lambda x: x[1], reverse=True) new_hold = new_hold[:K] new_hold = [item[0] for item in new_hold] # 等权重分配 todo: 已持仓的应应该不变,对cash对新增的等权分配 if len(new_hold) > 0: weight = 1 / len(new_hold) for data in new_hold: self.order_target_percent(data, weight*0.99) if __name__ == '__main__': e = BacktraderEngine(start=datetime(2012, 6, 26), end=datetime(2020, 12, 31)) for code in ['159915.SZ','510300.SH']: e.add_arctic_data(code) e.cerebro.addstrategy(StrategyRoc) e.run() #e.cerebro.plot(iplot=False) e.analysis()
仔细想来,你说年化20%到底难不难呢?