|
|
|
|
移动端

2.3.2 继承和多态

《量化交易之路:用Python做股票量化分析》第2章量化语言——Python,第2部分(第2~6章)主要讲解了量化交易需要的基础知识及相关工具,如Python语言、NumPy、pandas、数据可视化及量化数学等知识,适合完全没有任何编程经验的读者从头开始阅读。本节为大家介绍继承和多态。

作者:阿布来源:机械工业出版社|2017-10-19 16:29

技术沙龙 | 6月30日与多位专家探讨技术高速发展下如何应对运维新挑战!


2.3.2  继承和多态

逆势、短线和重仓是交易失败的三大原因。

封装、继承和多态是面向对象的三大特点。

以下代码通过实现一个最简单量化交易系统来讲解继承与多态。

以下编写的交易策略与回测系统只是为了学习Python基础为目的,在“第8章量化系统——开发”中将详细讲解abu量化交易回测系统的具体开发流程;

本章所有代码的实现前提是不使用NumPy、pandas等封装库,本章的很多问题在使用上述库后解决方案将变得十分简单。

Python中通过ABC模块实现接口或抽象类,并且通过执行类型检查来确保子类实现了某些特定的方法。下面编写一个量化交易策略基类,代码如下:

  1. import six  
  2. from abc import ABCMeta, abstractmethod  
  3. class TradeStrategyBase(six.with_metaclass(ABCMeta, object)):  
  4.     """  
  5.         交易策略抽象基类  
  6.     """  
  7.     @abstractmethod  
  8.     def buy_strategy(self, *args, **kwargs):  
  9.         # 买入策略基类  
  10.         pass  
  11.     @abstractmethod  
  12.     def sell_strategy(self, *args, **kwargs):  
  13.         # 卖出策略基类  
  14.         pass 

TradeStrategyBase类通过继承ABCMeta,@abstractmethod声明方法为接口。@xxx这种写法在Python中称为装饰器。装饰器是在Python闭包技术基础上再次底层封装的技术,是建立在Python里一切皆为对象的根本上。多个装饰器修饰一个方法时,需要注意装饰器的顺序。

def buy_strategy(self, *args, **kwargs):中*args、**kwargs代表可接受任意数量参数的函数。为了能让一个函数接受任意数量的位置参数,可以使用一个*参数,它的数据结构类型为list列表。为了接受任意数量的关键字参数,使用一个以**开头的参数,它的数据结构类型为dict字典。

下面编写具体量化策略TradeStrategy1,继承TradeStrategyBase实现buy_strategy()与sell_strategy()接口。它的交易策略为:当股价上涨一个阀值(默认7%)时买入股票并持有s_keep_stock_threshold天,代码如下:

  1. class TradeStrategy1(TradeStrategyBase):  
  2.     """  
  3.         交易策略1: 追涨策略,当股价上涨一个阀值默认为7%时  
  4.         买入股票并持有s_keep_stock_threshold(20)天  
  5.     """  
  6.     s_keep_stock_threshold = 20 
  7.     def __init__(self):  
  8.         self.keep_stock_day = 0 
  9.         # 7%上涨幅度作为买入策略阀值  
  10.         self.__buy_change_threshold = 0.07  
  11.     def buy_strategy(self, trade_ind, trade_day, trade_days):  
  12.         if self.keep_stock_day == 0 and \  
  13.                         trade_day.change > self.__buy_change_threshold:  
  14.             # 当没有持有股票的时候self.keep_stock_day == 0 并且  
  15.             # 符合买入条件上涨一个阀值,买入  
  16.             self.keep_stock_day += 1  
  17.         elif self.keep_stock_day > 0:  
  18.             # self.keep_stock_day > 0代表持有股票,持有股票天数递增  
  19.             self.keep_stock_day += 1  
  20.     def sell_strategy(self, trade_ind, trade_day, trade_days):  
  21.         if self.keep_stock_day >= \  
  22.                 TradeStrategy1.s_keep_stock_threshold:  
  23.             # 当持有股票天数超过阀值s_keep_stock_threshold,卖出股票  
  24.             self.keep_stock_day = 0 
  25.     """  
  26.         property属性稍后会讲到  
  27.     """  
  28.     @property  
  29.     def buy_change_threshold(self):  
  30.         return self.__buy_change_threshold  
  31.     @buy_change_threshold.setter  
  32.     def buy_change_threshold(self, buy_change_threshold):  
  33.         if not isinstance(buy_change_threshold, float):  
  34.             """  
  35.                 上涨阀值需要为float类型  
  36.             """  
  37.             raise TypeError('buy_change_threshold must be float!')  
  38.         # 上涨阀值只取小数点后两位  
  39.         self.__buy_change_threshold = round(buy_change_threshold, 2) 

继续编写代码,实现一个交易回测系统,代码如下:

  1. class TradeLoopBack(object):  
  2.     """  
  3.         交易回测系统  
  4.     """  
  5.     def __init__(self, trade_days, trade_strategy):  
  6.         """  
  7.         使用前面封装的StockTradeDays类和本节编写的交易策略类  
  8.         TradeStrategyBase类初始化交易系统  
  9.         :param trade_days: StockTradeDays交易数据序列  
  10.         :param trade_strategy: TradeStrategyBase交易策略  
  11.         """  
  12.         self.trade_days = trade_days  
  13.         self.trade_strategy = trade_strategy  
  14.         # 交易盈亏结果序列  
  15.         self.profit_array = []  
  16.     def execute_trade(self):  
  17.         """  
  18.         执行交易回测  
  19.         :return:  
  20.         """  
  21.         for ind, day in enumerate(self.trade_days):  
  22.             """  
  23.                 以时间驱动,完成交易回测  
  24.             """  
  25.             if self.trade_strategy.keep_stock_day > 0:  
  26.                 # 如果有持有股票,加入交易盈亏结果序列  
  27.                 self.profit_array.append(day.change)  
  28.             # hasattr: 用来查询对象有没有实现某个方法  
  29.             if hasattr(self.trade_strategy, 'buy_strategy'):  
  30.                 # 买入策略执行  
  31.                 self.trade_strategy.buy_strategy(ind, day,  
  32.                                                  self.trade_days)  
  33.                   
  34.             if hasattr(self.trade_strategy, 'sell_strategy'):  
  35.                 # 卖出策略执行  
  36.                 self.trade_strategy.sell_strategy(ind, day,  
  37.                                                   self.trade_days) 

接下来使用前面获取的TSLA的504天真实交易数据构造的StockTradeDays类对象trade_days和TradeStrategy1类,来实例化回测,并使用execute_trade()函数执行回测,代码如下:

  1. trade_loop_back = TradeLoopBack(trade_days, TradeStrategy1())  
  2. trade_loop_back.execute_trade()  
  3. print '回测策略1 总盈亏为:{}%'.format(  
  4.     reduce(lambda a, b: a + b, trade_loop_back.profit_array) * 100) 

输出如下:

  1. 回测策略1 总盈亏为:37.6% 

上面通过回测,reduce()交易盈亏结果序列显示策略最终盈利37.6%,但是这个结果很不直观。下面通过可视化技术来直观感受一下这个策略交易盈亏结果序列,结果如图2-2所示。

备注:读者不用理解下面的代码绘制流程,接下来的NumPy、pandas等几乎所有章节中都离不开数据可视化,本章的重点是Python基础。

  1. # 图2-2 所示  
  2. plt.plot(np.array(trade_loop_back.profit_array).cumsum()) 

输出结果如图2-2所示。

喜欢的朋友可以添加我们的微信账号:

51CTO读书频道二维码


51CTO读书频道活动讨论群:365934973

【责任编辑:book TEL:(010)68476606】

回书目   上一节   下一节
点赞 0
分享:
大家都在看
猜你喜欢

读 书 +更多

JAVA并发编程实践

本书既能够成为读者的理论支持,又可以作为构建可靠的、可伸缩的、可维护的并发程序的技术支持。本书并不仅仅提供并发API的清单及其机制,...

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊