作者: 阿布
阿布量化版权所有 未经允许 禁止转载
之前的章节无论讲解策略优化,还是针对回测进行滑点或是手续费都是针对一支股票进行择时操作。
本节将示例讲解多支股票进行择时策略的实现,依然使用AbuFactorBuyBreak做为买入策略,其它四个卖出策略同时生效的组合。
from abupy import AbuFactorBuyBreak, AbuFactorSellBreak
from abupy import AbuFactorAtrNStop, AbuFactorPreAtrNStop, AbuFactorCloseAtrNStop
from abupy import ABuPickTimeExecute, AbuBenchmark, AbuCapital
# buy_factors 60日向上突破,42日向上突破两个因子
buy_factors = [{'xd': 60, 'class': AbuFactorBuyBreak},
{'xd': 42, 'class': AbuFactorBuyBreak}]
# 四个卖出因子同时并行生效
sell_factors = [
{
'xd': 120,
'class': AbuFactorSellBreak
},
{
'stop_loss_n': 0.5,
'stop_win_n': 3.0,
'class': AbuFactorAtrNStop
},
{
'class': AbuFactorPreAtrNStop,
'pre_atr_n': 1.0
},
{
'class': AbuFactorCloseAtrNStop,
'close_atr_n': 1.5
}]
benchmark = AbuBenchmark()
capital = AbuCapital(1000000, benchmark)
选择的股票如下所示:
choice_symbols = [‘usTSLA’, ‘usNOAH’, ‘usSFUN’, ‘usBIDU’, ‘usAAPL’,
‘usGOOG’, ‘usWUBA’, ‘usVIPS’]
备注:本节示例都基于美股市场,针对A股市场及港股市场,比特币,期货市场后在后面的章节讲解
# 我们假定choice_symbols是我们选股模块的结果,
choice_symbols = ['usTSLA', 'usNOAH', 'usSFUN', 'usBIDU', 'usAAPL',
'usGOOG', 'usWUBA', 'usVIPS']
使用ABuPickTimeExecute.do_symbols_with_same_factors()函数对多支股票使用相同的买入因子,卖出因子
%%time
capital = AbuCapital(1000000, benchmark)
orders_pd, action_pd, all_fit_symbols_cnt = ABuPickTimeExecute.do_symbols_with_same_factors(choice_symbols,
benchmark,
buy_factors,
sell_factors,
capital,
show=False)
CPU times: user 18.5 s, sys: 264 ms, total: 20.1 s
Wall time: 19.2 s
运行完毕,使用了ipython的magic code %%time去统计代码块运行时间,显示运行了19.2 s,本节最后会使用多进程模式运行相同的回测,会和这个时间进行比较。
备注:具体实际运行时间根据cpu的性能确定
下面代码显示orders_pd中前10个交易数据:
orders_pd[:10]
通过buy_cnt列可以发现每次交易数量都不一样,由于内部有资金管理控制模块默认使用atr进行仓位控制
默认资金管理控制使用AbuAtrPosition,详情请阅读源代码,下面会有自定义仓位管理的示例。
下面代码显示action_pd中前10个行为数据:
action_pd[:10]
下面我们使用abu量化系统度量模块对整体结果做个度量,如下图所示(之后章节会对度量方法及模块进行详细讲解,这里请先简单使用即可)。
from abupy import AbuMetricsBase
metrics = AbuMetricsBase(orders_pd, action_pd, capital, benchmark)
metrics.fit_metrics()
metrics.plot_returns_cmp(only_show_returns=True)
买入后卖出的交易数量:67
买入后尚未卖出的交易数量:3
胜率:43.2836%
平均获利期望:12.2712%
平均亏损期望:-4.9050%
盈亏比:1.9327
策略收益: 29.4383%
基准收益: 15.0841%
策略年化收益: 14.7192%
基准年化收益: 7.5420%
策略买入成交比例:84.2857%
策略资金利用率比例:22.3612%
策略共执行504个交易日
上面使用AbuMetricsBase进行度量,我们计算出:
有这三个参数就可以使用kelly公式来做仓位控制,AbuKellyPosition实现如下:
class AbuKellyPosition(AbuPositionBase):
"""示例kelly仓位管理类"""
def fit_position(self, factor_object):
""" fit_position计算的结果是买入多少个单位(股,手,顿,合约) 需要factor_object策略因子对象通过历史回测统计胜率,期望收益,期望亏损, 并设置构造当前factor_object对象,通过kelly公司计算仓位 :param factor_object: ABuFactorBuyBases子类实例对象 :return:买入多少个单位(股,手,顿,合约) """
# 败率
loss_rate = 1 - self.win_rate
# kelly计算出仓位比例
kelly_pos = self.win_rate - loss_rate / (self.gains_mean / self.losses_mean)
# 最大仓位限制,依然受上层最大仓位控制限制,eg:如果kelly计算出全仓,依然会减少到75%,如修改需要修改最大仓位值
kelly_pos = self.pos_max if kelly_pos > self.pos_max else kelly_pos
# 结果是买入多少个单位(股,手,顿,合约)
return self.read_cash * kelly_pos / self.bp * self.deposit_rate
def _init_self(self, **kwargs):
"""kelly仓位控制管理类初始化设置"""
# 默认kelly仓位胜率0.50
self.win_rate = kwargs.pop('win_rate', 0.50)
# 默认平均获利期望0.10
self.gains_mean = kwargs.pop('gains_mean', 0.10)
# 默认平均亏损期望0.05
self.losses_mean = kwargs.pop('losses_mean', 0.05)
"""以默认的设置kelly根据计算0.5 - 0.5 / (0.10 / 0.05) 仓位将是0.25即25%"""
自定义仓位管理代码如上AbuKellyPosition:
更多资金管理代码请阅读AbuPositionBase
下面编写buy_factors2,其42d突破使用position=AbuKellyPosition
代码如下所示:
from abupy import AbuKellyPosition
# 42d使用刚刚编写的AbuKellyPosition,60d仍然使用默认仓位管理类,即abupy中内置的AbuAtrPosition类
buy_factors2 = [{'xd': 60, 'class': AbuFactorBuyBreak},
{'xd': 42, 'position': {'class': AbuKellyPosition, 'win_rate': metrics.win_rate,
'gains_mean': metrics.gains_mean, 'losses_mean': -metrics.losses_mean},
'class': AbuFactorBuyBreak}]
capital = AbuCapital(1000000, benchmark)
orders_pd, action_pd, all_fit_symbols_cnt = ABuPickTimeExecute.do_symbols_with_same_factors(choice_symbols,
benchmark,
buy_factors2,
sell_factors,
capital,
show=False)
从输出生成的orders_pd中可以看到buy Pos列所有42d突破都使用了AbuKellyPosition,60d仍然使用AbuAtrPosition
orders_pd[:10].filter(['symbol', 'buy_cnt', 'buy_factor', 'buy_pos'])
使用ABuPickTimeExecute.do_symbols_with_diff_factors()函数针对不同的股票使用不同的买入因子和不同的卖出因子,
具体实现请查阅源代码ABuPickTimeExecute,使用示例如下:
# 选定noah和sfun
target_symbols = ['usSFUN', 'usNOAH']
# 针对sfun只使用42d向上突破作为买入因子
buy_factors_sfun = [{'xd': 42, 'class': AbuFactorBuyBreak}]
# 针对sfun只使用60d向下突破作为卖出因子
sell_factors_sfun = [{'xd': 60, 'class': AbuFactorSellBreak}]
# 针对noah只使用21d向上突破作为买入因子
buy_factors_noah = [{'xd': 21, 'class': AbuFactorBuyBreak}]
# 针对noah只使用42d向下突破作为卖出因子
sell_factors_noah = [{'xd': 42, 'class': AbuFactorSellBreak}]
factor_dict = dict()
# 构建SFUN独立的buy_factors,sell_factors的dict
factor_dict['usSFUN'] = {'buy_factors': buy_factors_sfun,
'sell_factors': sell_factors_sfun}
# 构建NOAH独立的buy_factors,sell_factors的dict
factor_dict['usNOAH'] = {'buy_factors': buy_factors_noah,
'sell_factors': sell_factors_noah}
# 初始化资金
capital = AbuCapital(1000000, benchmark)
# 使用do_symbols_with_diff_factors执行
orders_pd, action_pd, all_fit_symbols = ABuPickTimeExecute.do_symbols_with_diff_factors(target_symbols,
benchmark,
factor_dict,
capital)
如下代码通过pandas的交叉表来分析输出的orders_pd, 来证明: noah买入因子全部是使用21d向上突破,sfun买入因子全部是使用42d向上突破:
pd.crosstab(orders_pd.buy_factor, orders_pd.symbol)
当你选择的股票非常多的时候,比如很多时候是对全市场进行回测,那就需要多进程并行来提升运行效率,AbuPickTimeMaster.do_symbols_with_same_factors_process()函数通过定义n_process_kl(同时获取股票数据的进程数)和n_process_pick_time(同时进行择时的进程数)来完成操作.
具体实现代码请阅读AbuPickTimeMaster,使用示例如下所示:
%%time
from abupy import AbuPickTimeMaster
capital = AbuCapital(1000000, benchmark)
orders_pd, action_pd, _ = AbuPickTimeMaster.do_symbols_with_same_factors_process(
choice_symbols, benchmark, buy_factors, sell_factors, capital,
n_process_kl=4, n_process_pick_time=4)
pid:12502 gen kl_pd complete:100.0%
pid:12503 gen kl_pd complete:100.0%
pid:12504 gen kl_pd complete:100.0%
pid:12505 gen kl_pd complete:100.0%
pid:12506 gen kl_pd complete:100.0%
pid:12507 gen kl_pd complete:100.0%
pid:12508 gen kl_pd complete:100.0%
pid:12509 gen kl_pd complete:100.0%
pid:12503 done!
pid:12505 done!
pid:12506 done!
pid:12507 done!
pid:12504 done!
pid:12502 done!
pid:12509 done!
pid:12508 done!
pid:12510 pick times complete:100.0%
pid:12511 pick times complete:100.0%
pid:12512 pick times complete:100.0%
pid:12513 pick times complete:100.0%
pid:12514 pick times complete:100.0%
pid:12515 pick times complete:100.0%
pid:12516 pick times complete:100.0%
pid:12517 pick times complete:100.0%
pid:12510 done!
pid:12512 done!
pid:12515 done!
pid:12513 done!
pid:12511 done!
pid:12514 done!
pid:12517 done!
pid:12516 done!
CPU times: user 2.48 s, sys: 192 ms, total: 2.67 s
Wall time: 6.36s
依然使用%%time度量代码块运行时间,之前使用开始时使用ABuPickTimeExecute运行相同的回测输出运行时间19.2 s,
使用AbuPickTimeMaster使用参数n_process_pick_time=8,即启动8个择时进程后,运行时间缩短到6.36s,从输出的信息也可以看到8个pid同时进行
择时
多进程的运行方式在进行多支股票设置全市场策略回测时是非常有用的,本节由于choice_symbols中的股票数少,n_process_kl即并行金融数据采集模块
并没有使用,还有一些需要注意的地方也还没有讲到,在后续的全市场回测章节讲继续讲解。
备注:
由于本例开辟进程数较多,但是每个进程处理的任务非常少,所以在cpu不够快的电脑上结果可能正好相反,多进程模式的运行也行会更加耗时,效率更低,属正常现象,后面的例子每个进程可能会处理几十几百个交易对象就不会出现创建销毁进程的开销大于任务执行时间的情况
更多关于abu量化系统请关注微信公众号: abu_quant