如何在C++交易系统中集成高性能回测与模拟撮合

DolphinDB 的高性能行情回放与模拟撮合引擎插件,为量化交易者提供了低延迟、高吞吐量的策略验证解决方案。对于已构建 C++ 回测框架的机构而言,直接在现有系统中集成撮合引擎,既能复用既有基础设施,又能获得 DolphinDB 的极速计算优势,是高频策略仿真的优选方案。

本文面向熟悉 C++ 开发、具备 DolphinDB 基础知识的量化工程师,重点讲解如何通过 Swordfish 计算库或 C++ API,将 DolphinDB 撮合引擎插件无缝集成到独立 C++ 交易系统中。相较于 DolphinDB 脚本回测,本方案可实现低延迟高并发的回测流程,特别适用于算法交易、做市策略等对时效性敏感的仿真场景。

1. 背景介绍

回测是量化交易投研的一个重要环节。量化策略上线之前,必须通过回测评估策略在历史数据上的表现。在中高频策略回测中,并不能简单的假设每个订单以当前价格或日终价格全部成交,需要一个模拟撮合引擎来模拟实际的交易过程,例如考虑订单能否成交、成交价格、成交量以及市场冲击等因素。DolhpinDB 提供了模拟撮合引擎插件,支持沪深交易所 Level-2 逐笔行情和快照行情,实现了与交易所一致的 “价格优先,时间优先” 高精度撮合、支持基于多种行情数据的撮合模式、并提供丰富的撮合配置,模拟真实的实盘交易环境;支持通过 DolphinDB 脚本语言、Python 或 C++语言完成中高频策略的研发和测试,提供了一个性能优异且易扩展的中高频量化交易策略回测解决方案。

Swordfish 是一个专为金融行业设计的高性能数据分析计算函数库,具备卓越的内存处理能力和优化的计算性能。它不仅提供多种通用计算功能,还支持实时流数据处理和用户自定义函数,满足复杂数据分析和低延迟流数据计算的需求。Swordfish 能够在任何支持 C++ 的平台上运行,用户可以通过 C++ 脚本直接调用其接口,实现高效计算。

DolphinDB C++ API 用于连接 DolphinDB 服务端和 C++客户端,从而实现数据的双向传输和脚本的调用执行。 它可以方便您在 C++ 程序中使用 DolphinDB 进行数据的处理、分析和建模等操作,利用其优秀的计算性能和强大的存储能力来帮助您加速数据的处理和分析。

本文依照《DolphinDB 策略回测白皮书》的系统设计,介绍如何在 C++ 中封装模拟撮合引擎插件,实现一个简单易拓展高精度撮合的回测框架,从而可以方便地集成到已有的 C++ 回测或者仿真系统中。本文设计了统一的事件型接口,并提供 Swordfish 和 C++ API 两种实现。2 种方式的适用场景如下:

表 1-1 Swordfish 和 C++ API 实现回测框架场景对比

2. 系统设计

在《DolphinDB 策略回测白皮书》中,介绍了中高频量化交易策略回测平台的实现,主要包括三个重要环节:

  • 行情数据回放
  • 委托订单模拟撮合
  • 策略开发与策略回测绩效评估

以此为依据可以设计出以 DolphinDB 为数据源在 C++ 进行回测的整体流程:

  1. 创建远程行情流表,并对其进行订阅;
  2. 回放行情数据到流表;
  3. 在订阅回调中遍历和解析数据,将解析后的行情数据写入到模拟撮合引擎;
  4. 触发行情回调,在回调内实现策略逻辑,执行下单等操作;
  5. 模拟撮合引擎输出成交明细等信息,并触发相关业务回调,在回调内实现策略逻辑。
  6. 回测结束后输出绩效指标。

使用 Swordfish 实现自定义回测的系统架构图如下:

图 1-1 Swordfish 自定义回测实现架构图

使用 C++ API 实现自定义回测的系统架构图如下:

图 1-2 C++ API 自定义回测实现架构图

3. 接口设计

本教程根据 DolphinDB 的模拟撮合接口所具备的功能,设计出了行情和交易接口。主要包括如下功能模块:

  • 配置项模块:负责回测框架实例的相关配置,包括远程连接配置、行情类别配置、并发相关配置等。
  • 主动调用接口模块:提供可在代码中主动调用的接口,包括创建模拟撮合引擎实例、回放数据下单、撤单等接口。
  • 回调接口模块:以回调函数的形式提供接口,包含行情回调、报单应答、成交通知等接口。
本节所介绍的配置项和接口,除非特别声明,在 Swordfish 和 C++ API 均可调用。

3.1 配置项

回测框架实例的配置项如下表所示。每个实例可独立配置,从而可以使用多个实例做并发回测。

3.2 相关接口说明

本教程设计的回测框架提供创建模拟撮合引擎实例、回放数据、下单、撤单等主动调用接口,以及行情回调、报单应答、成交通知等回调接口。下面将介绍核心的接口的设计和使用说明,其他更具体的接口说明详见附件源码内注释。

3.2.1 创建模拟撮合引擎

首先,创建模拟撮合引擎实例的接口为 createMatchEngine,提供两种接口实现:

dolphindb::SmartPointer<MatchingEngineSimulatorWrapper> createMatchEngine(dolphindb::ConstantSP name, dolphindb::ConstantSP exchange, dolphindb::DictionarySP config,dolphindb::TableSP dummyQuoteTable, dolphindb::DictionarySP quoteColMap, dolphindb::TableSP dummyUserOrderTable,dolphindb::DictionarySP userOrderColMap, dolphindb::TableSP dummyOrderDetailsOutput,dolphindb::ConstantSP orderDetailsOutputStreamTableName=nullptr)dolphindb::SmartPointer<MatchingEngineSimulatorWrapper> createMatchEngine(std::vector<dolphindb::ConstantSP> args)

第一种实现为展开的参数列表,第二种实现将第一种实现的所有参数放在一个数组里。该接口的参数要求与模拟撮合引擎插件的 createMatchEngine 接口基本相同,这里只介绍有区别的参数:

  • dummyOrderDetailsOutput:Table 类指针,成交明细输出表的实际结构,用于给 Swordfish/DolphinDB 创建输出流表提供参考结构。
  • orderDetailsOutputStreamTableName:String 类指针,成交明细输出表的流表名称,默认为 “orderDetailsOutputStream”,用于给 DolphinDB 创建流表指定名称。C++ API 特有参数

返回值为 MatchingEngineSimulatorWrapper 对象指针,引擎实例,可用来做写入行情、下单、获取成交明细等操作。

注意:在 C++ API 实现时,由于模拟撮合引擎实例存在于 DolphinDB,每次调用 createMatchEngine 都会新建一个 DolphinDB 远程连接以绑定,故建议不要频繁调用,而应该将接口返回的实例保存下来重复使用。

3.2.2 回放行情数据

创建好模拟撮合引擎后,使用 replayQuoteToMatchEngine 接口回放指定股票代码和天数的行情数据到指定引擎,可以指定回放速率。

void Interface::replayQuoteToMatchEngine(VectorSP codes, ConstantSP startDate, ConstantSP endDate,SmartPointer<MatchingEngineSimulatorWrapper> engine, int replayRate)

注意:本教程仅提供回放 Level2 股票快照行情的示例。用户可参考代码实现其他类型的行情回放。

3.2.3 行情回调

行情开始写入引擎后,会触发 onQuote 行情回调,参数为一条行情的字典,可通过 getMember(“key“) 读取字段,例如读取股票代码:

virtual void onQuote(const ConstantSP &quote){string symbol = quote->getMember("symbol")->getString();
}
3.2.4 策略实现

在实现策略时,可以使用 getMatchEngine 接口来获取指定名称的模拟撮合引擎,用来下单或撤单等。

SmartPointer<MatchingEngineSimulatorWrapper> Interface::getMatchEngine(ConstantSP name)

报单请求接口为 submitOrder,撤单请求接口为 cancelOrder,参数为引擎实例和订单数据。订单数据类型为 OrderField,是一个 struct,与模拟撮合引擎插件的用户订单表字段格式相同,字段说明:

  • symbol:字符串,标的代码。
  • timestamp:long long,下单时间戳,非必填,不填时即时撮合。
  • orderType:int,订单类型。
  • price:double,订单委托价格。
  • orderQty:long long,委托数量。
  • direction:int,买卖方向,1(买 ),2(卖)。
  • orderId:int,用户订单 ID,非必填,仅撤单时需要。
  • userOrderId:int,用户自定义订单 ID,非必填,不填时自动填一个递增的 ID。需要保证每次报单时对一个引擎填写的 userOrderId 是唯一的。

返回值为一个 long long,下单或撤单成功时返回用户订单 ID,失败时返回 -1。

long long Interface::submitOrder(SmartPointer<MatchingEngineSimulatorWrapper> engine, const OrderField &order)
long long Interface::cancelOrder(SmartPointer<MatchingEngineSimulatorWrapper> engine, const OrderField &order
3.2.5 报单/撤单应答和通知

报单或撤单后,将触发应答和通知。报单应答的回调接口为 onOrderSubmit,撤单应答的回调接口为 onOrderCancel,包含订单数据和错误码。委托通知的回调接口为 onOrder,成交通知的回调接口为 onMatch,参数为一条委托或成交明细的字典,字段格式与模拟撮合引擎的成交明细表相同。

virtual void onOrder(dolphindb::DictionarySP orderDetail);
virtual void onMatch(dolphindb::DictionarySP tradeDetail);

4. 回测平台系统实现

根据系统设计和接口设计,设计如下功能模块来实现回测和仿真交易系统:

  • 远程连接:远程连接 DolphinDB 并执行脚本,实现回放数据和清理远程环境等接口。
  • 插件加载和使用:加载模拟撮合插件,封装模拟撮合插件的相关脚本方法为 C++ 接口,实现下单和撤单等主动调用接口,以及报单委托和成交委托等回调。
  • 流数据订阅、解析和回调:订阅 DolphinDB 的流表作为数据源,解析流数据并写入到模拟撮合引擎,实现行情回调。

下面分别介绍使用 Swordfish 和 C++ API 实现的逻辑。

4.1 使用 Swordfish 实现

Swordfish 支持加载插件,支持使用 C++ 函数指针调用插件方法,入参和返回值均为以 Constant 类为基类的 DolphinDB 数据类型。我们可以通过在 Swordfish 本地调用模拟撮合引擎的方法来实现自定义回测逻辑。下面介绍主要逻辑的实现设计。

4.1.1 远程连接

在 Swordfish 中可以使用 xdb 方法远程连接 DolphinDB 节点,然后使用 remoteRun 方法执行脚本。为了实现便捷的远程连接操作,我们封装了 xdb 和 remoteRun,定义了远程连接类 DDBConnection。该类专门用于远程连接指定的 DolphinDB 节点、执行脚本和订阅流表。参数和返回值参考了 C++ API 远程连接类的设计,具体说明见源码注释。

4.1.2 插件加载和使用

在 Swordfish 中本地加载和使用模拟撮合引擎插件,可以通过 loadPlugin 方法加载并获得其接口的函数指针。为了实现便捷的插件加载和调用相关接口操作,我们封装了 loadPlugin 方法,定义了插件类 DDBPlugin,用于加载指定的插件和调用插件的接口。继承插件类实现模拟撮合引擎插件类 MatchingEngineSimulatorWrapper,调用模拟撮合引擎的相关接口实现下单和撤单等主动调用接口。具体使用说明见源码注释。

4.1.3 流数据订阅、解析和回调

在 Swordfish 中可以使用 subscribeTable 方法订阅远程 DolphinDB 的流表,该方法的一个关键参数是 handler, 用于处理订阅数据的函数指针。我们封装 Swordfish 函数定义类 SwordfishFunctionDef,用于将 C++ 函数指针方便地转换为 Swordfish 函数指针,从而可以在 C++ 的自定义方法内解析流数据并调用相关业务回调。具体使用说明见源码注释。

4.2 使用 C++ API 实现

在 DolphinDB 加载模拟撮合插件后,可以使用 C++ API 远程连接 DolphinDB,上传参数并调用相关脚本方法来实现自定义回测逻辑。下面介绍主要逻辑的实现设计。

4.2.1 远程连接

在 C++ API 可以使用 DBConnection 类远程连接 DolphinDB 和执行脚本。具体接口使用说明请参考 C++ API 官方文档。

4.2.2 插件加载和使用

在 C++ API 实现时,模拟撮合引擎插件在 DolphinDB 远程加载和使用,可以远程执行 loadPlugin 方法加载插件到 DolphinDB,然后封装远程连接类的 run 接口执行模拟撮合引擎的接口脚本,实现模拟撮合引擎插件类 MatchingEngineSimulatorWrapper,实现下单和撤单等主动调用接口。具体接口使用说明请参考 C++ API 官方文档。

4.2.3 流数据订阅、解析和回调

在 C++ API 可以使用 ThreadedClient 类订阅远程 DolphinDB 的流表,该类提供的 subscribe 方法可以直接以 C++ 的函数指针作为订阅回调,从而可以在 C++ 的自定义方法内解析流数据并调用相关业务回调。具体接口使用说明请参考 C++ API 官方文档。

5. 回测案例

基于前述设计与实现方案,本节通过核心代码示例详细阐述简易回测策略的实现逻辑,具体策略为在实时处理每笔行情快照数据后自动生成限价委托订单。完整代码请查看附件源码。

1. 定义接口类并实现策略

继承 Interface 类为 CustomInterface 类,并重写 onQuote 方法,在收到一笔行情时调用 getMatchEngine 方法获取引擎实例,然后调用 submitOrder 下单:

class CustomInterface : public Interface {public:CustomInterface(unordered_map<string, string> config) : Interface(config) {}void onQuote(const ConstantSP &quote) override {...engine = getMatchEngine(new String(matchEngineName_));string symbol = quote->getMember("symbol")->getString();OrderField order;order.symbol = symbol;order.orderType = 5;order.price = bidPrice->getLong();order.orderQty = 200;order.direction = 1;submitOrder(engine, order);}
};

2. 创建模拟撮合引擎在 main 函数中,创建 CustomInterface 类,使用 getExampleMatchEngineArgs 方法获取模拟撮合引擎的示例参数,然后使用 createMatchEngine 方法创建模拟撮合引擎。

interface = new CustomInterface(config);
auto args = interface->getExampleMatchEngineArgs();
engine = interface->createMatchEngine(args);

3. 订阅行情数据使用 subQuoteTable 方法订阅行情数据,从而使行情回调方法生效。

interface->subQuoteTable();

4. 回放行情数据

使用 replayQuoteToMatchEngine 方法回放指定股票代码和日期时间范围的数据到引擎。

interface->replayQuoteToMatchEngine(codes, startDate, endDate, engine, -1);

5. 等待回测结束

使用 isBacktestEnd 方法等待回测结束。

interface->isBacktestEnd(true);

6. 输出绩效指标

以使用 getPosition 方法输出持仓为例。可以在 CustomInterface 类中实现自定义指标的计算和输出。

cout << interface->getPosition() << endl;

6. 性能测试

本文使用的测试环境配置为:

  • DolphinDB v3.00.2.2 单节点
  • Swordfish v3.00.2 ABI0
  • CPU:Intel(R) Xeon(R) Silver 4216 CPU @ 2.10GHz 64核
  • 内存:400G
  • 硬盘:SSD 12 Gbps

统计 Swordfish 实现的回测框架进行多并发全速回放的总耗时。下单策略为对每笔快照行情下 1 单限价单。性能统计如下:

表 6-1 Swordfish 实现的回测框架性能测试统计

可见多线程并行能够有效提高性能,但并不是线性的提升,因为服务端的数据回放到流表和发送到客户端需要一定的耗时。

由于 C++ API 实现下模拟撮合引擎位于远程 DolphinDB,故下单和撤单等操作存在网络时延,倍速回放时会出现客户端操作时刻服务端已回放到更后面的时间的情况,故只能原速回放,无法进行倍速回放性能测试。

7. 总结

本文展示了如何通过使用 Swordfish 或 C++ API 在 C++ 环境下调用模拟撮合引擎插件实现自定义的高性能回测,并封装了统一的接口,从而实现将 DolphinDB 回测逻辑方便地集成到已有的 C++ 回测系统。其中,Swordfish 可以本地运行模拟撮合引擎,具有更高的灵活性,并支持倍速回放,在性能方面表现更优。

8. 附件

CppApiBacktest.zip

SwordfishBacktest.zip

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/89572.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/89572.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Laravel】 Laravel 智能验证规则生成器

Laravel 智能验证规则生成器:企业级增强方案 <?phpnamespace App\Services\Validation;use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Validator; use Illuminate\Support\Str; use Illuminate\Validation\…

讲基于优化的 IMU 与视觉信息融合

目录 视觉 SLAM 里的 Bundle Adjustment 问题 最小二乘基础概念 迭代下降法求解:下降法 最速下降法和牛顿法 阻尼法 非线性最小二乘 Gauss-Newton 和 LM 鲁棒核函数的实现 VIO 残差函数的构建 视觉重投影误差 IMU 测量值积分 状态误差线性递推公式的推导 基于误差随时间变化的…

洛谷P1107 [BJWC2008] 雷涛的小猫

洛谷P1107 [BJWC2008] 雷涛的小猫 洛谷题目传送门 题目背景 原最大整数参见 P1012 题目描述 雷涛同学非常的有爱心&#xff0c;在他的宿舍里&#xff0c;养着一只因为受伤被救助的小猫&#xff08;当然&#xff0c;这样的行为是违反学生宿舍管理条例的&#xff09;。在他的…

ROS2---话题重映射

一、话题重映射的基本概念 在 ROS2&#xff08;Robot Operating System 2&#xff09;中&#xff0c;话题重映射&#xff08;Topic Remapping&#xff09; 是一种灵活的机制&#xff0c;允许用户在不修改代码的情况下&#xff0c;改变节点发布或订阅的话题名称。这一机制在多机…

IOday4——7.3

1.思维导图 2.创建一个分支线程&#xff0c;在主线程中拷贝文件的前一部分&#xff0c;主线程拷贝文件的后一部分。 3.解读代码 info1 from child process_1 info2 from child process_1 info1 from child process_2 info1 from parent process 4.解读代码&#xff0c;打印…

[特殊字符] Excel 提取+图片批量插入 | Python 自动化生成稽查报告 Word 模板

本篇教程展示如何利用 Python&#xff0c;实现从 Excel 中提取稽查问题数据&#xff0c;并将对应图片按顺序插入到 Word 模板表格里&#xff0c;最终生成一份图文并茂的稽查报告。 目录 &#x1f4dd; Step 1&#xff1a;从 Excel 提取稽查问题数据 &#x1f5bc; Step 2&am…

【libm】 7 双精度正弦函数 (k_sin.rs)

一、源码 这段代码实现了一个高精度的正弦函数计算核心&#xff08;kernel sin function&#xff09;&#xff0c;用于计算在区间约[-π/4, π/4]内的正弦值。 // origin: FreeBSD /usr/src/lib/msun/src/k_sin.c // // // Copyright (C) 1993 by Sun Microsystems, Inc. Al…

c++ 的标准库 --- std::

在 C 的标准库&#xff08;std&#xff09;里&#xff0c;除了 std::string&#xff0c;还有很多常用的类型和工具。下面列举一些最常用的&#xff1a; 常用的 std:: 标准库类型 1. 容器类&#xff08;用来存放一组数据&#xff09; std::vector  // 动态数组&#xff0c;类…

用 PyTorch 构建液态神经网络(LNN):下一代动态深度学习模型

引言 在深度学习领域&#xff0c;研究人员不断探索更接近生物神经系统工作方式的模型。液态神经网络(Liquid Neural Networks, LNN)正是这样一种受生物神经元动态特性启发的创新架构。本文将带你了解LNN的核心概念&#xff0c;并展示如何使用PyTorch实现这种前沿模型。 一、什…

取消latex Beamer 中,右下角的导航按钮

取消 Beamer 右下角的导航按钮 在 Beamer 中,右下角的导航按钮(如上一页、下一页、目录等)是由主题(如 Boadilla)自动添加的。要移除它们,可以通过以下方法实现: 方法 1:使用 \setbeamertemplate{navigation symbols}{}(推荐) 在导言区(\begin{document} 之前)添…

LLaMA-Factory 单卡后训练微调Qwen3完整脚本

LLaMA-Factory 单卡后训练微调Qwen3完整脚本 flyfish 使用说明 将下面代码保存为 train_single_gpu.sh 修改脚本中的以下参数&#xff1a; MODEL_PATH&#xff1a;模型路径 DS_CONFIG_PATH&#xff1a;DeepSpeed配置文件路径 OUTPUT_PATH&#xff1a;输出目录路径 --dataset…

AI自动化神器-DroidRun使用体验

引言 DroidRun 是一个强大的框架&#xff0c;用于通过 LLM 代理控制 Android 设备。它允许您使用自然语言命令自动化 Android 设备交互。 特点 使用自然语言命令控制 Android 设备 支持多个 LLM 提供商(OpenAI、Anthropic、Gemini) 易于使用的 CLI 用于自定义自动化的可扩…

免费文件管理 智能转换GC-Prevue:PDF 转 Word 多种格式 一键完成

前言 在现代办公环境中&#xff0c;高效的数据处理和文档管理是提高工作效率的关键。GC-Prevue是一款专为Windows系统设计的办公辅助软件&#xff0c;软件下载地址安装包 它通过一系列实用的功能&#xff0c;帮助用户更高效地处理和管理文档&#xff0c;提升整体办公效率。 软…

Java SE--运算符和逻辑控制

大多数和c语言一样 新增补充&#xff1a; 一.运算符 1.左移&#xff08;<<&#xff09; 结果公式&#xff1a; n*2^x (n代表所要位移的数&#xff0c;x代表位移几位) 2.右移&#xff08;>>&#xff09; 结果公式&#xff1a; n/2*x (n代表所要位移的数&a…

如何配置core dump生成

文章目录 **一、临时配置&#xff08;当前会话有效&#xff09;**1. **设置core文件大小限制**2. **设置core文件命名格式&#xff08;可选&#xff09;** **二、永久配置&#xff08;所有会话生效&#xff09;**1. **修改系统限制配置**2. **修改内核参数** **三、高级配置选项…

小程序包上传大小超限制处理

背景。想要进行真机测试&#xff0c;体验版。但是单机上传操作之后。提示超大晓限制。上传操作 完成填写后上传 上传后超过限制。能看到图片下方有错误提示。可以根据提示处理包大小问题。 解决方案&#xff1a;待续

JS | 动态生成函数 和 保存局部变量

动态生成函数 和 保存局部变量&#xff0c;适用于 闭包 和 高阶函数&#xff0c;存在于异步编程、事件处理、回调函数以及函数式编程中。 动态生成函数&#xff1a;运行时创建函数。 闭包&#xff1a;创建一个可以访问外部作用域变量的函数。 Function 构造函数&#xff1a;使…

设计模式(七)

迭代器模式&#xff08;Iterator Pattern&#xff09;详解 一、核心概念 迭代器模式提供一种方法来顺序访问一个聚合对象中的各个元素&#xff0c;而又不暴露该对象的内部表示。该模式将遍历逻辑封装在迭代器对象中&#xff0c;使聚合对象和遍历逻辑分离。 核心组件&#xf…

24年OPPO秋季笔试题

257. 小欧过河 链接&#xff1a;https://kamacoder.com/problempage.php?pid1337 思路&#xff1a;这道题的实际需要求的就是在两个11之间&#xff0c;最多能有多少个0。可以记录在遍历序列的时候&#xff0c;记录有最多个0的1的两个下标&#xff0c;最后再返回其差值。要注…

处理Lombok的一个小BUG

对于Lombok报错的修改 一、问题描述 在使用IDEA创建spring boot项目时如果你勾选了Lombok&#xff0c;生成的Lombok会随着maven的刷新而改变处理器的扫描路径&#xff0c;从项目类变到自定义的处理器路径 二、原因与解决方法 原因就是这里写了Lombok的路径才会导致你每次刷新都…