作者: 阿布
阿布量化版权所有 未经允许 禁止转载
abu量化系统github地址 (欢迎+star)
之前的几节做的全部是ump相关的回测与训练,本节将在第10节:比特币莱特币的回测, 第12节:机器学习与比特币示例, 第14节:量化相关性分析应用的基础上做一个完整的比特币策略示例。
首先导入abupy中本节使用的模块:
In [2]:
# 基础库导入
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
import ipywidgets
%matplotlib inline
import os
import sys
sys.path.insert(0, os.path.abspath('../'))
import abupy
# 使用沙盒数据,目的是和书中一样的数据环境
abupy.env.enable_example_env_ipython()
In [3]:
from abupy import AbuFuturesCn, AbuFuturesGB, ABuSymbolPd, ABuCorrcoef, ECoreCorrType, EMarketDataFetchMode
from abupy import ECoreCorrType, EMarketTargetType, find_similar_with_se, ABuScalerUtil, abu, ABuProgress
from abupy import AbuProgress, AbuMetricsBase, EDataCacheType, ml, AbuFactorSellNDay
In [4]:
fcn = AbuFuturesCn()
fcn.futures_cn_df[(fcn.futures_cn_df['product'] == '黄金') |
(fcn.futures_cn_df['product'] == '白银')]
Out[4]:
接下来从内置期货symbol数据中查到国际期货黄金,白银的code:
In [5]:
fgb = AbuFuturesGB()
fgb.futures_gb_df[(fgb.futures_gb_df['product'] == '伦敦金') | (fgb.futures_gb_df['product'] == '伦敦银') |
(fgb.futures_gb_df['product'] == '纽约黄金') | (fgb.futures_gb_df['product'] == '纽约白银')]
Out[5]:
将上述期货黄金,白银产品和比特币,莱特币一起做交易数据获取,如下:
In [6]:
choice_symbols = ['btc', 'ltc', 'AU0', 'AG0', 'XAU', 'XAG', 'SI', 'GC']
panel = ABuSymbolPd.make_kl_df(choice_symbols, start='2014-03-19', end='2017-07-25',
show_progress=True)
# 转换panel轴方向,即可方便获取所有金融时间数据的某一个列
panel = panel.swapaxes('items', 'minor')
# dropna:因为btc, ltc一周交易7天,别的市场5天,dropna即把周六,周日的都drop了
cg_df = panel['p_change'].dropna()
cg_df.tail()
Out[6]:
只使用正负号相关度计算,如下所示:
备注:更多关于相关性的接口使用请阅读 第14节:量化相关性分析应用
In [7]:
corr_df = ABuCorrcoef.corr_matrix(cg_df, similar_type=ECoreCorrType.E_CORE_TYPE_SIGN)
corr_df.btc.sort_values()[::-1]
Out[7]:
In [8]:
# 关闭沙盒数据
abupy.env.disable_example_env_ipython()
关闭沙盒数据,需要运行下载了第19节中的各个全市场数据,由于hdf5文件解压后非常大,还需要区分python版本,而且python2还分了市场,所以建议使用csv格式的缓存文件。
csv格式美股,A股,港股,币类,期货6年日k数据 密码: gvtr
下面根据下载的数据缓存类型设置缓存类型,如果下载解压的是csv需要勾选use_csv,如果是hdf5不需要勾选:
In [10]:
# 将数据读取模式设置为本地数据模式,即进行全市场回测时最合适的模式,运行效率高,且分类数据更新和交易回测。
abupy.env.g_data_fetch_mode = EMarketDataFetchMode.E_DATA_FETCH_FORCE_LOCAL
def select_store_cache(use_csv):
if use_csv:
abupy.env.g_data_cache_type = EDataCacheType.E_DATA_CACHE_CSV
else:
abupy.env.g_data_cache_type = EDataCacheType.E_DATA_CACHE_HDF5
print(abupy.env.g_data_cache_type)
use_csv = ipywidgets.Checkbox(True)
_ = ipywidgets.interact(select_store_cache, use_csv=use_csv)
下面使用正负号(涨跌)相关计算比特币和a股市场中所有股票的相关性,如下:
In [15]:
abupy.env.g_market_target = EMarketTargetType.E_MARKET_TARGET_CN
similar_a = find_similar_with_se('btc', start='2013-09-01', end='2016-08-08', corr_type=ECoreCorrType.E_CORE_TYPE_SIGN)
将结果使用DataFrame进行包装, 如下:
In [16]:
similar_a_pd = pd.DataFrame(similar_a, columns=['symbol', 'sim'])
similar_a_pd.head()
Out[16]:
首先统计一下A股所有股票与比特币相关性的平均值,可以看到平均结果在0.035左右,则上面期货黄金,白银与比特币的相关度也就大概这个水平,并不高,如下 :
In [17]:
similar_a_pd.sim.mean()
Out[17]:
先用qcut统计一下相关度的平均各个级,如下:
In [19]:
pd.qcut(similar_a_pd.sim, 10).value_counts()
Out[19]:
大概算出bin的阀值,使用cut bins的方式进行统计,如下所示:
In [20]:
pd.cut(similar_a_pd.sim, bins=[-np.inf, -0.03, 0.1, np.inf]).value_counts()
Out[20]:
可以看到A股市场中与比特币正相关的值比较高,所以如下要大概选取100个a股市场中与比特币最相关的只选取正相关的,如下:
In [24]:
similar_a_top = similar_a_pd[(similar_a_pd.sim > 0.088)].iloc[2:]
# 添加个投票方向在下面的示例策略中会使用
similar_a_top['vote_direction'] = np.where(similar_a_top.sim > 0, 1, -1)
print(similar_a_top.shape)
similar_a_top.head()
Out[24]:
下面先构造一个在第12节:机器学习与比特币示例中使用的BtcBigWaveClf对象,如下所示:
In [29]:
# 只取到2016-08-08,保留一年的数据做回测使用
btc = ABuSymbolPd.make_kl_df('btc', start='2013-09-01', end='2016-08-08')
btc_ml = ml.BtcBigWaveClf(btc=btc)
param_grid = {'max_features': ['sqrt', 'log2'], 'n_estimators': np.arange(50, 500, 50)}
btc_ml.random_forest_classifier_best(param_grid=param_grid)
_ = btc_ml.fit()
下面开始写择时策略AbuBTCDayBuy,如下:
In [38]:
from abupy import AbuFactorBuyBase, BuyCallMixin
class AbuBTCDayBuy(AbuFactorBuyBase, BuyCallMixin):
def _init_self(self, **kwargs):
# 市场中与btc最相关的top个股票
self.btc_similar_top = kwargs.pop('btc_similar_top')
# 超过多少个相关股票今天趋势相同就买入
self.btc_vote_val = kwargs.pop('btc_vote_val', 0.60)
def _collect_kl(sim_line):
"""在初始化中将所有相关股票的对应时间的k线数据进行收集"""
start = self.kl_pd.iloc[0].date
end = self.kl_pd.iloc[-1].date
kl = ABuSymbolPd.make_kl_df(sim_line.symbol, start=start, end=end)
self.kl_dict[sim_line.symbol] = kl
self.kl_dict = {}
# k线数据进行收集到类字典对象self.kl_dict中
self.btc_similar_top.apply(_collect_kl, axis=1)
def fit_day(self, today):
"""
:param today: 当前驱动的交易日金融时间序列数据
:return:
"""
# 忽略不符合买入的天(统计周期内前两天, 因为btc的机器学习特证需要三天交易数据)
if self.today_ind < 2:
return None
# 今天,昨天,前天三天的交易数据进行特证转换
btc = self.kl_pd[self.today_ind - 2:self.today_ind + 1]
# 三天的交易数据进行转换后得到btc_today_x
btc_today_x = self.make_btc_today(btc)
# btc_ml并没有在这里传入,实际如果要使用,需要对外部的btc_ml进行本地序列化后,构造读取本地
# 买入条件2: 使用在第12节:机器学习与比特币示例中编写的:信号发出今天比特币会有大行情
if btc_ml.predict(btc_today_x):
# 买入条件1: 当日这100个股票60%以上都是上涨的
vote_val = self.similar_predict(today.date)
if vote_val > self.btc_vote_val:
# 没有使用当天交易日的close等数据,且btc_ml判断的大波动是当日,所以当日买入
return self.buy_today()
def make_btc_today(self, sib_btc):
"""构造比特币三天数据特证"""
sib_btc['big_wave'] = (sib_btc.high - sib_btc.low) / sib_btc.pre_close > 0.55
sib_btc['big_wave'] = sib_btc['big_wave'].astype(int)
sib_btc_scale = ABuScalerUtil.scaler_std(
sib_btc.filter(['open', 'close', 'high', 'low', 'volume', 'pre_close',
'ma5', 'ma10', 'ma21', 'ma60', 'atr21', 'atr14']))
# 把标准化后的和big_wave,date_week连接起来
sib_btc_scale = pd.concat([sib_btc['big_wave'], sib_btc_scale, sib_btc['date_week']], axis=1)
# 抽取第一天,第二天的大多数特征分别改名字以one,two为特征前缀,如:one_open,one_close,two_ma5,two_high.....
a0 = sib_btc_scale.iloc[0].filter(['open', 'close', 'high', 'low', 'volume', 'pre_close',
'ma5', 'ma10', 'ma21', 'ma60', 'atr21', 'atr14', 'date_week'])
a0.rename(index={'open': 'one_open', 'close': 'one_close', 'high': 'one_high', 'low': 'one_low',
'volume': 'one_volume', 'pre_close': 'one_pre_close',
'ma5': 'one_ma5', 'ma10': 'one_ma10', 'ma21': 'one_ma21',
'ma60': 'one_ma60', 'atr21': 'one_atr21', 'atr14': 'one_atr14',
'date_week': 'one_date_week'}, inplace=True)
a1 = sib_btc_scale.iloc[1].filter(['open', 'close', 'high', 'low', 'volume', 'pre_close',
'ma5', 'ma10', 'ma21', 'ma60', 'atr21', 'atr14', 'date_week'])
a1.rename(index={'open': 'two_open', 'close': 'two_close', 'high': 'two_high', 'low': 'two_low',
'volume': 'two_volume', 'pre_close': 'two_pre_close',
'ma5': 'two_ma5', 'ma10': 'two_ma10', 'ma21': 'two_ma21',
'ma60': 'two_ma60', 'atr21': 'two_atr21', 'atr14': 'two_atr14',
'date_week': 'two_date_week'}, inplace=True)
# 第三天的特征只使用'open', 'low', 'pre_close', 'date_week',该名前缀today,如today_open,today_date_week
a2 = sib_btc_scale.iloc[2].filter(['big_wave', 'open', 'low', 'pre_close', 'date_week'])
a2.rename(index={'open': 'today_open', 'low': 'today_low',
'pre_close': 'today_pre_close',
'date_week': 'today_date_week'}, inplace=True)
# 将抽取改名字后的特征连接起来组合成为一条新数据,即3天的交易数据特征->1条新的数据
btc_today = pd.DataFrame(pd.concat([a0, a1, a2], axis=0)).T
# 开始将周几进行离散处理
dummies_week_col = btc_ml.df.filter(regex='(^one_date_week_|^two_date_week_|^today_date_week_)').columns
dummies_week_df = pd.DataFrame(np.zeros((1, len(dummies_week_col))), columns=dummies_week_col)
# 手动修改每一天的one hot
one_day_key = 'one_date_week_{}'.format(btc_today.one_date_week.values[0])
dummies_week_df[one_day_key] = 1
two_day_key = 'two_date_week_{}'.format(btc_today.two_date_week.values[0])
dummies_week_df[two_day_key] = 1
today_day_key = 'today_date_week_{}'.format(btc_today.today_date_week.values[0])
dummies_week_df[today_day_key] = 1
btc_today.drop(['one_date_week', 'two_date_week', 'today_date_week'], inplace=True, axis=1)
btc_today = pd.concat([btc_today, dummies_week_df], axis=1)
return btc_today.as_matrix()[:, 1:]
def similar_predict(self, today_date):
"""与比特币在市场中最相关的top100个股票已各自今天的涨跌结果进行投票"""
def _predict_vote(sim_line, _today_date):
kl = self.kl_dict[sim_line.symbol]
if kl is None:
return -1 * sim_line.vote_direction > 0
kl_today = kl[kl.date == _today_date]
if kl_today is None or kl_today.empty:
return -1 * sim_line.vote_direction > 0
# 需要 * sim_line.vote_direction,因为负相关的存在
return kl_today.p_change.values[0] * sim_line.vote_direction > 0
vote_result = self.btc_similar_top.apply(_predict_vote, axis=1, args={today_date, })
# 将所有投票结果进行统计,得到与比特币最相关的这top100个股票的今天投票结果
vote_val = 1 - vote_result.value_counts()[False] / vote_result.value_counts().sum()
return vote_val
上面编写的AbuBTCDayBuy即完成了在预测今天比特币有大行情,且今天与比特币最相关的市场是涨势的择时策略:
下面构造买入因子和卖出因子,买入因子构造AbuBTCDayBuy使用similar_a_top,即a股最相关的top100个做为参数传入,卖出因子使用AbuFactorSellNDay其为简单卖出策略,买入后持有sell_n天后不管结果如何就卖出,下面的参数sell_n=1, 即买入后第二天就卖出,如下:
In [39]:
buy_factors = [{'btc_similar_top':similar_a_top,
'class': AbuBTCDayBuy}]
sell_factors = [{'class': AbuFactorSellNDay, 'sell_n': 1}]
# 设置市场类型为币类
abupy.env.g_market_target = EMarketTargetType.E_MARKET_TARGET_TC
#买入因子,卖出因子等依然使用相同的设置,如下所示:
read_cash = 1000000
abupy.beta.atr.g_atr_pos_base = 0.5
下面开始使用2016-08-09至2017-08-08做为回测时间段,如下:
In [40]:
abu_result_tuple, kl_pd_manger = abu.run_loop_back(read_cash,
buy_factors,
sell_factors,
start='2016-08-09',
end='2017-08-08',
choice_symbols=['btc'], n_process_pick=1)
AbuMetricsBase.show_general(*abu_result_tuple, returns_cmp=True)
Out[40]:
In [41]:
abupy.env.g_market_target = EMarketTargetType.E_MARKET_TARGET_US
similar_us = find_similar_with_se('btc', start='2013-09-01', end='2016-08-08', corr_type=ECoreCorrType.E_CORE_TYPE_SIGN)
similar_us_pd = pd.DataFrame(similar_us, columns=['symbol', 'sim'])
similar_us_pd.head()
Out[41]:
使用qcut可以明显看到和A股市场不同,美股市场中存在一定数量与比特币负相关值比较高的symbol:
In [45]:
pd.qcut(similar_us_pd.sim, 10).value_counts()
Out[45]:
同样再使用cut找到正负相关性最高的top100,与a股市场不同,美股市场同时使用了正相关和负相关,如下:
In [46]:
pd.cut(similar_us_pd.sim, bins=[-np.inf, -0.072, 0.072, np.inf]).value_counts()
Out[46]:
从下面可以看到vote_direction的值根据相关性的正负设定了方向,在AbuBTCDayBuy策略中会根据这个方向做投票方向统计:
In [50]:
sim_us_top = similar_us_pd[(similar_us_pd.sim > 0.071) | (similar_us_pd.sim < -0.070)].iloc[2:]
sim_us_top['vote_direction'] = np.where(sim_us_top.sim > 0, 1, -1)
pd.options.display.max_rows = 6
sim_us_top
Out[50]:
与a股市场类似,下面使用AbuBTCDayBuy进行回测,不同点是使用美股市场的top100做为相关参数,如下:
In [44]:
# 设置市场类型为港股
abupy.env.g_market_target = EMarketTargetType.E_MARKET_TARGET_TC
buy_factors = [{'btc_similar_top': sim_us_top, 'btc_vote_val': 0.55, 'class': AbuBTCDayBuy}]
abu_result_tuple, kl_pd_manger = abu.run_loop_back(read_cash,
buy_factors,
sell_factors,
start='2016-08-09',
end='2017-08-08',
choice_symbols=['btc'], n_process_pick=1)
AbuMetricsBase.show_general(*abu_result_tuple, returns_cmp=True)
Out[44]:
上面结果可以看到胜率达到80%,但是成交的数量并不多,在实盘中可以并行多个小策略进行择时,本节使用的数据还是日线级别的数据,所以策略的设计受到很多限制,盈利的能力也有限,在之后的章节将使用分钟级别的时间,策略会不断升级,将比特币这个策略进行不断完善优化,敬请关注公众号的代码以及教程更新提醒。
abu量化系统文档教程持续更新中,请关注公众号中的更新提醒。
更多关于量化交易相关请阅读《量化交易之路》
更多关于量化交易与机器学习相关请阅读《机器学习之路》
更多关于abu量化系统请关注微信公众号: abu_quant