量化投资:第4节 多支股票择时回测与仓位管理

0
回复
5398
查看
[复制链接]

24

主题

15

回帖

227

积分

中级会员

积分
227
来源: 2019-10-31 23:24:21 显示全部楼层 |阅读模式

之前的章节无论讲解策略优化,还是针对回测进行滑点或是手续费都是针对一支股票进行择时操作。
本节将示例讲解多支股票进行择时策略的实现,依然使用AbuFactorBuyBreak做为买入策略,其它四个卖出策略同时生效的组合。


  1. <font style="background-color: white;">from abupy import AbuFactorBuyBreak, AbuFactorSellBreak
  2. from abupy import AbuFactorAtrNStop, AbuFactorPreAtrNStop, AbuFactorCloseAtrNStop
  3. from abupy import ABuPickTimeExecute, AbuBenchmark, AbuCapital

  4. # buy_factors 60日向上突破,42日向上突破两个因子
  5. buy_factors = [{'xd': 60, 'class': AbuFactorBuyBreak},
  6.                {'xd': 42, 'class': AbuFactorBuyBreak}]
  7. # 四个卖出因子同时并行生效
  8. sell_factors = [
  9.     {
  10.         'xd': 120,
  11.         'class': AbuFactorSellBreak
  12.     },
  13.     {
  14.         'stop_loss_n': 0.5,
  15.         'stop_win_n': 3.0,
  16.         'class': AbuFactorAtrNStop
  17.     },
  18.     {
  19.         'class': AbuFactorPreAtrNStop,
  20.         'pre_atr_n': 1.0
  21.     },
  22.     {
  23.         'class': AbuFactorCloseAtrNStop,
  24.         'close_atr_n': 1.5
  25.     }]
  26. benchmark = AbuBenchmark()
  27. capital = AbuCapital(1000000, benchmark)</font>
复制代码


1. 多支股票使用相同的因子进行择时
选择的股票如下所示:
choice_symbols = ['usTSLA', 'usNOAH', 'usSFUN', 'usBIDU', 'usAAPL',
'usGOOG', 'usWUBA', 'usVIPS']
备注:本节示例都基于美股市场,针对A股市场及港股市场,比特币,期货市场后在后面的章节讲解


  1. <font style="background-color: white;"># 我们假定choice_symbols是我们选股模块的结果,
  2. choice_symbols = ['usTSLA', 'usNOAH', 'usSFUN', 'usBIDU', 'usAAPL',
  3.                   'usGOOG', 'usWUBA', 'usVIPS']</font>
复制代码


使用ABuPickTimeExecute.do_symbols_with_same_factors()函数对多支股票使用相同的买入因子,卖出因子




  1. <font style="background-color: white;">%%time
  2. capital = AbuCapital(1000000, benchmark)
  3. orders_pd, action_pd, all_fit_symbols_cnt = ABuPickTimeExecute.do_symbols_with_same_factors(choice_symbols,
  4.                                                                                             benchmark,
  5.                                                                                             buy_factors,
  6.                                                                                             sell_factors,
  7.                                                                                             capital,
  8.                                                                                             show=False)</font>
复制代码

  1. <font style="background-color: white;"><span style='color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>CPU </span><span class="hljs-string" style='color: rgb(163, 21, 21); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>times:</span><span style='color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'> user </span><span class="hljs-number" style='color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>18.5</span><span style='color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'> s, </span><span class="hljs-string" style='color: rgb(163, 21, 21); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>sys:</span><span style='color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'> </span><span class="hljs-number" style='color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>264</span><span style='color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'> ms, </span><span class="hljs-string" style='color: rgb(163, 21, 21); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>total:</span><span style='color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'> </span><span class="hljs-number" style='color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>20.1</span></font><font style="background-color: white;"><span style='color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'> s
  2. Wall </span><span class="hljs-string" style='color: rgb(163, 21, 21); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>time:</span><span style='color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'> </span><span class="hljs-number" style='color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>19.2</span><span style='color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'> s</span></font>
复制代码


运行完毕,使用了ipython的magic code %%time去统计代码块运行时间,显示运行了19.2 s,本节最后会使用多进程模式运行相同的回测,会和这个时间进行比较。
备注:具体实际运行时间根据cpu的性能确定
下面代码显示orders_pd中前10个交易数据:
  1. <font style="background-color: white;">orders_pd[:10]</font>
复制代码
103107.png





通过buy_cnt列可以发现每次交易数量都不一样,由于内部有资金管理控制模块默认使用atr进行仓位控制
默认资金管理控制使用AbuAtrPosition,详情请阅读源代码,下面会有自定义仓位管理的示例。
下面代码显示action_pd中前10个行为数据:
  1. action_pd[:10]
复制代码

103108.png








  • 注意deal列代表了交易是否成交,由于内部有资金管理控制模块,所以不是所有交易信号都可以最后成交。
下面我们使用abu量化系统度量模块对整体结果做个度量,如下图所示(之后章节会对度量方法及模块进行详细讲解,这里请先简单使用即可)。




  1. <font style="background-color: white;">from abupy import AbuMetricsBase
  2. metrics = AbuMetricsBase(orders_pd, action_pd, capital, benchmark)
  3. metrics.fit_metrics()
  4. metrics.plot_returns_cmp(only_show_returns=True)</font>
复制代码

  1. <font style="background-color: white;">买入后卖出的交易数量:67
  2. 买入后尚未卖出的交易数量:3
  3. 胜率:43.2836%
  4. 平均获利期望:12.2712%
  5. 平均亏损期望:-4.9050%
  6. 盈亏比:1.9327
  7. 策略收益: 29.4383%
  8. 基准收益: 15.0841%
  9. 策略年化收益: 14.7192%
  10. 基准年化收益: 7.5420%
  11. 策略买入成交比例:84.2857%
  12. 策略资金利用率比例:22.3612%
  13. 策略共执行504个交易日</font>
复制代码
103109.png



2. 自定义仓位管理策略的实现
上面使用AbuMetricsBase进行度量,我们计算出:
  • 胜率:41.79%
  • 平均获利期望:12.01%
  • 平均亏损期望:-4.91%
有这三个参数就可以使用kelly公式来做仓位控制,AbuKellyPosition实现如下:


  1. <font style="background-color: white;">class AbuKellyPosition(AbuPositionBase):
  2.     """示例kelly仓位管理类"""

  3.     def fit_position(self, factor_object):
  4.         """
  5.         fit_position计算的结果是买入多少个单位(股,手,顿,合约)
  6.         需要factor_object策略因子对象通过历史回测统计胜率,期望收益,期望亏损,
  7.         并设置构造当前factor_object对象,通过kelly公司计算仓位
  8.         :param factor_object: ABuFactorBuyBases子类实例对象
  9.         :return:买入多少个单位(股,手,顿,合约)
  10.         """
  11.         # 败率
  12.         loss_rate = 1 - self.win_rate
  13.         # kelly计算出仓位比例
  14.         kelly_pos = self.win_rate - loss_rate / (self.gains_mean / self.losses_mean)
  15.         # 最大仓位限制,依然受上层最大仓位控制限制,eg:如果kelly计算出全仓,依然会减少到75%,如修改需要修改最大仓位值
  16.         kelly_pos = self.pos_max if kelly_pos > self.pos_max else kelly_pos
  17.         # 结果是买入多少个单位(股,手,顿,合约)
  18.         return self.read_cash * kelly_pos / self.bp * self.deposit_rate

  19.     def _init_self(self, **kwargs):
  20.         """kelly仓位控制管理类初始化设置"""

  21.         # 默认kelly仓位胜率0.50
  22.         self.win_rate = kwargs.pop('win_rate', 0.50)
  23.         # 默认平均获利期望0.10
  24.         self.gains_mean = kwargs.pop('gains_mean', 0.10)
  25.         # 默认平均亏损期望0.05
  26.         self.losses_mean = kwargs.pop('losses_mean', 0.05)

  27.         """以默认的设置kelly根据计算0.5 - 0.5 / (0.10 / 0.05) 仓位将是0.25即25%"""</font>
复制代码


自定义仓位管理代码如上AbuKellyPosition:
  • 仓位管理类需要继承AbuPositionBase
  • 仓位管理类主要需要实现函数fit_position,即根据买入价格,本金基数等融合买入策略对买入单位进行计算
  • 仓位管理类主要需要实现函数_init_self,外部通过字典参数将胜率等参数进行关键子参数设置(详见后使用示例)
更多资金管理代码请阅读AbuPositionBase
下面编写buy_factors2,其42d突破使用position=AbuKellyPosition
  • 参数胜率:metrics.win_rate(41.79%)
  • 期望收益:metrics.gains_mean(12.01%)
  • 期望亏损:metrics.losses_mean(-4.91%),
代码如下所示:


  1. <font style="background-color: white;"><span class="hljs-keyword" style='color: rgb(0, 0, 255); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>from</span><span style='color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'> abupy </span><span class="hljs-keyword" style='color: rgb(0, 0, 255); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>import</span></font><font style="background-color: white;"><span style='color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'> AbuKellyPosition

  2. </span><span class="hljs-comment" style='color: rgb(0, 128, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'># 42d使用刚刚编写的AbuKellyPosition,60d仍然使用默认仓位管理类,即abupy中内置的AbuAtrPosition类</span></font><span style='color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>
  3. <font style="background-color: white;">buy_factors2 = [{</font></span><font style="background-color: white;"><span class="hljs-string" style='color: rgb(163, 21, 21); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>'xd'</span><span style='color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>: </span><span class="hljs-number" style='color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>60</span><span style='color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>, </span><span class="hljs-string" style='color: rgb(163, 21, 21); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>'class'</span></font><font style="background-color: white;"><span style='color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>: AbuFactorBuyBreak},
  4.                 {</span><span class="hljs-string" style='color: rgb(163, 21, 21); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>'xd'</span><span style='color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>: </span><span class="hljs-number" style='color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>42</span><span style='color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>, </span><span class="hljs-string" style='color: rgb(163, 21, 21); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>'position'</span><span style='color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>: {</span><span class="hljs-string" style='color: rgb(163, 21, 21); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>'class'</span><span style='color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>: AbuKellyPosition, </span><span class="hljs-string" style='color: rgb(163, 21, 21); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>'win_rate'</span></font><font style="background-color: white;"><span style='color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>: metrics.win_rate,
  5.                                         </span><span class="hljs-string" style='color: rgb(163, 21, 21); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>'gains_mean'</span><span style='color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>: metrics.gains_mean, </span><span class="hljs-string" style='color: rgb(163, 21, 21); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>'losses_mean'</span></font><font style="background-color: white;"><span style='color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>: -metrics.losses_mean},
  6.                  </span><span class="hljs-string" style='color: rgb(163, 21, 21); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>'class'</span></font><font style="background-color: white;"><span style='color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>: AbuFactorBuyBreak}]

  7. capital = AbuCapital(</span><span class="hljs-number" style='color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>1000000</span></font><font style="background-color: white;"><span style='color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>, benchmark)
  8. orders_pd, action_pd, all_fit_symbols_cnt = ABuPickTimeExecute.do_symbols_with_same_factors(choice_symbols,
  9.                                                                                             benchmark,
  10.                                                                                             buy_factors2,
  11.                                                                                             sell_factors,
  12.                                                                                             capital,
  13.                                                                                             show=</span><span class="hljs-keyword" style='color: rgb(0, 0, 255); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>False</span><span style='color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; font-family: "Courier New", sans-serif; font-size: 12px; font-style: normal; font-weight: normal; word-spacing: 0px; float: none; display: inline !important; white-space: pre-wrap; orphans: 2; widows: 2; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px;'>)</span></font>
复制代码


从输出生成的orders_pd中可以看到buy Pos列所有42d突破都使用了AbuKellyPosition,60d仍然使用AbuAtrPosition
  1. <font style="background-color: white;">orders_pd[:10].filter(['symbol', 'buy_cnt', 'buy_factor', 'buy_pos'])</font>
复制代码
103110.png

3. 多支股票使用不同的因子进行择时
使用ABuPickTimeExecute.do_symbols_with_diff_factors()函数针对不同的股票使用不同的买入因子和不同的卖出因子,
具体实现请查阅源代码ABuPickTimeExecute,使用示例如下:
  1. <font style="background-color: white;"># 选定noah和sfun
  2. target_symbols = ['usSFUN', 'usNOAH']

  3. # 针对sfun只使用42d向上突破作为买入因子
  4. buy_factors_sfun = [{'xd': 42, 'class': AbuFactorBuyBreak}]
  5. # 针对sfun只使用60d向下突破作为卖出因子
  6. sell_factors_sfun = [{'xd': 60, 'class': AbuFactorSellBreak}]

  7. # 针对noah只使用21d向上突破作为买入因子
  8. buy_factors_noah = [{'xd': 21, 'class': AbuFactorBuyBreak}]
  9. # 针对noah只使用42d向下突破作为卖出因子
  10. sell_factors_noah = [{'xd': 42, 'class': AbuFactorSellBreak}]

  11. factor_dict = dict()
  12. # 构建SFUN独立的buy_factors,sell_factors的dict
  13. factor_dict['usSFUN'] = {'buy_factors': buy_factors_sfun,
  14.                          'sell_factors': sell_factors_sfun}

  15. # 构建NOAH独立的buy_factors,sell_factors的dict
  16. factor_dict['usNOAH'] = {'buy_factors': buy_factors_noah,
  17.                          'sell_factors': sell_factors_noah}

  18. # 初始化资金
  19. capital = AbuCapital(1000000, benchmark)
  20. # 使用do_symbols_with_diff_factors执行
  21. orders_pd, action_pd, all_fit_symbols = ABuPickTimeExecute.do_symbols_with_diff_factors(target_symbols,
  22.                                                                                         benchmark,
  23.                                                                                         factor_dict,
  24.                                                                                         capital)</font>
复制代码




如下代码通过pandas的交叉表来分析输出的orders_pd, 来证明: noah买入因子全部是使用21d向上突破,sfun买入因子全部是使用42d向上突破:
  1. <font style="background-color: white;">pd.crosstab(orders_pd.buy_factor, orders_pd.symbol)</font>
复制代码
103111.png

4. 使用并行来提升择时运行效率
当你选择的股票非常多的时候,比如很多时候是对全市场进行回测,那就需要多进程并行来提升运行效率,AbuPickTimeMaster.do_symbols_with_same_factors_process()函数通过定义n_process_kl(同时获取股票数据的进程数)和n_process_pick_time(同时进行择时的进程数)来完成操作.
具体实现代码请阅读AbuPickTimeMaster,使用示例如下所示:


  1. <font style="background-color: white;">%%time
  2. from abupy import AbuPickTimeMaster

  3. capital = AbuCapital(1000000, benchmark)
  4. orders_pd, action_pd, _ = AbuPickTimeMaster.do_symbols_with_same_factors_process(
  5.                                     choice_symbols, benchmark, buy_factors, sell_factors, capital,
  6.                                     n_process_kl=4, n_process_pick_time=4)</font>
复制代码

  1. <font style="background-color: white;">pid:12502 gen kl_pd complete:100.0%
  2. pid:12503 gen kl_pd complete:100.0%
  3. pid:12504 gen kl_pd complete:100.0%
  4. pid:12505 gen kl_pd complete:100.0%
  5. pid:12506 gen kl_pd complete:100.0%
  6. pid:12507 gen kl_pd complete:100.0%
  7. pid:12508 gen kl_pd complete:100.0%
  8. pid:12509 gen kl_pd complete:100.0%
  9. pid:12503 done!
  10. pid:12505 done!
  11. pid:12506 done!
  12. pid:12507 done!
  13. pid:12504 done!
  14. pid:12502 done!
  15. pid:12509 done!
  16. pid:12508 done!
  17. pid:12510 pick times complete:100.0%
  18. pid:12511 pick times complete:100.0%
  19. pid:12512 pick times complete:100.0%
  20. pid:12513 pick times complete:100.0%
  21. pid:12514 pick times complete:100.0%
  22. pid:12515 pick times complete:100.0%
  23. pid:12516 pick times complete:100.0%
  24. pid:12517 pick times complete:100.0%
  25. pid:12510 done!
  26. pid:12512 done!
  27. pid:12515 done!
  28. pid:12513 done!
  29. pid:12511 done!
  30. pid:12514 done!
  31. pid:12517 done!
  32. pid:12516 done!
  33. CPU times: user 2.48 s, sys: 192 ms, total: 2.67 s
  34. Wall time: 6.36s</font>
复制代码


依然使用%%time度量代码块运行时间,之前使用开始时使用ABuPickTimeExecute运行相同的回测输出运行时间19.2 s,
使用AbuPickTimeMaster使用参数n_process_pick_time=8,即启动8个择时进程后,运行时间缩短到6.36s,从输出的信息也可以看到8个pid同时进行
择时
  • pid:84544 pick times complete:100.0%
  • pid:84545 pick times complete:100.0%
  • pid:84546 pick times complete:100.0%
  • pid:84547 pick times complete:100.0%
  • pid:84548 pick times complete:100.0%
  • pid:84549 pick times complete:100.0%
  • pid:84550 pick times complete:100.0%
  • pid:84551 pick times complete:100.0%
多进程的运行方式在进行多支股票设置全市场策略回测时是非常有用的,本节由于choice_symbols中的股票数少,n_process_kl即并行金融数据采集模块
并没有使用,还有一些需要注意的地方也还没有讲到,在后续的全市场回测章节讲继续讲解。
备注:
由于本例开辟进程数较多,但是每个进程处理的任务非常少,所以在cpu不够快的电脑上结果可能正好相反,多进程模式的运行也行会更加耗时,效率更低,属正常现象,后面的例子每个进程可能会处理几十几百个交易对象就不会出现创建销毁进程的开销大于任务执行时间的情况
  • 特别是windows系统,mac上不会发生,由于mac上的并行使用joblib,在windows上长任务joblib存在bug,所以windows上并行只是封装为joblib的接口形式,详情阅读源代码ABuParallel




















回复

使用道具 举报

您需要登录后才可以回帖 登录 | 免费注册
关注微信