量化系统一般分为回测模块、实盘模块。 - 回测模块:首先交易者编写实现一个交易策略,它基于一段历史的交易数据,根据交易策略进行模拟买入卖出,策略中可以涉及买入规则、卖出规则、选股规则、仓位控制及滑点策略等等,回测的目的是验证交易策略是否可行。
- 实盘模块:将回测通过的策略应用于每天的实时交易数据,根据策略发出买入信号、卖出信号,进行实际的买入、卖出操作。
回测模块最重要的组成部份是择时、选股: 只有在对的时间买入对的股票才能获利,就像下面张小娴的名言一样,可以把‘股票’ 代替 ‘人’完全合乎逻辑。 在对的时间,遇见对的人(股票),是一种幸福 在对的时间,遇见错的人(股票),是一种悲伤 在错的时间,遇见对的人(股票),是一声叹息 在错的时间,遇见错的人(股票),是一种无奈
本节首先讲解择时(什么时候投资), 后面的小节将讲解选股 1. 买入择时因子的编写海龟交易法则是量化经典书籍中的经典作品,它里面介绍过一种趋势跟踪策略:N日趋势突破策略 趋势突破定义为当天收盘价格超过N天内的最高价或最低价,超过最高价格作为买入信号买入股票持有,超过最低价格作为卖出信号。 下面将用abupy来实现海龟交易法则作为一个买入因子的实现代码,向经典致敬: - class AbuFactorBuyBreak(AbuFactorBuyXD, BuyCallMixin):
- """示例继承AbuFactorBuyXD完成正向突破买入择时类, 混入BuyCallMixin,即向上突破触发买入event"""
- def fit_day(self, today):
- """
- 针对每一个交易日拟合买入交易策略,寻找向上突破买入机会
- :param today: 当前驱动的交易日金融时间序列数据
- :return:
- """
- # 今天的收盘价格达到xd天内最高价格则符合买入条件
- if today.close == self.xd_kl.close.max():
- # 生成买入订单, 由于使用了今天的收盘价格做为策略信号判断,所以信号发出后,只能明天买
- return self.buy_tomorrow()
- return None
复制代码上AbuFactorBuyBreak即是完成了海龟突破策略的代码实现: - 买入因子需要继承AbuFactorBuyXD或者更复杂的策略继承AbuFactorBuyBase
- 买入因子混入BuyCallMixin,即做为正向策略,股票相关的策略全部是正向策略,即买涨,后续章节示例期货,期权会使用BuyPutMixin
- 买入因子需要实现fit_day,即每一个交易日如何执行交易策略,当符合买入条件后,使用buy_tomorrow或者buy_today生成订单
更多买入因子实现代码请阅读AbuFactorBuyBase 2. 分解模式一步一步对策略进行回测本节首先通过分解流程方式一步一步实现使用AbuFactorBuyBreak进行回测,目的是为了更清晰的说明内部操作流程,
编码过程会显的有些复杂臃肿,但实际上在编写完成一个策略后只需要使用一行代码即可以完成回测,在后面的小节中会进行讲解。 通过字典形式初始化买入buy_factors,首先实现针对一支股票的择时操作: - benchmark的意义为基准参考,基准默认使用回测股票对应市场的大盘指数
- 默认参数下回测过去两年的交易数据,传递AbuBenchmark(n_folds=2)参数修改回测周期
- AbuCapital为资金主类,参数需要初始资金设定,这里初始设定1000000(100万),另一个参数为刚刚介绍过的benchmark(基准参考)对象
- buy_factors由两个买入因子组成,进行择时的时候两个因子同时并行生效
- # buy_factors 60日向上突破,42日向上突破两个因子
- buy_factors = [{'xd': 60, 'class': AbuFactorBuyBreak},
- {'xd': 42, 'class': AbuFactorBuyBreak}]
- benchmark = AbuBenchmark()
- capital = AbuCapital(1000000, benchmark)
复制代码择时ABuPickTimeExecute主要驱动方式为时间驱动,即通过时间序列一天一天递进,通过买入因子卖出因子的fit来查询是否有事件生成(买入卖出行为),另外也有框架使用事件驱动,它们分别有各自的优点,原始的abu框架就是时间驱动+事件驱动的,它最大的优点是执行效率比时间驱动高,但是灵活性及扩展性要比时间驱动差。 下面使用ABuPickTimeExecute开始进行择时交易回测,ABuPickTimeExecute实际上不是最简洁的回测接口,更简单的接口可以使用abu.run_loop_back()函数,在后面的章节将会示例使用,本节目的是为了更清晰的说明内部操作流程。 由回测结果图可看出由于AbuPickTimeWorker没有设置sell_factors,所以所有的交易单子都一直保留没有卖出: - orders_pd:所有交易的相关数据(之后会有内容展示)
- action_pd:所有交易的行为数据(之后会有内容展示)
- orders_pd, action_pd, _ = ABuPickTimeExecute.do_symbols_with_same_factors(['usTSLA'],
- benchmark,
- buy_factors,
- None,
- capital, show=True)
复制代码
3. 卖出择时因子的实现上面所有单子都没有成交的原因是没有卖出因子,下面首先实现类似买入策略的N日趋势突破策略AbuFactorSellBreak,当股价向下突破N日最低价格时卖出股票,即当天收盘价格低于N天内最低价格作为卖出信号,认为下跌趋势成立卖出股票: - class AbuFactorSellBreak(AbuFactorSellXD):
- """示例继承AbuFactorBuyXD, 向下突破卖出择时因子"""
- def support_direction(self):
- """支持的方向,只支持正向"""
- return [ESupportDirection.DIRECTION_CAll.value]
- def fit_day(self, today, orders):
- """
- 寻找向下突破作为策略卖出驱动event
- :param today: 当前驱动的交易日金融时间序列数据
- :param orders: 买入择时策略中生成的订单序列
- """
- # 今天的收盘价格达到xd天内最低价格则符合条件
- if today.close == self.xd_kl.close.min():
- for order in orders:
- self.sell_tomorrow(order)
复制代码上AbuFactorSellBreak即是完成了卖出突破策略的代码实现: - 卖出因子需要继承AbuFactorSellXD或者更复杂的策略继承AbuFactorSellBase
- 卖出因子需要实现support_direction方法,确定策略支持的买入策略方向,本例中[ESupportDirection.DIRECTION_CAll.value]即只支持正向买入策略,即买涨
- 卖出因子需要实现fit_day,看有没有符合卖出条件的交易单子
更多具体卖出因子实现代码请阅读AbuFactorSellBase 备注:之后章节的期货示例讲讲解如何使用ESupportDirection做反向交易,buy put 3.2 买入因子和卖出因子在回测中同时生效同理使用字典组装卖出因子: - # 使用120天向下突破为卖出信号
- sell_factor1 = {'xd': 120, 'class': AbuFactorSellBreak}
- # buy_factors 60日向上突破,42日向上突破两个因子
- buy_factors = [{'xd': 60, 'class': AbuFactorBuyBreak},
- {'xd': 42, 'class': AbuFactorBuyBreak}]
- # 只使用120天向下突破为卖出因子
- sell_factors = [sell_factor1]
- capital = AbuCapital(1000000, benchmark)
- orders_pd, action_pd, _ = ABuPickTimeExecute.do_symbols_with_same_factors(['usTSLA'],
- benchmark,
- buy_factors,
- sell_factors,
- capital, show=True)
复制代码
从上图可以看到,大多数的交易卖出因子都生效了,但效果很不好, 下一节将继续通过增加多个卖出因子同时作用于策略上来提高策略的效果。 |