交易知识就在 ——ALPHA ZONE-HOME ,由自营交易室机构交易员主导,理论结合实践,助力金融知识变现!
回测是将交易策略构想应用于历史数据,以确定过去其表现的研究过程。然而,回测器不能保证该策略的未来表现。但是,它们是策略研究过程的重要组成部分,以在将策略投入生产之前将其过滤掉。
在本文中,将概述使用Python编写的面向对象的基础回测器。这个早期的系统将主要是“教学辅助工具”,用于演示回测器的不同组件。随着文章的逐渐深入,将探索其更复杂的功能。
回测概述
设计强大的回测器的过程非常困难。有效地模拟影响算法交易系统性能的所有组件是非常具有挑战性的事情。不良的数据粒度,经纪商发送订单的不透明性,订单等待时间以及无数其他因素共同导致策略的“真实”性能与回测的性能不同。
在开发回测器时,很容易想不断“从头开始重写”,因为发现更多因素对于评估性能至关重要。在开发过程中必须在某个时间点做出判断,即系统已经捕获了足够的因素,没有回测器可以完成这件事。
考虑到这些问题,此处介绍的回测器将有些简化。随着我们探索更多问题(投资组合优化,风险管理,交易成本处理),回测器将变得更加强大。
回测系统的类型
通常有两种类型的回测器将是您感兴趣的。第一种是基于研究的,主要用于早期阶段,在此阶段将测试许多策略,以选择经过严格评估的策略。这些研究回测器通常用Python,R或MatLab编写,因为在此阶段,开发速度比执行速度更为重要。
第二种回测器是基于事件的。也就是说,它在类似于交易执行系统本身的执行循环中执行回测过程。它将对市场数据和订单执行过程建模,以便对策略进行更严格的评估。
后者的系统通常是用高性能语言(例如C ++或Java)编写的,在这些语言中,执行速度至关重要。对于使用频率较低的策略(尽管仍在盘中),使用Python绰绰有余(在此文中)。
Python中的面向对象研究回测器
现在将讨论基于对象和研究的回测环境的设计和实现。出于以下原因,面向对象被选作为软件设计范例:
· 可以预先指定使用每个组件的接口,而随着项目的进行,可以修改(或替换)每个组件的内部
· 通过预先指定接口,可以有效地测试每个组件的行为(通过单元测试)
· 扩展系统时,可以通过组合在其他组件之上构造新组件
在此阶段,回测器的设计易于实现,并具有一定程度的灵活性,但要以牺牲市场准确性为代价。该回测器将只能处理应用于单个工具的策略。稍后,回测器将进行修改以处理各种仪器。对于初始回测器,需要以下组件:
缺少了什么?
可以看出,该回测器不包含投资组合/风险管理,执行处理(即无限制订单)的任何参考,也不会提供交易成本的复杂建模。在现阶段这不是什么大问题。它使我们能够熟悉创建面向对象的反向测试器和Pandas / NumPy库的过程。随着时间推移,它将得到改善。
现在,我们将概述每个对象的实施过程:
战 略
在此阶段,策略对象必须非常通用,因为它将处理预测,均值回归,动量和波动率策略。这里考虑的策略将始终基于时间序列,即“价格驱动”。此回测器的早期要求是派生的策略接受条形图列表(OHLCV)作为输入,而不是报价(逐笔交易价格)或订单簿数据。因此,此处考虑的最细粒度为1秒柱。
策略类也将始终产生信号建议。这意味着它将建议做多/做空或持有头寸。这种灵活性将使我们能够创建多个策略“顾问”,以提供一组信号,更高级的投资组合类别可以接受这些信号,以确定所输入的实际头寸。
接口将通过抽象基类方法来实施。抽象基类是无法实例化的对象,因此只能创建派生类。在名为backtest.py的文件中提供了Python代码。策略类要求任何子类别都可以实现该generate_signals方法。
为了防止直接实例化策略类(因为它是抽象的!),必须使用abc模块中 ABCMeta的和abstractmethod对象。我们设置该类的一个属性,该属性称为metaclass,等同于ABCMeta,用abstractmethod嵌入 generate_signals方法之中。
尽管上面的程序很简单,但是为每种特定的策略继承此类时,它将变得更加复杂。最终,在此设置中,策略类的目标是为要发送到投资组合的每种工具提供多头/空头/持有信号的列表。
投资组合
投资组合类是大多数交易逻辑所在的位置。对于该研究回测器,投资组合负责确定头寸规模,风险分析,交易成本管理和执行处理(即开市价,平仓价定单)。在稍后的阶段,这些任务将分解为单独的组件。现在,他们将分为同一类。
此类充分利用了pandas,并提供了一个很好的示例(库可以在其中节省大量时间,尤其是在“样板”数据处理方面)。顺便说一句,pandas和NumPy的主要技巧是避免使用for d in ...语法迭代任何数据集。这是因为NumPy(作为pandas的基础)通过矢量化操作优化了循环。因此,使用pandas时,您将看到很少(如果有的话)直接迭代。
投资组合类的目标是最终产生一系列交易和一个资产曲线,然后由绩效类进行分析。为了实现这一点,必须为它提供来自策略对象的交易建议列表。在以后,这将成为一组策略对象。
投资组合类将需要被告知如何将资金用于特定的一组交易信号,如何处理交易成本以及将使用哪种形式的订单。策略对象是基于数据条操作的,因此必须对执行订单时获得的价格做出假设。
由于任何数据条的高/低价格都是先验未知的,因此只能使用开盘价和收盘价进行交易。实际上,无法保证使用市场定单时将以这些特定价格之一执行定单,因此充其量只能是近似值。
除了关于已执行订单的假设外,该回测器还将忽略保证金/经纪约束,并假设可以在没有任何流动性约束的情况下,在任何工具中自由做多或做空。这显然是一个非常不现实的假设,但是以后可以放宽条件。
以下继续backtest.py:
在这一阶段,已经引入了策略和投资组合抽象基类。我们现在可以完成一些具体派生的类的实施,以便产生一个可行的“玩具策略”。
我们将首先生成一个名为RandomForecastStrategy的策略子类,其唯一任务是产生随机选择的长/短信号!尽管这显然是一种荒谬的交易策略,但它将通过演示面向对象的回测框架来满足我们的需求。因此,我们将撰写一个名为random_forecast.py的新文件,其中的随机预测器陈列如下:
现在我们有了一个“具体”的预测系统,我们必须实施一个投资组合对象。该对象将包含大多数回测代码。它旨在创建两个单独的数据框架,第一个是positions框架,用于存储在任何特定柱上持有的每种工具的数量。第二个,portfolio实际上包含每条上所有持仓的市场价格,以及现金的总计(假设有初始资本)。这最终提供了一条评估战略绩效的资产曲线。
投资组合对象虽然在界面上非常灵活,但是在如何处理交易成本,市场订单等方面需要有特定的选择。在这个基本示例中,我认为可以轻松地做多/做空而没有受到任何限制。保证金,直接以柱线的开盘价买卖,交易成本为零(包括滑点,费用和市场影响),并指定了每笔交易可直接购买的库存数量。
接下来仍然是random_forecast.py:
这为我们提供了基于该系统生成资产曲线所需的一切。最后一步是将所有main功能与一个函数绑定在一起:
程序的输出如下。根据您选择的日期范围和使用的随机种子,您的输出将与下面的输出不同:
在这种情况下,该策略亏损了,鉴于预测者的随机性,这并不奇怪!下一步是创建一个Performance对象,该对象接受Portfolio,并提供性能指标列表,基于这些指标可以决定是否过滤策略。
我们还可以改进Portfolio对象,以更现实地处理交易成本(例如,盈透证券佣金和滑点)。我们还可以直接将预测引擎包含到策略对象中,这将(希望能)产生更好的结果。在以下文章中,我们将更深入地探讨这些概念。
本文翻译整理自quantstart,侵删。