<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 ABU量化系统使用文档
<center>
        <img src="./image/abu_logo.png" alt="" style="vertical-align
Step1:  之前的章节无论讲解策略优化，还是针对回测进行滑点或是手续费都是针对一支股票进行择时操作。
本节将示例讲解多支股票进行择时策略的实现，依然使用AbuFactorBuyBreak做为买入策略，其它四个卖出策略同时生效的组合。
Step2:  1. 多支股票使用相同的因子进行择时
选择的股票如下所示：
choice_symbols = ['usTSLA', 'usNOAH', 'usSFUN', 'usBIDU', 'usAAPL',
                  'usGOOG', 'usWUBA', 'usVIPS']
备注：本节示例都基于美股市场，针对A股市场及港股市场，比特币，期货市场后在后面的章节讲解
Step3:  使用ABuPickTimeExecute.do_symbols_with_same_factors()函数对多支股票使用相同的买入因子，卖出因子
Step4:  运行完毕，使用了ipython的magic code %%time去统计代码块运行时间，显示运行了19.2 s，本节最后会使用多进程模式运行相同的回测，会和这个时间进行比较。
备注：具体实际运行时间根据cpu的性能确定
下面代码显示orders_pd中前10个交易数据：
Step5:  通过buy_cnt列可以发现每次交易数量都不一样，由于内部有资金管理控制模块默认使用atr进行仓位控制
默认资金管理控制使用AbuAtrPosition，详情请阅读源代码，下面会有自定义仓位管理的示例。
下面代码显示action_pd中前10个行为数据：
Step6:  注意deal列代表了交易是否成交，由于内部有资金管理控制模块，所以不是所有交易信号都可以最后成交。
下面我们使用abu量化系统度量模块对整体结果做个度量，如下图所示（之后章节会对度量方法及模块进行详细讲解，这里请先简单使用即可）。
Step11:  2. 自定义仓位管理策略的实现
上面使用AbuMetricsBase进行度量，我们计算出：
胜率
Step12:  自定义仓位管理代码如上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%)，
代码如下所示：
Step13:  从输出生成的orders_pd中可以看到buy Pos列所有42d突破都使用了AbuKellyPosition，60d仍然使用AbuAtrPosition
Step14:  3. 多支股票使用不同的因子进行择时
使用ABuPickTimeExecute.do_symbols_with_diff_factors()函数针对不同的股票使用不同的买入因子和不同的卖出因子，
具体实现请查阅源代码ABuPickTimeExecute，使用示例如下：
Step15:  如下代码通过pandas的交叉表来分析输出的orders_pd， 来证明
Step16:  4. 使用并行来提升择时运行效率
当你选择的股票非常多的时候，比如很多时候是对全市场进行回测，那就需要多进程并行来提升运行效率，AbuPickTimeMaster.do_symbols_with_same_factors_process()函数通过定义n_process_kl（同时获取股票数据的进程数）和n_process_pick_time（同时进行择时的进程数）来完成操作.
具体实现代码请阅读AbuPickTimeMaster，使用示例如下所示：
<ASSISTANT_TASK:>
Python Code:
from __future__ import print_function
from __future__ import division
import warnings
warnings.filterwarnings('ignore')
warnings.simplefilter('ignore')
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
import os
import sys
# 使用insert 0即只使用github，避免交叉使用了pip安装的abupy，导致的版本不一致问题
sys.path.insert(0, os.path.abspath('../'))
import abupy
# 使用沙盒数据，目的是和书中一样的数据环境
abupy.env.enable_example_env_ipython()
Explanation: ABU量化系统使用文档
<center>
        <img src="./image/abu_logo.png" alt="" style="vertical-align:middle;padding:10px 20px;"><font size="6" color="black"><b>第4节 多支股票择时回测与仓位管理</b></font>
</center>
作者: 阿布
阿布量化版权所有 未经允许 禁止转载
abu量化系统github地址 (您的star是我的动力！)
本节ipython notebook
首先导入abupy中本节使用的模块：
End of explanation
from abupy import AbuFactorBuyBreak, AbuFactorSellBreak, AbuPositionBase
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)
Explanation: 之前的章节无论讲解策略优化，还是针对回测进行滑点或是手续费都是针对一支股票进行择时操作。
本节将示例讲解多支股票进行择时策略的实现，依然使用AbuFactorBuyBreak做为买入策略，其它四个卖出策略同时生效的组合。
End of explanation
# 我们假定choice_symbols是我们选股模块的结果，
choice_symbols = ['usTSLA', 'usNOAH', 'usSFUN', 'usBIDU', 'usAAPL',
                  'usGOOG', 'usWUBA', 'usVIPS']
Explanation: 1. 多支股票使用相同的因子进行择时
选择的股票如下所示：
choice_symbols = ['usTSLA', 'usNOAH', 'usSFUN', 'usBIDU', 'usAAPL',
                  'usGOOG', 'usWUBA', 'usVIPS']
备注：本节示例都基于美股市场，针对A股市场及港股市场，比特币，期货市场后在后面的章节讲解
End of explanation
%%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)
Explanation: 使用ABuPickTimeExecute.do_symbols_with_same_factors()函数对多支股票使用相同的买入因子，卖出因子
End of explanation
orders_pd[:10]
Explanation: 运行完毕，使用了ipython的magic code %%time去统计代码块运行时间，显示运行了19.2 s，本节最后会使用多进程模式运行相同的回测，会和这个时间进行比较。
备注：具体实际运行时间根据cpu的性能确定
下面代码显示orders_pd中前10个交易数据：
End of explanation
action_pd[:10]
Explanation: 通过buy_cnt列可以发现每次交易数量都不一样，由于内部有资金管理控制模块默认使用atr进行仓位控制
默认资金管理控制使用AbuAtrPosition，详情请阅读源代码，下面会有自定义仓位管理的示例。
下面代码显示action_pd中前10个行为数据：
End of explanation
from abupy import AbuMetricsBase 
metrics = AbuMetricsBase(orders_pd, action_pd, capital, benchmark)
metrics.fit_metrics()
metrics.plot_returns_cmp(only_show_returns=True)
Explanation: 注意deal列代表了交易是否成交，由于内部有资金管理控制模块，所以不是所有交易信号都可以最后成交。
下面我们使用abu量化系统度量模块对整体结果做个度量，如下图所示（之后章节会对度量方法及模块进行详细讲解，这里请先简单使用即可）。
End of explanation
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%
Explanation: 2. 自定义仓位管理策略的实现
上面使用AbuMetricsBase进行度量，我们计算出：
胜率:41.79%
平均获利期望:12.01%
平均亏损期望:-4.91%
有这三个参数就可以使用kelly公式来做仓位控制，AbuKellyPosition实现如下：
End of explanation
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)
Explanation: 自定义仓位管理代码如上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%)，
代码如下所示：
End of explanation
orders_pd[:10].filter(['symbol', 'buy_cnt', 'buy_factor', 'buy_pos'])
Explanation: 从输出生成的orders_pd中可以看到buy Pos列所有42d突破都使用了AbuKellyPosition，60d仍然使用AbuAtrPosition
End of explanation
# 选定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)
Explanation: 3. 多支股票使用不同的因子进行择时
使用ABuPickTimeExecute.do_symbols_with_diff_factors()函数针对不同的股票使用不同的买入因子和不同的卖出因子，
具体实现请查阅源代码ABuPickTimeExecute，使用示例如下：
End of explanation
pd.crosstab(orders_pd.buy_factor, orders_pd.symbol)
Explanation: 如下代码通过pandas的交叉表来分析输出的orders_pd， 来证明: noah买入因子全部是使用21d向上突破，sfun买入因子全部是使用42d向上突破：
End of explanation
%%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)
Explanation: 4. 使用并行来提升择时运行效率
当你选择的股票非常多的时候，比如很多时候是对全市场进行回测，那就需要多进程并行来提升运行效率，AbuPickTimeMaster.do_symbols_with_same_factors_process()函数通过定义n_process_kl（同时获取股票数据的进程数）和n_process_pick_time（同时进行择时的进程数）来完成操作.
具体实现代码请阅读AbuPickTimeMaster，使用示例如下所示：
End of explanation
<END_TASK>