# 基础库导入

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 AbuFactorAtrNStop, AbuFactorPreAtrNStop, AbuFactorCloseAtrNStop, AbuFactorBuyBreak, ABuProgress
from abupy import abu, EMarketTargetType, AbuMetricsBase, ABuSymbolPd, tl, get_price, ABuMarketDrawing, ABuKLUtil

"""
Explanation: ABU量化系统使用文档
<center>
        <img src="./image/abu_logo.png" alt="" style="vertical-align:middle;padding:10px 20px;"><font size="6" color="black"><b>第10节 比特币, 莱特币的回测</b></font>
</center>

作者: 阿布
阿布量化版权所有 未经允许 禁止转载
abu量化系统github地址 (欢迎+star)
本节ipython notebook
上一节讲解的是港股市场的回测，以及使用AbuTLine.show_least_valid_poly优化策略，提高系统的稳定性，本节主要示例比特币与莱特币的走势分析与回测。
首先导入需要使用的abupy中的模块：
End of explanation
"""


# btc是比特币symbol代号
btc = ABuSymbolPd.make_kl_df('btc', start='2013-09-01', end='2017-07-26')
# ltc是莱特币symbol代号
ltc = ABuSymbolPd.make_kl_df('ltc', start='2014-03-19', end='2017-07-26')
btc.tail(7)

"""
Explanation: 1. 比特币, 莱特币的走势数据分析
abupy内置沙盒数据中：

比特币的数据是从2013-09-01至2017-07-26
莱特币的数据是从2014-03-19至2017-07-26

很多人说做币类市场更容易，因为整个市场就两个能做的票，比特币，莱特币，但是真的是这样吗？
量化策略失败结果的人工分析，是对策略结果影响非常大的一个环节，但是在失败结果分析前，对交易目标的历史数据进行
分析也是对策略结果影响非常大的一个环节，通过观察交易目标，分析价格走势，趋势的分布，策略的适配度，以致生成定制针对交易目标的特定策略都是在这个环节中涉及的，由于本文只是abupy使用文档，所以不涉及与交易牵扯过深的知识，本节只示例一些简单的数据分析以及可视化分析技巧。
首先使用ABuSymbolPd.make_kl_df接口将btc和ltc沙盒中的数据请求到对象btc，ltc中：
备注：下面使用btc.tail(7)可以看到交易日是连续的，因为比特币和莱特币一年365天都可交易
End of explanation
"""


ABuMarketDrawing.plot_simple_two_stock({'btc': btc, 'ltc': ltc})

"""
Explanation: 下面通过ABuMarketDrawing.plot_simple_two_stock缩放到一个级别上进行走势对比，走势基本相似，ltc的启动要慢btc:
End of explanation
"""


btc365 = btc[-365:]
ltc365 = ltc[-365:]

"""
Explanation: 由于最近一年的走势和之前差别很大，所以单独切割出btc365, ltc365：
End of explanation
"""


ABuKLUtil.date_week_wave({'btc': btc, 'btc365':btc365, 'ltc':ltc, 'ltc365':ltc365})

"""
Explanation: 使用ABuKLUtil.date_week_wave统计交易日震荡幅度可以发现:

不管周几，每一天的比特币的震荡幅度不管是最近一年还是之前的走势都大概在每天5%上下
不管周几，每一天的莱特币的震荡幅度不管是最近一年还是之前的走势都大概在每天6%上下
End of explanation
"""


ABuKLUtil.p_change_stats({'btc': btc, 'btc365': btc365, 'ltc': ltc, 'ltc365': ltc365})

"""
Explanation: 下面统计周期内的上涨均值，下跌均值，以及数量，比值：
使用ABuKLUtil.p_change_stats可以发现:

比特币最近一年日涨跌幅度呈现稳定趋势：(up:2.615->2.264↓, down:-2.422->-2.135↓)
比特币最近一年的大趋势并不是每天的大幅拉升:日平均涨跌比1.080－>1.061↓，而是上涨的交易日远大于下跌的数量：上涨下跌数量比1.183－>1.411↑
莱特币最近一年日涨跌幅度呈现趋势上升：(up:3.275->3.645↑, down:-2.773->--2.421↓)
莱特币最近一年的大趋势是每天的大幅拉升:日平均涨跌比1.181－>1.5051↑，上涨的交易日远大于下跌的数量：上涨下跌数量比0.980－>1.151↑
End of explanation
"""


ABuKLUtil.wave_change_rate({'btc': btc, 'ltc': ltc})

"""
Explanation: 如下ABuKLUtil.wave_change_rate所示比特币和莱特币日振幅涨跌幅比都在2.0以上, 具备日交易进行统计套利的条件：
备注：美股市场在1.8以上认为具有统计套利条件, 另外还有成交量等几个参数需要综合计算，之后的章节会具体讲解
End of explanation
"""


ABuKLUtil.date_week_win({'btc': btc, 'btc365': btc365, 'ltc': ltc, 'ltc365': ltc365})

"""
Explanation: 使用ABuKLUtil.date_week_win查看每天的涨跌概率：

比特币周一周二周五上涨概率都接近60%，周六下跌概率大，且最近一年更是周一到周五每天都有接近60%上涨概率
莱特币上涨概率大于下跌概率最近一年，之前无明显套利模式
End of explanation
"""


ABuKLUtil.date_week_mean({'btc': btc, 'btc365': btc365, 'ltc': ltc, 'ltc365': ltc365})

"""
Explanation: 使用ABuKLUtil.date_week_mean查看每天的带正负的涨跌mean：

莱特币最近一年平均都为正，且最大周三周四有1以上
比特币一直以来的数据都显示周一周二具有安全的套利空间
End of explanation
"""


ABuKLUtil.bcut_change_vc({'btc': btc, 'btc365': btc365, 'ltc': ltc, 'ltc365': ltc365})

"""
Explanation: 下面使用ABuKLUtil.p_change_bcut_vc统计：

比特币和莱特币最频繁区间是(-3, 0], (0, 3]
比特币和莱特币在(-inf, -10]和(10, inf]的分布都有1%以上，莱特币(-inf, -10]：0.0228有2%以上，属于危险交易品种
End of explanation
"""


ABuKLUtil.qcut_change_vc({'btc': btc, 'btc365': btc365, 'ltc': ltc, 'ltc365': ltc365})

"""
Explanation: 上面使用bcut_change_vc无法知道(-inf, -10]和(10, inf]的正无穷与无穷的具体数值，使用qcut_change_vc：

比特币loss10: [-26.895, -3.284] , top10：(4.182, 38.786]
比特币最近一年风险下降：loss10: [-16.273, -2.783], top10：(3.948, 15.22]
莱特币loss10: [-28.48, -4.1]， top10：(4.405, 41.083]
莱特币最近一年继续呈现高风险loss10：[-22.823, -3.229] 高收益top10：(5.0606, 37.505]
End of explanation
"""


def show_tl(tc='btc', show_cnt=365, offset=0, step_x=1.0):
    tc = btc if tc =='btc'else ltc
    show_cnt = int(show_cnt)
    offset = int(offset)
    step_x = float(step_x)
    
    tc_line = tl.AbuTLine(tc[-show_cnt-offset:len(tc) - offset].close, 'tc_line')
    # 可视化技术线拟合曲线及上下拟合通道曲线
    tc_line.show_regress_trend_channel(step_x=step_x)
    # 可视化可视化技术线骨架通道
    tc_line.show_skeleton_channel(step_x=step_x)
    # 可视化技术线比例分割的区域
    tc_line.show_percents()
    # 可视化技术线最优拟合次数
    tc_line.show_best_poly()
show_tl()

"""
Explanation: 上面通过数据的转换分析对比特币，莱特币进行了分析，下面通过可视化对比特币，莱特币进行分析
2 比特币, 莱特币的走势可视化分析
下面封装一个函数使用AbuTLine中的可视化接口分析数据：
备注: 关于AbuTLine中的具体实现以及接口的功能作用请阅读源代码AbuTLine
End of explanation
"""


from ipywidgets import interact

tc_range = ['btc', 'ltc']
show_range = ['180', '360', '720', '1080']
offset_range = ['0', '60', '120', '180', '250', '360', '720']
step_x_range = ['0.8', '1.0', '1.2', '1.5', '1.8', '2.0']
_ = interact(show_tl, tc=tc_range, show_cnt=show_range, offset=offset_range, step_x=step_x_range)

"""
Explanation: 上面的show_tl函数如果想要切换观察周期，需要不断改参数，太麻烦，下面使用ipywidgets的可交互插件进行可视化控制：
End of explanation
"""


# 设置市场类型为港股
abupy.env.g_market_target = EMarketTargetType.E_MARKET_TARGET_TC

#买入因子，卖出因子等依然使用相同的设置，如下所示：
read_cash = 1000000

# 买入因子依然延用向上突破因子
buy_factors = [{'xd': 60, 'class': AbuFactorBuyBreak},
               {'xd': 42, 'class': AbuFactorBuyBreak}]

# 卖出因子继续使用上一节使用的因子
sell_factors = [
    {'stop_loss_n': 1.0, 'stop_win_n': 3.0,
     'class': AbuFactorAtrNStop},
    {'class': AbuFactorPreAtrNStop, 'pre_atr_n': 1.5},
    {'class': AbuFactorCloseAtrNStop, 'close_atr_n': 1.5}
]

"""
Explanation: 通过上面的数据分析和可视化分析，对比特币使用和之前策略相同的参数和策略组合和参数分配其实是不合适的，因为币类市场的振幅实在是太大，而且走势分布混乱，止盈止损的设定也并不清晰，实际上最适合的量化策略是做一些统计套利策略，关于高频统计套利相关策略，会在之后的章节使用比特币，莱特币做为示例。
下面我们本节先不管回测结果如何，先和之前使用的策略一样的情况下进行回测示例。
3. 比特币，莱特币市场的回测
与A股市场，港股类似首先将abupy量化环境设置为E_MARKET_TARGET_TC代表币类市场，代码如下所示：
End of explanation
"""


# 注意这里把atr资金管理的仓位基数设置为0.5，即50%
abupy.beta.atr.g_atr_pos_base = 0.5
abu_result_tuple, kl_pd_manger = abu.run_loop_back(read_cash,
                                                   buy_factors,
                                                   sell_factors,
                                                   start='2013-09-01',
                                                   end='2017-07-26',
                                                   choice_symbols=None)
ABuProgress.clear_output()

AbuMetricsBase.show_general(*abu_result_tuple, only_show_returns=True)

"""
Explanation: 继续使用run_loop_back进行回测，之前示例回测都是使用n_folds参数，下面换一种写法示例，使用start， end做为参数:

start='2013-09-01'
end='2017-07-26'

choice_symbols=None或者使用['btc', 'ltc']都行, 如果使用None则做全市场测试，但是由于币类市场中暂时只有btc和ltc，所以这里传递['btc', 'ltc']和传递None的结果是一致的。
下面通过：
abupy.beta.atr.g_atr_pos_base = 0.5

调整了默认仓位管理的控制参数，仓位管理类默认使用的是AbuAtrPosition, 调整abupy.beta.atr.g_atr_pos_base=0.5的作用可理解为将每一笔交易的买入资金基数设置为初始资金数50%，g_atr_pos_base默认值为0.1，即10%的资金量做为买入基数。
之所以需要调整资金管理的仓位基数是因为回测中的股票池只有两支btc, ltc，为了提高资金利用率，所以需要调整g_atr_pos_base值。
备注：实际上不必特别在意abupy.beta.atr.g_atr_pos_base仓位，根据回测结果中的策略资金利用率比例不断调整就行，而且策略资金利用率比例不仅和回测中使用的股票池的数量有关，和回测中使用的买入策略数量也相关，比如下面的回测虽然把每次买入时的仓位调整的很高了，但是策略资金利用率比例依然不高的原因即是因为使用的买入策略只有两个，如果有多个策略且策略生效频率很高，即使股票池只有一支股票，策略资金利用率也可以很高。
关于仓位管理的更多详情请阅读AbuPositionBase，AbuAtrPosition或者《量化交易之路》中的相关内容
End of explanation
"""


# 卖出因子只使用AbuFactorAtrNStop，且止盈止损参数都设置100
sell_factors = [
    {'stop_loss_n': 100, 'stop_win_n': 100,
     'class': AbuFactorAtrNStop},
    ]
abu_result_tuple, kl_pd_manger = abu.run_loop_back(read_cash,
                                                   buy_factors,
                                                   sell_factors,
                                                   start='2013-09-01',
                                                   end='2017-07-26',
                                                   choice_symbols=None)
ABuProgress.clear_output()

AbuMetricsBase.show_general(*abu_result_tuple, only_show_returns=True)

"""
Explanation: 从收益曲线对比上发现完全输给了基准的收益，虽然策略收益也有: 392%，但是既然做了高风险的产品，没有高的收益是不对的，不要认为这是贪心，俗话说操着卖白粉的心, 赚着卖白菜的钱，就是这种情况。
备注：币类市场使用的基准大盘就是比特币
要想改善突破策略收益最简单的方式就是如下方式：
End of explanation
"""


ABuKLUtil.resample_close_mean(ABuSymbolPd.make_kl_df('usTSLA'))

"""
Explanation: 哈，如上所示，其实这就是自己骗自己，卖出因子只使用AbuFactorAtrNStop，且止盈止损参数都设置100即就是买入后就不卖出了，我倒是相信大多数人亏损的时候可以做到不卖出，将亏损的部分坚持持有，对外声称自己是价值投资者、基本面分析者，认为应该长期持有、长线投资，但稍微有了一点利润后就肯定要着急兑现，盈利了那么多之后还能一支持有的其实很了不起。
交易中应该追求的是让利润尽情的奔跑,让亏损尽快的止损，但大多数人做的都是让亏损尽情地亏损，让利润尽快地兑现。
下面使用正经的方法做策略参数选择，首先买入因子沿用之前的60，42天突破就是很大的问题，币类市场的趋势周期从上面的数据分析看明显要小于这两个值，那么到底选择什么值合适呢，这里可以使用abu量化文档‘第七节 寻找策略最优参数和评分’来进行参数选择，下面单只从突破周期介绍使用另一种方法。
使用abupy中的ABuKLUtil.resample_close_mean函数，首先针对之前章节做回测的tsla进行数据进行resample_close_mean
End of explanation
"""


ABuKLUtil.resample_close_mean({'btc': btc, 'btc365': btc365, 'ltc': ltc, 'ltc365': ltc365})

"""
Explanation: 关于ABuKLUtil.resample_close_mean的作用这里不过多讲解，有兴趣自行阅读源代码，这里实际上只需要知道一点，使用周期突破的策略选择的周期应该是ABuKLUtil.resample_close_mean返回值在0.08左右范围的重采样周期。
观察上面resample_close_mean针对tsla数据的结果60D, 42D都是在0.08左右，所以之前一直使用的突破策略选择60日突破和42日突破都是适合tsla做为策略使用的。（实际从上面可以看出21d，42d，60d，90d，120d其实都可以适应tsla，且基本适应大多数股票交易品种）
下面使用resample_close_mean针对比特币，莱特币数据：
End of explanation
"""


# xd: 10, xd: 12
buy_factors = [{'xd': 10, 'class': AbuFactorBuyBreak},
               {'xd': 12, 'class': AbuFactorBuyBreak}]

# stop_win_n：3.0->7.0
sell_factors = [
    {'stop_loss_n': 1.0, 'stop_win_n': 7.0,
     'class': AbuFactorAtrNStop},
    {'class': AbuFactorPreAtrNStop, 'pre_atr_n': 1.5},
    {'class': AbuFactorCloseAtrNStop, 'close_atr_n': 1.5}
]

abu_result_tuple, kl_pd_manger = abu.run_loop_back(read_cash,
                                                   buy_factors,
                                                   sell_factors,
                                                   start='2013-09-01',
                                                   end='2017-07-26',
                                                   choice_symbols=None)
ABuProgress.clear_output()

AbuMetricsBase.show_general(*abu_result_tuple, only_show_returns=True)

"""
Explanation: 从输出可以看出10d以上就已经不适合比特币和莱特币做为周期参数了：
10D 0.0847  0.0760  0.0958  0.1147

下面的回测使用10d和12d，且修改止盈参数stop_win_n从3.0至7.0：
备注：止盈参数的设置本来就要随着做的品种的风险而定，风险越大的，止盈也必要要提高，否则不管怎么优化其它策略，参数收益都不会高，7.0也只是我随意写的数，读者可尝试使用其它值测试
End of explanation
"""


abu_result_tuple.orders_pd.buy_cnt

"""
Explanation: 上面的回测结果已经可以比肩基准收益，且读者可以发现这个的收益比上面那个一直持有不卖出的：
'stop_loss_n': 100, 'stop_win_n': 100

收益还要好很多，而且更重要的是，采取了多种规避风险策略，止损参数依然使用1.0：
'stop_loss_n': 1.0, 'stop_win_n': 7.0,

依然使用风险控制止损策略AbuFactorPreAtrNStop，且参数依然使用1.5
{'class': AbuFactorPreAtrNStop, 'pre_atr_n': 1.5}

依然使用风险控制止损策略AbuFactorPreAtrNStop，且参数依然使用1.5
依然使用利润保护止盈策略AbuFactorCloseAtrNStop，且参数依然使用1.5
{'class': AbuFactorCloseAtrNStop, 'close_atr_n': 1.5}

另一点关于比特币，莱特币市场还有一点特殊即是买入数量非整数，精确到小数点后三位，最少交易数量为0.01个币，如下显示交易单的buy_cnt所示：
End of explanation
"""


