失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > etf动量轮动+大盘择时:年化30%的策略

etf动量轮动+大盘择时:年化30%的策略

时间:2021-08-27 19:56:23

相关推荐

etf动量轮动+大盘择时:年化30%的策略

原创文章第111篇,专注“个人成长与财富自由、世界运作的逻辑, AI量化投资”。

今天重点来探索一下elegantRL。

昨天的文章金融强化学习与finRL开发包里介绍了finRL的源码结构,背后的强化学习框架是elegantRL。

聚宽平台上有一个“动量轮动+RSRS”择时,在咱们自己的AI量化平台上复现一下。

01 策略思路

我们之前用的动量是ROC(20)就是20日收益率。这里的动量定义为 20日收盘价的“斜率”——就是线性回归的斜率。“斜率”取最大的K支,构建组合。然后RSRS(18,600)对市场择时,如果RSRS信号为buy,则按上述动量组合调仓,若RSRS信号为SELL,则平仓。

02 动量计算

动量定义为 20日收盘价的“斜率”——就是线性回归的斜率。

qlib原本的表达式,使用了cpython,这里我们使用np.polyfit即可实现。

class Slope(Rolling):def __init__(self, feature, N):super(Slope, self).__init__(feature, N, "slope")def _load_internal(self, instrument):def calc_slope(x):x = x / x[0] # 这里做了一个“归一化”slope = np.polyfit(range(len(x)), x, 1)[0]return slopeseries = self.feature.load(instrument)result = series.rolling(self.N, min_periods=2).apply(calc_slope)series = pd.Series(result, index=series.index)return series

这是单序列的线性回归,RSRS是双序列的线性回归。目前没有找到办法rolling,导致性能很差。

调用的代码如下:

fields += ['Slope($close,20)']names += ['mom_slope']fields += ["Ref($close,-1)/$close - 1"]names += ['label']all = Dataloader().load_one_df(['000300.SH'], names, fields)

如此即可以实现代码最大程度的复用了。

02 排序算子之topK

按某一个因子的顺序,选择前K个进行持仓的算子。

class SelectTopK:def __init__(self, K=1, order_by='order_by', b_ascending=False):self.K = Kself.order_by = order_byself.b_ascending = b_ascendingdef __call__(self, context):stra = context['strategy']features = context['features']if self.order_by not in features.columns:logger.error('排序字段{}未计算'.format(self.order_by))returnbar = get_current_bar(context)if bar is None:logger.error('取不到bar')return Truebar.sort_values(self.order_by, ascending=self.b_ascending, inplace=True)selected = []pre_selected = Noneif 'selected' in context:pre_selected = context['selected']del context['selected']for code in list(bar.code):if pre_selected:if code in pre_selected:selected.append(code)else:selected.append(code)if len(selected) >= self.K:breakcontext['selected'] = selected

有了算子之后,都是代码模块。

不择时的收益率如下:

如果把“斜率”换成“20日ROC”,收益率小一点,但回撤大不少。

03 大盘择时

大盘使用沪深300的RSRS给大盘择时。

大盘择时的逻辑为:若择时指标为“买”,则按原计划操作,若大盘择时为“卖”,则全部平仓退场。

class PickTime:def __init__(self, benchmark='000300.SH', signal='signal'):self.benchmark = benchmark#self.buy = self.buyself.signal = signaldef __call__(self, context):stra = context['strategy']extra = context['extra']df = extra[self.benchmark]if self.signal not in df.columns:logger.error('择时信号不存在')return Truecurr_date = stra.get_current_dt()if curr_date not in df.index:logger.error('日期不存在{}'.format(curr_date))return Nonebar = df.loc[curr_date]if type(bar) is pd.Series:bar = bar.to_frame().Tif bar[self.signal][0]:logger.info('择时信号显示,平仓所有。')context['selected'] = []

04 组合成策略

积木式开发不需要写策略代码,这个非常方便,而且所有的算子均可复用。

e = BacktraderEngine(init_cash=1000000, benchmark='399006.SZ', start=datetime(, 1, 1))e.add_features(symbols, names, fields)e.add_extra('000300.SH', fields=['RSRS($high,$low,18,600)', '$RSRS_beta<0.8'], names=['RSRS', 'signal'])from engine.strategy.algos import SelectTopK, PickTime, WeightEquallye.run_algo_strategy([SelectTopK(K=1), PickTime(), WeightEqually()])e.analysis(pyfolio=False)

斜率版本可以改善最大回撤:

明天继续加上卡曼滤波,以及换成真实的ETF(今天是两支指数)。

代码与数据均上传至星球,可前往量化专栏下载。

每天代码,每周研报复现。

【每周研报复现】基于阻力支撑相对强度(RSRS)的市场择时

我的开源项目及知识星球

如果觉得《etf动量轮动+大盘择时:年化30%的策略》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。