必威体育Betway必威体育官网
当前位置:首页 > IT技术

【策略研究】行业轮动策略(附源码)

时间:2019-05-30 12:41:04来源:IT技术作者:seo实验室小编阅读:78次「手机版」
 

行业轮动

什么是行业轮动策略?

行业轮动是利用市场趋势获利的一种主动交易策略,其本质是利用不同投资品种强势时间的错位对行业品种进行切换以达到投资收益最大化的目的。通俗点讲就是根据不同行业的区间表现差异性进行轮动配置,力求能够抓住区间内表现较好的行业、剔除表现不佳的行业,在判断市场不佳的时候,权益类仓位降低,提升债券或货币的比例。

行业轮动的具体内容及特点

​ 我们可以将行业分为以下几类:

​ 周期性:当增长加速时,股票和大宗商品表现好,周期性行业例如汽车、房地产、钢铁股战胜市场;当增长放缓,债券、现金和防守型股票战胜市场。

成长性:当通胀率下降,贴现率下降,金融资产表现好,成长型股票战胜市场;当通胀率上升,大宗商品等实物资产和现金表现最好,定价权变强,价值型股票战胜市场。

利率敏感性:银行和消费类股票是利率敏感型的“早周期”表现者,在衰退和复苏阶段,当中央银行放松政策和经济增长率开始回升时表现最好。

资产类品种:一些行业和其拥有的资产的表现紧密相关,银行保险经常对债券和股票价格敏感,在衰退和复苏阶段表现好;采矿业股票对金属价格敏感,在过热阶段表现好;石油和天然气行业对油价敏感,在滞胀阶段战胜市场。

​ 上图来自“通达信板块地图”界面,结合近几年我国A股市场行业轮动的基本情况来看,周期循环通常是沿着产业链按一定的顺序地依次发生:住房和汽车消费是引领经济景气周期启动的主要和先导动力,这些行业在经济上升阶段(复苏期)的良好表现,将逐步带动机械设备、化工、建材等中游制造业的兴起,并传导到有色、钢铁、煤炭、石油等上游资源品行业,此时经济到达过热期。衰退也是由下游行业开始,逐步传导到上游行业。在经济景气的最高峰,商业一片繁荣,此时的主角就是非必需的消费品,如轿车、高档服装、奢侈品、消费类电子产品和旅游等行业,享受最后的经济周期盛宴。当经济下滑(滞胀期、衰退期),周期性行业业绩受到影响,而医药、必选消费等非周期性行业由于需求弹性小,受宏观经济影响不大,表现相对较好;银行价格相对较稳定,需求波动也较小,且作为利率敏感型的“早周期”表现者,兴起于衰退后期。当然,考虑到历史背景不同,行业周期轮动并非简单的重复,不能直接套用历史经验判断周期拐点,而应根据经验具体情况具体分析。

阶段 经济 通胀 最佳大类资产 最佳股票行业
收缩 债券 公共事业
复苏 股票 金融、有色
扩张 商品 钢铁
滞胀 现金 食品饮料、农林牧渔

行业轮动策略实现(基于掘金量化平台

策略思想

  • 每隔1个月定时触发计算“300工业”、“300材料”、“300可选”、“300消费”、“300医药”、“300金融”这几个行业指数过去20个交易日的收益率。

  • 随后选取了收益率最高的指数的成份股中流通市值最小的5只股票。

  • 对不在股票池的股票平仓并等权配置股票池的标的

策略主要步骤实现

获取当前交易日日期

now = context.now = context.now

​ 直接调用context.now函数,返回“datetime.datetime”格式

获取上一交易日日期

last_day = get_previous_trading_date(exchange='SHSE', date=now) = get_previous_trading_date(exchange='SHSE', date=now)

​ 获取上一交易日可调用get_previous_trading_date函数,返回值为字符串格式:

  • exchang需要设置交易市场代码

  • date需要设置指定日期。

固定月初调仓

schedule(schedule_func=algo, date_rule='1m', time_rule='09:40:00')(schedule_func=algo, date_rule='1m', time_rule='09:40:00')

​ 固定时间调仓可使用schedule函数进行定时任务配置:

  • 参数schedule_func为调用的策略函数。

  • date_rule可设为1m(一月)。

  • time_rule为开仓日的开仓时间,这里设为每月第一个交易日的09:40:00

获取过去交易日的历史信息

return_index_his = history_n(symbol=symbol, frequency='1d', count=20, fields='close,bob',fill_missing='Last', adjust=ADJUST_PREV, end_time=last_day, df=True) = history_n(symbol=symbol, frequency='1d', count=20, fields='close,bob',fill_missing='Last', adjust=ADJUST_PREV, end_time=last_day, df=True)

​ 获取历史信息需要调用histor_n函数,默认返回值为“字典“格式,如果参数df设为True,则返回"dataframe"格式

  • symbol设置所需获取的标的代码。

  • frequency获取历史信息的频率,如日线数据设置为1d

  • count需要设置获取的bar的数量。

  • fileds设置返回值的种类。

  • fill_missing需要设置对于空值的填充方式, None- 不填充,NaN- 用空值填充, Last- 用上一个值填充,默认 None

  • adjust需要设置对于复权的处理,ADJUST_NONE or 0: 不复权, ADJUST_PREV or 1: 前复权, ADJUST_POST or 2: 后复权, 默认不复权。

  • end_time需设置获取历史信息的结束时间。

获取指数成分股

symbols = get_history_constituents(index=index_symbol, start_date=last_day, end_date=last_day)[0]['constituents'].keys() = get_history_constituents(index=index_symbol, start_date=last_day, end_date=last_day)[0]['constituents'].keys()

​ 获取指数成分股可调用函数get_history_constituents或者get_constituents,返回值类型为list[dict],这里调用get_history_constituents是因为再回测时需要获取上一交易日的成分股,而get_constituents只能获取最新的成分股:

  • index需要设置获取指数的代码。

  • start_dateend_date需设置获取成分股的开始与结束日期,这里需要调成上一交易日以获取上一交易日的成分股信息。

获取当天有交易的股票

not_suspended_info = get_history_instruments(symbols=symbols, start_date=now, end_date=now)
not_suspended_symbols = [item['symbol'] for item in not_suspended_info if not item['is_suspended']] = get_history_instruments(symbols=symbols, start_date=now, end_date=now)
not_suspended_symbols = [item['symbol'] for item in not_suspended_info if not item['is_suspended']]

​ 获取当天有交易的股票,即非停牌的股票,首先需获取停牌信息,这里需调用get_history_instruments函数,返回值类型为list[dict],之后就是将所提取的“字典”转换为”list“:

  • symbols需要设置订阅的标的代码。

  • start_dateend_date需设置获取成分股的开始与结束日期,这里需要调成上一交易日以获取上一交易日的成分股信息。

获取财务(市值)信息

fin = get_fundamentals(table='tq_sk_finindic', symbols=not_suspended_symbols, start_date=last_day,end_date=last_day, limit=5, fields='NEGOTIABLEMV', order_by='NEGOTIABLEMV', df=True) = get_fundamentals(table='tq_sk_finindic', symbols=not_suspended_symbols, start_date=last_day,end_date=last_day, limit=5, fields='NEGOTIABLEMV', order_by='NEGOTIABLEMV', df=True)

获取财务数据使用get_fundamentals函数,返回值类型为list[dict]

  • table需填写所需获取指标所在表格的代码。

  • fields设置返回值的种类。

  • orde_by需设置数据的排序方式,默认 NoneTCLOSE 表示按 TCLOSE 升序排序。 -TCLOSE 表示按 TCLOSE 降序排序。TCLOSE, -NEGOTIABLEMV 表示按 TCLOSE 升序, NEGOTIABLEMV 降序综合排序。

  • limit表示返回值的个数。

策略回测分析

分析

​ 我们选取了2016年5月至2016年11月作为回测周期,可以看出:

  • 胜率(具有盈利的平仓次数与总平仓次数之比)达到了60%。

  • 卡玛比率(年化收益率与历史最大回撤之比)是使用最大回撤率来衡量风险。采用最大回撤率来衡量风险,关注的是最极端的情况。卡玛比率越高表示策略承受每单位最大损失获得的报酬越高。在这里卡玛比率超过了3.5。

  • 夏普比率(年化收益率减无风险收益率的差收益波动率之比)超过1,也即承受1单位的风险,会有超过1个单位的收益回报

  • 策略收益曲线较为稳定,在无止损条件的情况下,最大回撤控制在承受范围,并成功跑赢沪深300指数。

行业轮动策略源码

  1. # coding=utf-8
  2. from __future__ import print_function, absolute_import, unicode_literals
  3. import numpy as np
  4. from gm.api import *
  5.  
  6. '''
  7. 本策略每隔1个月定时触发计算SHSE.000910.SHSE.000909.SHSE.000911.SHSE.000912.SHSE.000913.SHSE.000914
  8. (300工业.300材料.300可选.300消费.300医药.300金融)这几个行业指数过去
  9. 20个交易日的收益率并选取了收益率最高的指数的成份股获取并获取了他们的市值数据
  10. 随后把仓位调整至市值最大的5只股票上
  11. 回测数据为:SHSE.000910.SHSE.000909.SHSE.000911.SHSE.000912.SHSE.000913.SHSE.000914和他们的成份股
  12. 回测时间为:2017-07-01 08:00:00到2017-10-01 16:00:00
  13. '''
  14.  
  15.  
  16. def init(context):
  17. # 每月第一个交易日的09:40 定时执行algo任务
  18. schedule(schedule_func=algo, date_rule='1m', time_rule='09:40:00')
  19. # 用于筛选的行业指数
  20. context.index = ['SHSE.000910', 'SHSE.000909', 'SHSE.000911', 'SHSE.000912', 'SHSE.000913', 'SHSE.000914']
  21. # 用于统计数据的天数
  22. context.date = 20
  23. # 最大下单资金比例
  24. context.ratio = 0.8
  25.  
  26.  
  27. def algo(context):
  28. # 获取当天的日期
  29. today = context.now
  30. # 获取上一个交易日
  31. last_day = get_previous_trading_date(exchange='SHSE', date=today)
  32. return_index = []
  33. # 获取并计算行业指数收益率
  34.  
  35. for i in context.index:
  36. return_index_his = history_n(symbol=i, frequency='1d', count=context.date, fields='close,bob',
  37. fill_missing='Last', adjust=ADJUST_PREV, end_time=last_day, df=True)
  38. return_index_his = return_index_his['close'].values
  39. return_index.APPend(return_index_his[-1] / return_index_his[0] - 1)
  40. # 获取指定数内收益率表现最好的行业
  41. sector = context.index[np.argmax(return_index)]
  42. print('最佳行业指数是: ', sector)
  43. # 获取最佳行业指数成份股
  44. symbols = get_history_constituents(index=sector, start_date=last_day, end_date=last_day)[0]['constituents'].keys()
  45. # 获取当天有交易的股票
  46. not_suspended_info = get_history_instruments(symbols=symbols, start_date=today, end_date=today)
  47. not_suspended_symbols = [item['symbol'] for item in not_suspended_info if not item['is_suspended']]
  48.  
  49. # 获取最佳行业指数成份股的市值,从大到小排序并选取市值最大的5只股票
  50. fin = get_fundamentals(table='tq_sk_finindic', symbols=not_suspended_symbols, start_date=last_day,
  51. end_date=last_day, limit=5, fields='NEGOTIABLEMV', order_by='-NEGOTIABLEMV', df=True)
  52. fin.index = fin['symbol']
  53. # 计算权重
  54. percent = 1.0 / len(fin.index) * context.ratio
  55. # 获取当前所有仓位
  56. positions = context.account().positions()
  57. # 如标的池有仓位,平不在标的池的仓位
  58. for position in positions:
  59. symbol = position['symbol']
  60. if symbol not in fin.index:
  61. order_target_percent(symbol=symbol, percent=0, order_type=OrderType_Market,
  62. position_side=PositionSide_Long)
  63. print('市价单平不在标的池的', symbol)
  64. # 对标的池进行操作
  65. for symbol in fin.index:
  66. order_target_percent(symbol=symbol, percent=percent, order_type=OrderType_Market,
  67. position_side=PositionSide_Long)
  68. print(symbol, '以市价单调整至仓位', percent)
  69.  
  70.  
  71. if __name__ == '__main__':
  72. '''
  73. strategy_id策略ID,由系统生成
  74. filename文件名,请与本文件名保持一致
  75. mode实时模式:MODE_LIVE回测模式:MODE_BACKTEST
  76. token绑定计算机的ID,可在系统设置-密钥管理中生成
  77. backtest_start_time回测开始时间
  78. backtest_end_time回测结束时间
  79. backtest_adjust股票复权方式不复权:ADJUST_NONE前复权:ADJUST_PREV后复权:ADJUST_POST
  80. backtest_initial_cash回测初始资金
  81. backtest_commission_ratio回测佣金比例
  82. backtest_slippage_ratio回测滑点比例
  83. '''
  84. run(strategy_id='strategy_id',
  85. filename='main.py',
  86. mode=MODE_BACKTEST,
  87. token='token_id',
  88. backtest_start_time='2017-07-01 08:00:00',
  89. backtest_end_time='2017-10-01 16:00:00',
  90. backtest_adjust=ADJUST_PREV,
  91. backtest_initial_cash=10000000,
  92. backtest_commission_ratio=0.0001,
  93. backtest_slippage_ratio=0.0001)

文章来源:掘金量化交易平台   转载请注明出处!

--------------------------------------------------------------------------------------------------------------

相关策略源码查看:

网格交易策略(附策略源码与收益图) https://www.myquant.cn/community/topic/548/2
指数增强策略 https://www.myquant.cn/community/topic/527
日内回转交易策略 https://www.myquant.cn/community/topic/526
跨期套利策略 https://www.myquant.cn/community/topic/525
跨品种价差套利策略 https://www.myquant.cn/community/topic/524
集合竞价选股 https://www.myquant.cn/community/topic/523
基于EV/EBITDA倍数估值法的Alpha对冲策略 https://www.myquant.cn/community/topic/522
行业轮动策略 https://www.myquant.cn/community/topic/521
海龟交易法则 https://www.myquant.cn/community/topic/520

相关阅读

B2B行业站要怎么建?

  B2B行业站要怎么建?要做好B2B这样的行业平台需要对B2B的功能有一定的了解,然后根据行业的特性选择最适合的功能,这样才是最重要

快消品行业的变革,从5个方面开始

快消品行业将围绕新消费、新商品、新营销、新渠道和数字化这5个方面发生变革,企业需要理清思路,以实际的行动从这五个方面做出一个

央视曝光违规分拣员:快递行业的毒瘤为何难除

11月16日消息,据央视财经《消费主张》栏目报道,双十一期间全峰快递、天天快递等公司仍然存在大量违规现象。例如:暴力分拣、包裹丢失

快消品迎来B2B元年,行业将如何变革?

未来,疲于争夺的区域性平台将会加速合作合并的步伐,优胜劣汰的行业大洗牌之后,全国范围内将出现实力超强的巨头企业,下一个独角兽即将

天天特价的商品库存数量及定价策略

准备报名天天特价的卖家朋友在填写资料的时候,需要填写与商品有关的信息。这时候给上活动的商品定什么价位,商品参加活动的数量有多

分享到:

栏目导航

推荐阅读

热门阅读