作者: 阿布
阿布量化版权所有 未经允许 禁止转载
abu量化系统github地址 (欢迎+star)
上一节讲解的是比特币,莱特币市场的回测,以及使用abupy内置模块对市场进行分析优化策略,提高系统的稳定性,本节主要示例期货市场的回测。
首先导入本节需要使用的abupy中的模块:
In [1]:
# 基础库导入
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()
In [2]:
from abupy import AbuFactorAtrNStop, AbuFactorPreAtrNStop, AbuFactorCloseAtrNStop, AbuFactorBuyBreak
from abupy import abu, EMarketTargetType, AbuMetricsBase, ABuSymbolPd, tl, get_price, ABuMarketDrawing
from abupy import AbuFuturesCn, AbuFuturesGB, ABuProgress
abupy中内置的期货沙盒数据有如下交易品种
V0(PVC) P0(棕榈) M0(豆粕) I0(铁矿石) JD0(鸡蛋) L0(塑料) PP0(PP) FB0(纤维板) BB0(胶合板) Y0(豆油) C0(玉米) A0(豆一) B0(豆二) J0(焦炭) JM0(焦煤) CS0(玉米淀粉) TA0(PTA) OI0(菜油) RS0(菜籽) RM0(菜粕) ZC0(动力煤) WH0(强麦) JR0(粳稻) SR0(白糖) CF0(棉花) RI0(早籼稻) MA0(郑醇) FG0(玻璃) LR0(晚籼稻) SF0(硅铁) SM0(锰硅) FU0(燃油) AL0(沪铝) RU0(橡胶) ZN0(沪锌) CU0(沪铜) AU0(黄金) RB0(螺纹钢) WR0(线材) PB0(沪铅) AG0(白银) BU0(沥青) HC0(热轧卷板) SN0(沪锡) NI0(沪镍)
In [3]:
futures = AbuFuturesCn()
futures.futures_cn_df[:10]
Out[3]:
如上所示PVC,豆粕,鸡蛋,胶合板等都是所做的期货具体商品,比如上面的鸡蛋一行:
In [4]:
ABuSymbolPd.make_kl_df('JD0').tail()
Out[4]:
比如上面看到的2017-07-19鸡蛋收盘价格为4014元/吨,如果你觉着还能涨,那就买入看涨合约,鸡蛋min_unit=5吨/手, 如果买20手,需要保证金账号里最少有多少钱呢?计算如下:
In [5]:
print('商品价值{}, 总数量{}顿鸡蛋, 保证金{}'.format(20 * 5 * 4014, 20 * 5, 20 * 5 * 4014 * 0.08))
如上所示保证金大概3万多块钱可以撬动价值40万的100吨鸡蛋商品,实际上这就是期货市场高风险高收益的根源,本来需要用40万能做的买卖,在期货市场用3万就能做,看似缩小了成本,但是比如你真有40万,你在期货市场不会还只做3万的买卖了,你将变成做400万的买卖,买卖做大了,风险和收益自然也大了。
下面让时间继续来到了2017-07-20日,由于你是买入的看涨,今天收盘价格下跌到3972,那么你今天就赔钱了,一共赔了:100吨 * (4014 - 3972)
In [6]:
(4014 - 3972) * 100
Out[6]:
假设你保证金账号里一共有35000,那么这时:35000 - 4200 = 30800, 还剩30800,现在的价格是3972元/吨,重新计算需要的保证金如下:
In [7]:
20 * 5 * 3972 * 0.08
Out[7]:
需要保证金31776,那么帐户里的钱就不够了,就会被期货公司强行平仓,实际上上面只是举例子,期货公司不会让帐户里的钱不够这种情况出现,帐户里资金不多时候,就会要求你继续追加保证金了。
下面假设帐户里的保证金很充足,时间继续向前,到了2017-07-25,当日的最高价格为4025,如果你真的以最高价格卖出了合约:
In [28]:
(4025 - 4014) * 100
Out[28]:
如上所示将最终赚钱1100块。
上面说的合约是在2017-07-19买的看涨合约期货,假如你在2017-07-19买的是看跌合约,好多人不理解看跌怎么挣钱,实际上看跌合约可理解为你向交易所借钱买入了商品然后马上卖出了,然后你的期望是价格下跌,然后当价格足够低的时候你再买入卖出,这样除了还给交易所之前借的钱之外,你还能获取这两次买卖的差价。
那么比如上面在2017-07-19以4014元/吨买入的是看跌合约,初始保证金和买入看涨合约时是一样的,然后假如你在2017-07-25,以当日的最低价格3930卖出了合约将最终获利8400元,如下所示:
In [30]:
(4014 - 3930) * 100
Out[30]:
再说个极端情况,假如2017-07-25是合约的最后交割日,那么是不是真的能提取100吨鸡蛋现货呢?
在你开户的时候就会让你选择你的账户类型:保值或者投机,但其实只有有资格的认证企业才能选保值,对于个人都只能选投机,投机是没有资格真的在交割日期进行提取现货的,只有企业账户才有资格,所以如果你真的在交割日还持有合约,交易所会强行平仓。
In [6]:
abupy.env.g_market_target = EMarketTargetType.E_MARKET_TARGET_FUTURES_CN
#买入因子,卖出因子等依然使用相同的设置,如下所示:
read_cash = 3000000
# 卖出因子继续使用上一节使用的因子
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}
]
买入因子组合稍微变动,之前使用的都是42, 60天突破,改为使用21,42天突破,上一节在示例讲解比特币市场时演示过通过ABuKLUtil.resample_close_mean计算出比特币市场应该选择的周期在10天上下,期货市场这里的周期选择实际上是因为市场的特点所改变的,因为期货有限定的交割周期,且很多期货产品有着明显的季节性。
In [9]:
# 买入因子依然延用AbuFactorBuyBreak,周期改变为21,42
buy_factors = [{'xd': 21, 'class': AbuFactorBuyBreak},
{'xd': 42, 'class': AbuFactorBuyBreak}]
In [10]:
abupy.beta.atr.g_atr_pos_base = 0.03
abu_result_tuple, kl_pd_manger = abu.run_loop_back(read_cash,
buy_factors,
sell_factors,
n_folds=2,
choice_symbols=None)
AbuMetricsBase.show_general(*abu_result_tuple, only_show_returns=True)
In [3]:
from abupy import AbuFactorBuyXD, BuyPutMixin
class AbuFactorBuyPutXDBK(AbuFactorBuyXD, BuyPutMixin):
"""示例继承AbuFactorBuyXD完成反向突破买入择时类"""
def fit_day(self, today):
"""
针对每一个交易日拟合买入交易策略,寻找向上突破买入机会
:param today: 当前驱动的交易日金融时间序列数据
"""
# 与AbuFactorBuyBreak区别就是买向下突破的,即min()
if today.close == self.xd_kl.close.min():
return self.buy_tomorrow()
return None
# 通过import的方式导入AbuFactorBuyPutBreak,因为在windows系统上,启动并行后,在ipython notebook中定义的类会在子进程中无法找到
from abupy import AbuFactorBuyPutBreak
上AbuFactorBuyPutBreak即是完成了向下突破put策略的代码,最大特点就是因子混入BuyPutMixin,即做为反向策略,看跌。
下面使用21天,42天向下突破看跌策略做为买入因子组合,其它都不变,代码如下所示:
In [13]:
buy_factors = [{'xd': 21, 'class': AbuFactorBuyPutBreak},
{'xd': 42, 'class': AbuFactorBuyPutBreak}]
abu_result_tuple, kl_pd_manger = abu.run_loop_back(read_cash,
buy_factors,
sell_factors,
n_folds=2,
choice_symbols=None)
AbuMetricsBase.show_general(*abu_result_tuple, only_show_returns=True)
下面拿出交易单的一个看看,可以发现expect_direction列值是-1, buy_type_str显示为put,如下所示:
In [14]:
abu_result_tuple.orders_pd.head(1)
Out[14]:
卖出因子在support_direction实现中需要声明自己支持的买入因子类型,且在fit_day中根据不同交易方向做处理,如下AbuFactorPreAtrNStop示例所示:
class AbuFactorPreAtrNStop(AbuFactorSellBase):
"""示例单日最大跌幅n倍atr(止损)风险控制因子"""
def _init_self(self, **kwargs):
"""kwargs中可选参数pre_atr_n: 单日最大跌幅止损的atr倍数"""
self.pre_atr_n = g_default_pre_atr_n
if 'pre_atr_n' in kwargs:
# 设置下跌止损倍数
self.pre_atr_n = kwargs['pre_atr_n']
self.sell_type_extra = '{}:pre_atr={}'.format(self.__class__.__name__, self.pre_atr_n)
def support_direction(self):
"""单日最大跌幅n倍atr(止损)因子支持两个方向"""
return [ESupportDirection.DIRECTION_CAll.value, ESupportDirection.DIRECTION_PUT.value]
def fit_day(self, today, orders):
"""
止损event:今天相比昨天的收益 * 买入时的期望方向 > today.atr21 * pre_atr_n
:param today: 当前驱动的交易日金融时间序列数据
:param orders: 买入择时策略中生成的订单序列
:return:
"""
for order in orders:
if (today.pre_close - today.close) * order.expect_direction > today.atr21 * self.pre_atr_n:
# 只要今天的收盘价格比昨天收盘价格差大于一个差值就止损卖出, 亦可以使用其它计算差值方式
self.sell_tomorrow(order)
上面fit_day中根据order.expect_direction的值对正向,反向买入因子做处理,即:
abupy中内置的几个卖出因子都实现了看涨和看跌两个方向,用户自己使用的卖出因子如果不考虑做期货等市场的情况下,则不需要支持看跌的买入因子。
更多详情自行阅读AbuFactorPreAtrNStop等卖出因子源代码
下面同时使用向上突破看涨call策略和向下突破看跌put策略进行回测,如下所示:
In [15]:
buy_factors = [{'xd': 21, 'class': AbuFactorBuyPutBreak},
{'xd': 42, 'class': AbuFactorBuyPutBreak},
{'xd': 21, 'class': AbuFactorBuyBreak},
{'xd': 42, 'class': AbuFactorBuyBreak}]
abu_result_tuple, kl_pd_manger = abu.run_loop_back(read_cash,
buy_factors,
sell_factors,
n_folds=2,
choice_symbols=None)
AbuMetricsBase.show_general(*abu_result_tuple, only_show_returns=True)
上面的回测结果收益一般,上一节比特币的回测通过分析数据对参数进行优化,提高回测收益,港股回测那一节通过AbuTLine.show_least_valid_poly对策略进行优化,本节将根据期货的特点,编写一个选股策略对交易进行优化。
上面的回测共交易的期货品种有38种,如下所示:
In [16]:
len(set(abu_result_tuple.orders_pd.symbol))
Out[16]:
实际上没有必要涉及这么多的品种,下面根据期货的交易特点编写一个选股策略,选取更合适策略的期货品种。
期货市场可以买涨也可以买跌,本节示例的策略使用向上突破买涨,向下突破买跌的策略,即多空都做,既然使用突破策略且突破策略使用参数为21天,42天这个突破周期对于期货市场来说并不短,那么期望买入的品种可以拥有一定的趋势,且有保持趋势一段时间的习惯,不希望品种的走势总是反复震荡,趋势总是短时间进行回复,并且也不希望走势太平稳,完全没有趋势形成。
下面通过位移路程比来进行选股主策略,位移路程比的计算通过AbuTLine中的show_shift_distance实现,首先定义个lambda函数可视化选股周期的位移路程比sd_line:
In [17]:
sd_line = lambda sym: tl.AbuTLine(
ABuSymbolPd.make_kl_df(sym, start='2014-06-27', end='2015-07-07').close, '').show_shift_distance(
step_x=1.2, show_log=False)
使用sd_line查看商品V0(PVC)在选股周期的位移路程比,如下所示,可以发现位移路程比值基本都在2以下,但也会有2以上的情况
In [18]:
sd_line('V0');
类似上面的V0的走势是符合我们的交易策略,因为不管你上涨还是下跌,只要商品可以惯性的保持一段时间趋势,使用的向上突破和向下突破就都可以找到盈利机会。
下面再看看商品FB0(纤维板)的位移路程比图:
In [19]:
sd_line('FB0');
从图中你可以发现FB0经常在短时间内上涨,然后反弹,趋势无法保持,所以FB0(纤维板)是我们应该过滤的商品,反复反弹就意外着位移路程比值大,你可以发现有多个大于2.0的位移路程比阶段。
再看看下面的Y0(豆油)位移路程比图:
In [108]:
sd_line('Y0');
从图中你可以发现走势太平稳了,没有好的趋势会形成,并不适合使用的突破策略,你可以发现有没有1个移路程比值大于2.0。
ok,下面就根据以上观察结果编写选股策略,代码如下所示:
备注:关于更多选股因子请阅读abu量化文档:第五节 选股策略的开发
In [3]:
from abupy import AbuPickStockBase, ps
class AbuPickStockShiftDistance(AbuPickStockBase):
"""位移路程比选股因子示例类"""
def _init_self(self, **kwargs):
"""通过kwargs设置位移路程比选股条件,配置因子参数"""
self.threshold_sd = kwargs.pop('threshold_sd', 2.0)
self.threshold_max_cnt = kwargs.pop('threshold_max_cnt', 4)
self.threshold_min_cnt = kwargs.pop('threshold_min_cnt', 1)
@ps.reversed_result
def fit_pick(self, kl_pd, target_symbol):
"""开始根据位移路程比边际参数进行选股"""
pick_line = tl.AbuTLine(kl_pd.close, 'shift distance')
shift_distance = pick_line.show_shift_distance(step_x=1.2, show_log=False, show=False)
shift_distance = np.array(shift_distance)
# show_shift_distance返回的参数为四组数据,最后一组是每个时间段的位移路程比值
sd_arr = (shift_distance)[:, -1]
# 大于阀值的进行累加和计算
threshold_cnt = (sd_arr >= self.threshold_sd).sum()
# 边际条件参数开始生效
if threshold_cnt < self.threshold_max_cnt and threshold_cnt >= self.threshold_min_cnt:
return True
return False
def fit_first_choice(self, pick_worker, choice_symbols, *args, **kwargs):
raise NotImplementedError('AbuPickStockShiftDistance fit_first_choice unsupported now!')
# 通过import的方式导入AbuPickStockShiftDistance,因为在windows系统上,启动并行后,在ipython notebook中定义的类会在子进程中无法找到
from abupy import AbuPickStockShiftDistance
下面代码继续同时使用向上突破看涨call策略和向下突破看跌put策略进行回测,唯一的不同是使用选股策略因子AbuPickStockShiftDistance:
In [21]:
stock_pickers = [{'class': AbuPickStockShiftDistance,
'threshold_sd': 2.0, 'threshold_max_cnt': 4, 'threshold_min_cnt': 1,
'reversed': False}]
buy_factors = [{'xd': 21, 'class': AbuFactorBuyPutBreak},
{'xd': 42, 'class': AbuFactorBuyPutBreak},
{'xd': 21, 'class': AbuFactorBuyBreak},
{'xd': 42, 'class': AbuFactorBuyBreak}]
abu_result_tuple, kl_pd_manger = abu.run_loop_back(read_cash,
buy_factors,
sell_factors,
stock_pickers,
n_folds=2,
choice_symbols=None)
ABuProgress.clear_output()
In [22]:
AbuMetricsBase.show_general(*abu_result_tuple, only_show_returns=True)
从上面结果看收益提升了大概7%,虽然不多,但是交易数量从1088下降到601,降低交易频率是最好的优化策略,涉及的交易商品品种也由之前的38个下降到21个, 如下所示:
In [115]:
len(set(abu_result_tuple.orders_pd.symbol))
Out[115]:
In [42]:
gb = AbuFuturesGB()
gb.futures_gb_df.head()
Out[42]:
将目标市场设置为国际期货市场,如下:
In [ ]:
abupy.env.g_market_target = EMarketTargetType.E_MARKET_TARGET_FUTURES_GLOBAL
之后的章节会有国内,国际期货市场进行相关策略的统计套利策略示例,本节继续简单使用向上突破看涨call策略和向下突破看跌put策略进行回测,如下:
In [46]:
buy_factors = [{'xd': 21, 'class': AbuFactorBuyPutBreak},
{'xd': 42, 'class': AbuFactorBuyPutBreak},
{'xd': 21, 'class': AbuFactorBuyBreak},
{'xd': 42, 'class': AbuFactorBuyBreak}]
abu_result_tuple_gb, _ = abu.run_loop_back(read_cash, buy_factors, sell_factors)
ABuProgress.clear_output()
AbuMetricsBase.show_general(*abu_result_tuple_gb, only_show_returns=True)
Out[46]:
小结:
上面通过位移路程比进行选股的策略编写在实现细节上可以有多种变种,比如使用多个时间段的均值和阀值进行比较,针对震荡太过剧烈趋势反复的和走势太过平稳的情况分开阀值进行判断等等,上面的实现主要是为了好理解,而且介于篇幅这里没能再多介绍几个选股因子并行生效处理,在之后的章节会有更加完整详细的示例,请关注公众号的更新提醒
与期货市场类似的是美股期权市场,abupy同样支持美股期权市场的回测分析等操作,但由于暂时没有合适的可对外的数据源提供,所以暂时无示例,后续适配合适的期权数据源后会完善美股期权示例讲解,用户也可以在abupy中接入自己的美股期权数据源,详例请阅读第19节:数据源
abu量化系统文档教程持续更新中,请关注公众号中的更新提醒。
更多关于量化交易相关请阅读《量化交易之路》
更多关于量化交易与机器学习相关请阅读《机器学习之路》
更多关于abu量化系统请关注微信公众号: abu_quant