<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:  很多刚接触交易的人总喜欢把交易看成一种有固定收入的工作，比如他们有自己的规矩，周五一定要把所有股票都卖了，安安心心过周末，周一看情况一切良好再把股票买回来。
还有一些人有着很奇怪的癖好认为周三是他的幸运日，在周三买入他选中的股票，有些人每个月第一个周五发工资，市场就是由这些各种各样的人组成的。
某一个股票上的活跃用户在一段短时间内变化并不大，也就是说这些习惯周五卖周一买的人会反复在一支股票上交易，普通投资者普遍的投资方式是针对一支股票不断的进行买卖，他们不会长期持有这支股票，但也不会远离这支股票很长时间，我认为有两点促成了以上事实。
贪欲：贪欲在这中间起到了很大的作用，当一个人第一次买入一支股票并且持有到有一定利润的时候，他选择卖出这支股票，因为他认为涨的已经很多了，该适当的回调了，之后股价的走势只有两种可能：第一按照他的预期下跌，这样的话他可能选择跌到某种程度再次进场买入这支股票；第二就是继续上涨，这种情况下他会选择不断‘诅咒’这支股票，直到有一天股价上涨到让他无法忍受，从此由‘黑转粉’。 
时间成本与懒惰：一个人类的时间和精力都是有限的，它无法获取市场中所有股票的信息，每次获取熟悉一支股票的时间成本在他看来也是非常巨大，他反复的盯着自己最频繁买卖的那几支股票。
1. 美股周期短线分析
下面先获取沙盒数据中美股一年的数据，做为短线分析示例：
Step2:  从日振幅涨跌幅比来看，只有BIDU和WUBA能勉强有短线套利的空间（值 > 1.8）, 但是由于沙盒数据中只有这些symbol，所以暂时忽略这个特证，之后做非沙盒数据全市场周期短线分析时再使用这个值。
Step3:  下面先一个一个观察每一个股票的周期涨跌概率，可以发现：
特斯拉在周四上涨的概率最大59%
诺亚财富也在周四上涨的概率最大65%
百度在周五上涨概率达到60%
苹果在周三上涨概率达到56%
Step4:  假如择时策略中需要找到每一个股票上涨概率超过55%的交易日，做为策略买入的日子，比如下面示例找特斯拉超过55%的交易日：
Step5:  可以看到上面的结果就是符号要求的交易日，但是如果虽然周四的胜率很很高，但是周四的上涨比例很低呢，如果上涨比例很低，会造成盈亏比很低，造成最终交易依然亏损，下面使用date_week_mean看看上面各个美股每个交易日的涨跌比例，如下：
Step6:  看看特斯拉满足胜率要求的交易日中的涨跌幅比例，如下：
Step7:  可以看到周四的涨跌平均值是0.54，在具体策略编写中可以使用如下两种阀值计算方式，确定周四的涨幅比例是否高于下面两种算法：
Step8:  可以看到第一种算法的值计算为0.73，第二种为0.45，0.54虽然大于0.45但是小于0.73，即虽然特斯拉在周四有大概率的上涨可能，如果使用第一种算法，那么由于涨幅比例不符合要求，在具体策略中将不会发出买入信号。
备注：
上面的计算中0.618是可以在具体策略中通过参数传递
无论是上面使用的55%胜率还是0.618都是以制造非均衡概率优势为目的
在实际策略编写中根据交易量需求，以及市场交易目标数量等等确定具体使用上面那一种算法, 或两个并行生效
下面看看百度上涨概率超过55%的交易日：
Step9:  看看百度满足胜率要求的交易日中的涨跌幅比例，以及两种阀值计算，如下：
Step16:  结果看到第一种算法的值计算为0.17，第二种为0.28，0.25虽然大于0.17但是小于0.28，即如果策略中使用第一种阀值计算方式将满足买入信号发出，如果第二种就不满足。
2. 日胜率均值回复策略
实盘中使用的symbol数量会远远多于本例中使用沙盒数据的数量，策略可以要求两种阀值都满足，且加入更多的非均衡条件构造最终的非均衡结果，但是由于本例沙盒数据量少，所以下面编写策略时采用两种阀值计算方式满足一种即可，策略大概原理如下：
策略的性质属于：均值回复
默认以40天为周期(8周)结合涨跌阀值计算周几适合买入
回测运行中每一个月重新计算一次上述的周几适合买入
在策略日任务中买入信号为：昨天下跌，今天开盘也下跌，且明天是计算出来的上涨概率大的'周几'
具体策略编写如下所示：
Step17:  3. 各个市场回测日胜率均值回复策略
上面的AbuFactorBuyWD即完成了整个策略的编写，下面开始进行回测，如下所示：
Step18:  可以看到上面的回测中胜率超过了50%，从下面的交易单中可以看到所有交易都只持有了一天，如下：
Step19:  上面的策略中计算'周几'上涨概率最大的交易周期默认为40天周期(8周)，这个周期长度不能太长也不能太短，因为某一个股票上的活跃用户只是在一段短时间内变化不大，但是一个市场中的参与者随着时间的流逝，也在慢慢不断变化，不断新老交替，就像我们人类，每7年我们就是一个全新的自己，所有细胞血液都将完全更新一遍。
下面使用这个策略对比特币，莱特币进行回测，如下所示：
Step20:  下面使用这个沙盒中A股市场symbol进行回测，如下所示：
<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()
from abupy import abu, AbuFactorBuyTD, BuyCallMixin, ABuSymbolPd, ABuKLUtil
from abupy import AbuFactorSellNDay, AbuMetricsBase, ABuProgress
Explanation: ABU量化系统使用文档
<center>
        <img src="./image/abu_logo.png" alt="" style="vertical-align:middle;padding:10px 20px;"><font size="6" color="black"><b>第26节 星期几是这个股票的‘好日子’</b></font>
</center>
作者: 阿布
阿布量化版权所有 未经允许 禁止转载
abu量化系统github地址 (欢迎+star)
本节ipython notebook
本节界面操作教程视频
上一节讲解量化交易中跨市场低频统计套利的示例，本节将示例一个与周期相关的短线择时策略，本节的内容是为《量化交易之路》中的一个小节做的完整策略实例补充。
首先导入本节需要使用的abupy中的模块：
End of explanation
us_choice_symbols = ['usTSLA', 'usNOAH', 'usSFUN', 'usBIDU', 'usAAPL', 'usGOOG', 'usWUBA', 'usVIPS']
kl_dict = {us_symbol[2:]: 
 ABuSymbolPd.make_kl_df(us_symbol, start='2014-07-26', end='2015-07-26') 
 for us_symbol in us_choice_symbols}
Explanation: 很多刚接触交易的人总喜欢把交易看成一种有固定收入的工作，比如他们有自己的规矩，周五一定要把所有股票都卖了，安安心心过周末，周一看情况一切良好再把股票买回来。
还有一些人有着很奇怪的癖好认为周三是他的幸运日，在周三买入他选中的股票，有些人每个月第一个周五发工资，市场就是由这些各种各样的人组成的。
某一个股票上的活跃用户在一段短时间内变化并不大，也就是说这些习惯周五卖周一买的人会反复在一支股票上交易，普通投资者普遍的投资方式是针对一支股票不断的进行买卖，他们不会长期持有这支股票，但也不会远离这支股票很长时间，我认为有两点促成了以上事实。
贪欲：贪欲在这中间起到了很大的作用，当一个人第一次买入一支股票并且持有到有一定利润的时候，他选择卖出这支股票，因为他认为涨的已经很多了，该适当的回调了，之后股价的走势只有两种可能：第一按照他的预期下跌，这样的话他可能选择跌到某种程度再次进场买入这支股票；第二就是继续上涨，这种情况下他会选择不断‘诅咒’这支股票，直到有一天股价上涨到让他无法忍受，从此由‘黑转粉’。 
时间成本与懒惰：一个人类的时间和精力都是有限的，它无法获取市场中所有股票的信息，每次获取熟悉一支股票的时间成本在他看来也是非常巨大，他反复的盯着自己最频繁买卖的那几支股票。
1. 美股周期短线分析
下面先获取沙盒数据中美股一年的数据，做为短线分析示例：
End of explanation
ABuKLUtil.wave_change_rate(kl_dict)
Explanation: 从日振幅涨跌幅比来看，只有BIDU和WUBA能勉强有短线套利的空间（值 > 1.8）, 但是由于沙盒数据中只有这些symbol，所以暂时忽略这个特证，之后做非沙盒数据全市场周期短线分析时再使用这个值。
End of explanation
pd.options.display.precision = 2
pd.options.display.max_columns = 30
ABuKLUtil.date_week_win(kl_dict)
Explanation: 下面先一个一个观察每一个股票的周期涨跌概率，可以发现：
特斯拉在周四上涨的概率最大59%
诺亚财富也在周四上涨的概率最大65%
百度在周五上涨概率达到60%
苹果在周三上涨概率达到56%
End of explanation
tl_dw = ABuKLUtil.date_week_win(kl_dict['TSLA'])
tl_dw_vd = tl_dw[tl_dw.win > 0.55]
tl_dw_vd
Explanation: 假如择时策略中需要找到每一个股票上涨概率超过55%的交易日，做为策略买入的日子，比如下面示例找特斯拉超过55%的交易日：
End of explanation
ABuKLUtil.date_week_mean(kl_dict)
Explanation: 可以看到上面的结果就是符号要求的交易日，但是如果虽然周四的胜率很很高，但是周四的上涨比例很低呢，如果上涨比例很低，会造成盈亏比很低，造成最终交易依然亏损，下面使用date_week_mean看看上面各个美股每个交易日的涨跌比例，如下：
End of explanation
tl_dwm = ABuKLUtil.date_week_mean(kl_dict['TSLA'])
tl_dwm.loc[tl_dw_vd.index]
Explanation: 看看特斯拉满足胜率要求的交易日中的涨跌幅比例，如下：
End of explanation
abs(tl_dwm.sum()).values[0] / 0.618, abs(tl_dwm._p_change).mean() / 0.618
Explanation: 可以看到周四的涨跌平均值是0.54，在具体策略编写中可以使用如下两种阀值计算方式，确定周四的涨幅比例是否高于下面两种算法：
End of explanation
bd_dw = ABuKLUtil.date_week_win(kl_dict['BIDU'])
bd_dw_vd = bd_dw[bd_dw.win > 0.55]
bd_dw_vd
Explanation: 可以看到第一种算法的值计算为0.73，第二种为0.45，0.54虽然大于0.45但是小于0.73，即虽然特斯拉在周四有大概率的上涨可能，如果使用第一种算法，那么由于涨幅比例不符合要求，在具体策略中将不会发出买入信号。
备注：
上面的计算中0.618是可以在具体策略中通过参数传递
无论是上面使用的55%胜率还是0.618都是以制造非均衡概率优势为目的
在实际策略编写中根据交易量需求，以及市场交易目标数量等等确定具体使用上面那一种算法, 或两个并行生效
下面看看百度上涨概率超过55%的交易日：
End of explanation
bd_dwm = ABuKLUtil.date_week_mean(kl_dict['BIDU'])
print(abs(bd_dwm.sum()).values[0] / 0.618, abs(bd_dwm._p_change).mean() / 0.618)
bd_dwm.loc[bd_dw_vd.index]
Explanation: 看看百度满足胜率要求的交易日中的涨跌幅比例，以及两种阀值计算，如下：
End of explanation
class AbuFactorBuyWD(AbuFactorBuyTD, BuyCallMixin):
    def _init_self(self, **kwargs):
        
            kwargs中可选参数：buy_dw:    代表周期胜率阀值，默认0.55即55%
            kwargs中可选参数：buy_dwm:   代表涨幅比例阀值系数，默认0.618
            kwargs中可选参数：dw_period: 代表分析dw，dwm所使用的交易周期，默认40天周期(8周)
        
        self.buy_dw    = kwargs.pop('buy_dw', 0.55)
        self.buy_dwm   = kwargs.pop('buy_dwm', 0.618)
        self.dw_period = kwargs.pop('dw_period', 40)
        
        # combine_kl_pd中包含择时金融时间数据与择时之前一年的金融时间数据, 先取出择时开始之前的周期数据
        last_kl = self.combine_kl_pd.loc[:self.kl_pd.index[0]]
        if last_kl.shape[0] > self.dw_period:
            last_kl = last_kl[-self.dw_period:]
        # 开始计算周几买，_make_buy_date把结果被放在self.buy_date_week序列中
        self._make_buy_date(last_kl)
    def fit_month(self, today):
        月任务，每一个重新取之前一年的金融时间序列数据，重新计算一遍'周几买'
        end_ind = self.combine_kl_pd[self.combine_kl_pd.date == today.date].key.values[0]
        start_ind = end_ind - self.dw_period  if end_ind - self.dw_period  > 0 else 0
        # 根据当前的交易日，切片过去的一年金融时间序列
        last_kl = self.combine_kl_pd.iloc[start_ind:end_ind]
        # 重新计算一遍'周几买'
        self._make_buy_date(last_kl)
    def fit_day(self, today):
        日任务：昨天下跌，今天开盘也下跌，根据今天是周几，在不在序列self.buy_date_week中决定今天买不买
        if self.yesterday.p_change < 0 and today.open < self.yesterday.close \
            and int(today.date_week) in self.buy_date_week:
            # 由于没有用到今天的收盘价格等，可以直接使用buy_today
            return self.buy_today()
        return None
    # noinspection PyProtectedMember
    def _make_buy_date(self, last_kl):
        self.buy_date_week = []
        # 计算周期内，周期的胜率
        last_dw = ABuKLUtil.date_week_win(last_kl)
        # 摘取大于阀值self.buy_dw的'周几'，buy_dw默认0.55
        last_dw_vd = last_dw[last_dw.win >= self.buy_dw]
        
            eg: last_dw_vd
                       0  1   win
            date_week            
            周四         3  5  0.62
            周五         2  6  0.75
        
        if len(last_dw_vd) > 0:
            # 如果胜率有符合要求的，使用周几平均涨幅计算date_week_mean
            last_dwm = ABuKLUtil.date_week_mean(last_kl)
            # 摘取满足胜率的last_dw_vd
            last_dwm_vd = last_dwm.loc[last_dw_vd.index]
            
                eg: last_dwm_vd
                           _p_change
                date_week           
                周四              1.55
                周五              1.12
            
            # 阀值计算方式1
            dwm1 = abs(last_dwm.sum()).values[0] / self.buy_dwm
            # 阀值计算方式2
            dwm2 = abs(last_dwm._p_change).mean() / self.buy_dwm
            # 如果symbol多可以使用&的关系
            dm_effect = (last_dwm_vd._p_change > dwm1) | (last_dwm_vd._p_change > dwm2)
            buy_date_loc = last_dwm_vd[dm_effect].index
            
                eg: buy_date_loc
                Index(['周四', '周五'], dtype='object', name='date_week')
            
            if len(buy_date_loc) > 0:
                # 如果涨跌幅阀值也满足，tolist，eg：['周一', '周二', '周三', '周四', '周五']
                dw_index = last_dw.index.tolist()
                # 如果是一周5个交易日的就是4，如果是比特币等7天交易日的就是6
                max_ind = len(dw_index) - 1
                for bdl in buy_date_loc:
                    sell_ind = dw_index.index(bdl)
                    buy_ind = sell_ind - 1 if sell_ind > 0 else max_ind
                    self.buy_date_week.append(buy_ind)
Explanation: 结果看到第一种算法的值计算为0.17，第二种为0.28，0.25虽然大于0.17但是小于0.28，即如果策略中使用第一种阀值计算方式将满足买入信号发出，如果第二种就不满足。
2. 日胜率均值回复策略
实盘中使用的symbol数量会远远多于本例中使用沙盒数据的数量，策略可以要求两种阀值都满足，且加入更多的非均衡条件构造最终的非均衡结果，但是由于本例沙盒数据量少，所以下面编写策略时采用两种阀值计算方式满足一种即可，策略大概原理如下：
策略的性质属于：均值回复
默认以40天为周期(8周)结合涨跌阀值计算周几适合买入
回测运行中每一个月重新计算一次上述的周几适合买入
在策略日任务中买入信号为：昨天下跌，今天开盘也下跌，且明天是计算出来的上涨概率大的'周几'
具体策略编写如下所示：
End of explanation
# 初始化资金
read_cash = 1000000
# 买入策略AbuFactorBuyWD，参数都使用默认的
buy_factors = [{'class': AbuFactorBuyWD}]
# 卖出策略使用AbuFactorSellNDay，sell_n=1即只持有一天，is_sell_today=True, 持有一天后当天卖出
sell_factors = [{'class': AbuFactorSellNDay, 'sell_n': 1, 'is_sell_today': True}]
def run_loo_back(choice_symbols, start, end):
    abu_result_tuple, _ = abu.run_loop_back(read_cash,
                                           buy_factors,
                                           sell_factors,
                                           start=start,
                                           end=end,
                                           choice_symbols=choice_symbols, n_process_pick=1)
    ABuProgress.clear_output()
    AbuMetricsBase.show_general(*abu_result_tuple, returns_cmp=True, only_info=True)
    return abu_result_tuple
# 开始进行美股沙盒数据回测，沙盒数据中美股只有从13年7月到16年7月的数据，其它市场会多一些
abu_result_tuple = run_loo_back(us_choice_symbols, '2013-07-26', '2016-07-26')
Explanation: 3. 各个市场回测日胜率均值回复策略
上面的AbuFactorBuyWD即完成了整个策略的编写，下面开始进行回测，如下所示：
End of explanation
abu_result_tuple.orders_pd.filter(
    ['symbol', 'buy_date', 'sell_date', 'keep_days', 'profit'])[:7]
Explanation: 可以看到上面的回测中胜率超过了50%，从下面的交易单中可以看到所有交易都只持有了一天，如下：
End of explanation
_ = run_loo_back(['btc', 'ltc'], '2013-07-26', '2017-07-26')
Explanation: 上面的策略中计算'周几'上涨概率最大的交易周期默认为40天周期(8周)，这个周期长度不能太长也不能太短，因为某一个股票上的活跃用户只是在一段短时间内变化不大，但是一个市场中的参与者随着时间的流逝，也在慢慢不断变化，不断新老交替，就像我们人类，每7年我们就是一个全新的自己，所有细胞血液都将完全更新一遍。
下面使用这个策略对比特币，莱特币进行回测，如下所示：
End of explanation
cn_choice_symbols = ['002230', '300104', '300059', '601766', '600085', '600036', '600809', '000002', '002594']
_ = run_loo_back(cn_choice_symbols, '2013-07-26', '2017-07-26')
Explanation: 下面使用这个沙盒中A股市场symbol进行回测，如下所示：
End of explanation
<END_TASK>