# DolphinDB 白皮书 中高频策略回测 ![bo_d5nnobf7aajc7385o8qg_0_21_1684_1614_641_0.jpg](images/bo_d5nnobf7aajc7385o8qg_0_21_1684_1614_641_0.jpg) ## 内容 前言. .iii 第 1 章. 中高频回测方案概述. .4 第 2 章. 数据回放与订阅 .6 2.1 单表回放. .7 2.2 多表回放. 9 2.3 回放与订阅处理示例 11 第 3 章. 模拟撮合引擎. 13 3.1 模拟撮合引擎功能介绍 13 3.2 模拟撮合引擎使用示例 15 3.3 开发算法交易策略 17 第 4 章. 回测引擎. 21 4.1 中高频回测引擎功能介绍 21 4.2 编写自定义策略. 22 4.3 回测引擎配置参数. .23 4.4 回测引擎使用注意事项. 25 4.5 使用示例 .25 第 5 章. DolphinScript 编写回测策略 28 5.1 动态网格交易策略回测 .28 5.2 科创版做市策略回测示例. 33 5.3 股票中高频 CTA 策略回测 36 5.4 期货分钟频 CTA 策略回测 37 5.5 银行间债券双边跟随最优价做市策略 .39 第 6 章. Python Parser 编写回测策略. 42 6.1 Python Parser 脚本改写策略回测 42 6.2 Python Parser 和 DolphinScript 的性能对比 43 第 7 章. C++ 编写回测策略. 44 7.1 C++ 策略实现 .45 7.2 C++和 DolphinScript 的性能对比 .48 第 8 章. 总结和展望. 50 第 9 章. 附录 51 ## 前言 回测是量化交易投研的一个重要环节。量化策略上线之前,必须通过回测评估策略在历史数据上的表现。中高频策略回测相比于低频策略回测,存在两个新的挑战。首先,数据量增加了几个数量级,无论数据查询或者计算都对性能有更加苛刻的要求。其次,在中高频策略回测中,并不能简单的假设每个订单以当前价格或日终价格全部成交,需要一个模拟撮合引擎来模拟实际的交易过程,例如考虑订单能否成交、成交价格、成交量以及市场冲击等因素。DolphinDB 基于其高性能的分布式存储和计算架构,实现了行情回放、模拟撮合引擎和事件型中高频回测引擎三大核心组件,支持通过 DolphinScript、Python 或 C++语言完成中高频策略的研发和测试,提供了一个性能优异且易扩展的中高频量化交易策略回测解决方案。 目前,DolphinDB 已实现对沪深交易所所有股票标的的多种策略回测支持,包括逐笔+快照、逐笔(逐笔合成快照触发策略)、快照和快照+成交、分钟以及日频行情策略回测。同时,还支持期货和期权的快照、分钟和日频行情,以及银行间现券和融资融券等策略的回测。 ## 第 1 章. 中高频回测方案概述 一个量化中高频策略在投入实盘交易之前,都需要使用市场的历史数据来进行回测,以评估交易策略的有效性。一个量化交易回测平台的基本架构如下图所示: ![bo_d5nnobf7aajc7385o8qg_3_165_436_1321_657_0.jpg](images/bo_d5nnobf7aajc7385o8qg_3_165_436_1321_657_0.jpg) 图 1-1 策略回测基本架构 中高频量化交易策略回测平台的实现主要包括三个重要环节: - 行情数据回放 一个量化策略在用于实际交易时,处理实时数据的程序通常为事件驱动。为了实现使用同一套策略逻辑进行回测和实盘交易,量化策略回测平台一般需要分批获取历史行情数据,并严格按时间排序后注入回测引擎。沪深交易所的中高频行情数据通常包括逐笔委托、逐笔成交、快照等多种类型的数据,每日的数据量在50G左右。 基于3秒快照行情订单撮合时,需要将快照行情数据严格按照时间先后顺序注入引擎;基于逐笔行情对策略生成的订单撮合时,需要同时注入逐笔委托单和逐笔成交单两个数据源,并且严格按照时间顺序和委托单序号先后顺序注入数据,才能准确模拟实际的交易过程。 ·委托订单模拟撮合 在中高频策略或者中高频算法交易策略中,我们常常会遇到这样的情况:一些在回测中表现良好的策略或者算法交易策略,一旦应用于实际交易,效果就不如预期。其中一个非常重要的原因是回测和真实交易时的订单撮合情况不同。为了确保策略的委托订单撮合时尽可能模拟真实交易时的订单撮合情况,我们需要在中高频回测过程中引入模拟撮合系统。 ·策略开发与策略回测绩效评估 在设计中高频交易策略时,通常会采用一些指标、模型或者机器学习方法来辅助判断市场的趋势,这些指标计算和模型需要丰富的函数库。策略的制定通常需要针对不同的事件,如新行情的出现、订单的成交等,因此开发策略时需要利用多样化的事件函数来应对这些情况。回测系统还应提供包括交易记录、持仓情况、收益信息等在内的全面的回测结果,以便用户深入分析策略的回测表现。 DolphinDB 提供了完整的解决方案,涵盖以下 3 个环节: - 回放功能:支持将一个或多个不同结构的分布式表中的数据严格按照时间或者按指定多列排序顺序回放到流表中,模拟实时行情数据。 ·模拟撮合引擎插件:支持沪深交易所 Level-2 逐笔行情和快照行情,实现了与交易所一致的“价格优先,时间优先”高精度撮合、支持基于多种行情数据的撮合模式、并提供丰富的撮合配置,模拟真实的实盘交易环境。 ·回测插件:用户可以在其中自定义指标,支持基于逐笔、快照、分钟和日频行情进行策略回测,获取回测的收益、持仓、交易明细等信息。其中基于逐笔和快照行情进行高精度策略回测,用户可以实现仿真和回测一体化的策略验证。 这 3 个模块化解决方案涵盖了中高频策略回测平台所需的所有环节,整合在一起就构成了 DolphinDB 一站式的中高频策略回测解决方案。这些解决方案与外部解决方案兼容性良好。如果用户已经实现了回测平台中某个环节,DolphinDB 提供的解决方案也可以与其融合成一个完整的回测方案。例如: 1. 用户已实现了基于其他语言的量化交易实盘和中高频回测一体化平台,可以将数据存储在 DolphinDB 中,采用 DolphinDB 的回放功能,将中高频行情数据回放到 C++、Java 和 Python 等客户端,快速对接已有量化交易回测系统。 2. 用户可以采用 DolphinDB 的回放功能和模拟撮合引擎,基于 Swordfish 编写回测系统。 3. 用户可以采用全套 DolphinDB 回测框架,编写 DolphinDB 脚本、Python 和 C++ 三种不同语言的策略代码。 ![bo_d5nnobf7aajc7385o8qg_4_101_1125_1455_854_0.jpg](images/bo_d5nnobf7aajc7385o8qg_4_101_1125_1455_854_0.jpg) 图1-2 中高频策略回测方案的三种实现方式 不同方案的模块部署如图 1-2 所示,其中紫色部分是需要用户实现的模块,蓝色部分为 DolphinDB 内置模块。本文第 2-4 章,我们将分别介绍 DolphinDB 的数据回放、模拟撮合引擎和中高频回测引擎插件。在第 5 章中,我们将实现一些具体的策略,展示如何在实际场景中使用 DolphinDB 中高频策略回测解决方案。 ## 第 2 章. 数据回放与订阅 用户的量化策略在生产(交易)环境中运行时,通常由事件驱动处理实时数据。为确保研发和生产使用同一套代码,通常在研发阶段需要将历史数据,严格按照事件发生的时间顺序进行回放,以此模拟交易环境进行回测。在回测时,对数据回放的要求包含以下几点: ・速度快:作为回测的一个环节,为了提高回测效率,能在最短时间内回放完所有数据。 - 支持多种数据:实时数据可能是一自单张表,也可能分布在多张表中,要求具备对多种数据源的支持能力。 - 支持多种部署方式:数据的发布和订阅可以部署在一台服务器上,也能部署在两台不同的服务器上。 - 灵活选择数据源:以类似 SQL 的方式,指定需要回放的数据,方便调试和测试。 针对以上要求,DolphinDB 以流表为中心,建立了一套包含发布、订阅、持久化功能的数据回放方案。上述提及的流表是 DolphinDB 中一种特殊的内存表,能支持同时读写,且只能添加记录,用户不能修改或删除记录。通过开启持久化功能可以将部分记录存盘,同时将其从内存中移除,以免流表内存占用过大。下图展示了方案的整体流程。 ![bo_d5nnobf7aajc7385o8qg_5_109_961_1394_1006_0.jpg](images/bo_d5nnobf7aajc7385o8qg_5_109_961_1394_1006_0.jpg) 图2-1 发布-订阅-消费流程 以流表为中心,整个方案包含三个任务。 1. 发布任务从数据库中取数据,并插入流表顶部,通过多线程执行发布任务以满足对回放性能的要求。 2. 消费者订阅流表后,订阅任务从流表中取数据,分批发给消费者,可以同时满足多个客户端订阅的需求。 3. 为了节省流表对系统内存的占用,通过开启持久化任务,定期将流表尾部的数据迁移到文件中。 DolphinDB 通过以上方案能解决多种回放方式、多种数据源、多种消费方式的需求,并提供以下功能: ·控制回放速率:通过调整回放的速率可以测试不同压力下的系统表现。DolphinDB 支持四种回放速率: 。指定每秒内的回放记录数; 。按时间范围加速N倍回放; 。按两条数据的精确时间间隔加速N倍回放; 。全速回放。 ·从指定位置订阅:回测时用户可以从第一条数据开始订阅、从上次消费的位置后面开始订阅或者订阅将来的数据。 ·对同一个流表进行多个订阅:用户可以对同一个流表进行多个订阅,每次订阅验证不同的仿真交易,每个订阅可以配置不同的参数和开始位置。 ·筛选订阅:用户可以在订阅时指定筛选条件,确保只收到符合条件的数据,这样用户可以在一次回放后,启动多个回测任务,每个任务只回测部分股票。 针对用户回放数据库表的数量不同,分为单表回放和多表回放。下面将分别介绍单表回放、多表回放以及在中高频回测中常见的对回放数据的处理方法。 ### 2.1 单表回放 单表回放是将一张表的数据回放到流表中,客户端订阅流表并处理收到的数据。以下是在 Server 中回放和客户端订阅的整体流程和涉及到的关键函数。 ![bo_d5nnobf7aajc7385o8qg_7_116_92_1457_1450_0.jpg](images/bo_d5nnobf7aajc7385o8qg_7_116_92_1457_1450_0.jpg) 图2-2 单表回放-订阅流程 回放的过程包括创建流表、回放和删除流表。创建流表时用户可以开启持久化以节省服务器内存。客户端订阅流表后,解析并处理数据,在收到结束标记时取消订阅。回放过程中用到的函数包含丰富的配置参数,能满足回测过程中的各种需求。 --- //构造和entrust字段一致的流表并开启持久化 colName = ["symbol", "symbolSource", "TradeTime", "sourceType", "orderType", "price", "qty", "buyNo", "sellNo", "direction", "ChannelNo", "seqNum"] colType = [SYMBOL, SYMBOL, TIMESTAMP, INT, INT, DOUBLE, LONG, LONG, LONG, INT, INT, LONG] enableTableShareAndPersistence(table=streamTable(10000000:0, colName, colType), tableName=msgStreamName, cacheSize=10000000) //构造数据源 ds1_chunk = replayDS(sqlObj=, dateColumn=`TradeTime, timeColumn=`TradeTime) ds2_chunk = replayDS(sqlobj=