在汇率波动日益频繁、企业与机构对风险管理要求不断提高的背景下,外汇交易策略已成为资产配置与对冲操作的重要工具。其中,CTA 策略在外汇交易中具有非常重要的实际应用价值,在风险控制、趋势捕捉、资金效率与交易实用性之间取得了良好平衡。
在投入实盘交易之前,利用市场的历史数据对量化中高频策略进行测试和评估是确保交易策略有效性和可行性的重要步骤。DolphinDB 凭借其高性能计算引擎和强大的数据处理能力,成为交易策略回测的理想选择。本文将通过一个结合中高频 CTA 逻辑与实时风控的外汇远期交易策略案例,展示 DolphinDB 回测引擎的使用,以及其在实际应用中的应用优势。

1. 背景介绍

本文将详细展示如何结合多个技术分析指标,如 RSI (相对强弱指数),Bollinger Bands(布林带),构建一个涵盖买卖开仓逻辑的外汇 CTA 策略,并通过算法订单实现具备实时止盈止损功能的风险控制机制。
在介绍该策略的实现过程之前,为帮助读者更清晰地理解背景与应用场景,本章将简要介绍外汇交易的基本特点、CTA 策略的核心思路,以及 DolphinDB 提供的回测解决方案。

1.1 外汇交易背景介绍

中国的外汇市场以银行间外汇市场为核心,由中国外汇交易中心(CFETS)组织交易。交易品种主要包括即期外汇、远期外汇、外汇掉期、期权等。不同于国际市场,中国尚未开放外汇期货交易,远期合约成为企业管理汇率风险的主要工具之一。外汇远期合约(Forward FX)是指买卖双方约定在未来某一时间以固定汇率交换一定数量货币的合约。它广泛用于锁定结汇成本、规避汇率波动。相比现货交易,远期合约具有非标准化、定制化、无交易所挂牌等特点。其价格通常基于即期汇率与利率平价理论计算而来,受利差、期限结构、市场预期等因素影响。尽管远期交易以对冲为主,但在利差套利、汇率择时、资金流动管理等领域也广泛应用于策略化操作。通过历史数据进行回测,可以系统评估策略的收益风险特征、参数稳定性以及对汇率变动的敏感性。

1.2 CTA 策略背景介绍

CTA 投资策略主要通过技术分析和系统化交易方法,对期货、外汇、利率等衍生品进行交易。随着全球金融市场的发展,CTA 策略已被广泛应用于外汇市场,成为机构和量化交易者应对汇率波动、实现趋势跟踪与风险控制的重要工具之一。CTA 策略通常分为主观 CTA 和量化 CTA 两大类型。前者依赖交易员对宏观经济、政策事件等基本面的判断进行主观决策;而后者则基于量化模型,按照预设规则自动生成买卖信号并执行交易。尤其在量化 CTA 策略中,交易决策往往依托一系列技术指标,RSI、Bollinger Bands、平均真实范围(ATR)等,来识别市场趋势和交易机会。同时, CTA 策略高度重视风险管理。通过设置止盈止损、限制头寸规模、控制最大浮亏等方式,量化 CTA 策略在追求趋势收益的同时,也注重保护资金安全,提高策略在不同市场环境下的稳健性。

1.3 DolphinDB 中高频回测解决方案概述

中高频量化交易策略回测平台的实现主要包括三个重要环节:行情数据按顺序回放,委托订单撮合,以及策略开发与策略回测绩效评估。而在实现中高频策略回测时往往面临以下几个挑战:
首先,海量中高频交易数据对回测引擎的查询与计算性能提出了极高的要求。
其次,为确保策略评估和优化的有效性,回测过程中应尽可能模拟实际的交易过程,例如考虑订单能否成交、成交价格、成交量以及市场冲击等因素。
此外,回测引擎还应具有灵活的架构,能够支持多种交易策略和技术指标的实现,并且易于扩展,以适应不同的市场和交易需求。
针对上述挑战,DolphinDB 基于其高性能的分布式存储和计算架构,为用户提供了一个易扩展、性能优的中高频量化交易策略回测解决方案。该方案实现了库内行情回放、模拟撮合引擎和事件型中高频回测引擎三大核心组件,支持通过 DLang、Python 或 C++语言完成中高频策略的研发和测试。具体来说,该方案涵盖以下三个模块:

  • 回放功能:支持将一个或多个不同结构的分布式表中的数据严格按照时间或者按指定多列排序顺序回放到流表中,因此可以方便地解决因子计算和量化策略研发中研发和生产一体化的问题。
  • 模拟撮合引擎插件:支持沪深交易所 Level-2 逐笔行情和快照行情,实现与交易所一致的 “价格优先,时间优先” 的高精度的撮合、基于多种行情数据的撮合模式、丰富的可用于模拟实盘环境的撮合配置。
  • 回测插件:用户可以在其中自定义指标,支持基于逐笔、快照、分钟和日频行情进行策略回测,获取回测的收益、持仓、交易明细等信息。其中基于逐笔和快照行情进行高精度策略回测,用户可以实现仿真和回测一体化的策略验证。

值得一提的是,这三个模块化解决方案与外部解决方案兼容性良好。即使用户已经实现了某个环节的解决方案,DolphinDB 提供的解决方案也可以与其融合成一个完整的回测方案。

2. 基于 DolphinDB 的外汇 CTA 策略:中低频交易与高频风控融合实践

在大部分的 CTA 策略中,高精度的订单模拟撮合和实时风险控制是确保策略成功和有效执行的关键因素。策略的主要逻辑可能是基于分钟等聚合的 K 线行情,订单的成交依赖高精度的订单撮合引擎或者策略止盈止损依赖实时的 tick 级高频行情。DolphinDB 可以实现回测引擎以实时的 tick 行情作为回测引擎行情输入,同时按配置的指定频率触发 onBar 行情回调方式回测。本案例基于 tick 级高频行情数据,通过配置项 callbackForSnapshot 实时合成 1 小时 K 线,以实现一个基于布林带突破与 RSI 指标的外汇 CTA 趋势策略。具体的策略逻辑如下:

  • 做多开仓:当前 RSI 大于 70 且布林带正在上移并打破上轨
  • 做空开仓:当前 RSI 小于 30 且布林带正在下移并打破下轨
  • 如果存在多头或空头委托订单,在算法订单中根据 tick 行情判断是否撤单、止盈止损

2.1 编写自定义策略

首先,基于 tick 行情数据定义重要的技术分析指标:RSI 和 Bollinger Bands。RSI 用来评估市场的超买或超卖状态,Bollinger Bands 则用来判断价格波动是否突破区间。为了满足使用中高频行情数据计算类似量价因子的需求,DolphinDB 回测引擎采用了响应式状态引擎。这一引擎能够实现流批统一计算,并有效处理带有状态的高频因子,具体也可以参考响应式状态引擎用户手册定义相应的指标。以下是定义技术指标 RSI 和 Bollinger Bands 的代码示例:

@state
defg RSI(close, timePeriod=14) {deltaClose = deltas(close)up = iif(nullCompare(>, deltaClose, 0), deltaClose, 0)down = iif(nullCompare(>, deltaClose, 0), 0, -deltaClose)upAvg = wilder(up, timePeriod)downAvg = wilder(down, timePeriod)return 100.0 * upAvg / (upAvg + downAvg)
}
@state
def stddev(close, timePeriod=5, nbdev=1){return sqrt(var(close, timePeriod, nbdev)) * nbdev
}
@state
def bBands_(close, timePeriod=5, nbdevUp=2, nbdevDn=2, maType=0){mid =sma(close, timePeriod)md = stddev(close, timePeriod, 1)return ((mid + nbdevUp * md), mid, (mid - nbdevDn * md))
}

中高频回测中,策略通常是事件驱动的,而一个策略逻辑通常需要涉及多种事件,比如新的行情到来、新的订单成交等等。DolphinDB 回测引擎采用事件驱动机制,提供了全面的事件函数如策略初始化函数、盘前回调函数、行情回调函数、每日盘后回调函数等,用户可以在相应的回调函数中编写策略逻辑实现相应的策略。此外,自定义回调函数支持 JIT 技术,可以有效提升策略执行效率。后续本案例将会展示不同的事件函数是如何实现的。
在策略初始化函数中,首先订阅指标 RSI 、Bollinger Bands。subscribeIndicator 接口获取回测引擎名、需要计算的数据类型、需要计算的指标字典(key 为指标名,用于之后访问;value 为指标计算的元代码),之后计算结果将传入 onBar 策略回调函数。

def initialize(mutable context){print("initialize")d=dict(STRING,ANY)d["rsi"]=<ta::rsi(lastPrice, 11)>d["bhigh"]=<ta::bBands(lastPrice, 20, 2, 2, 0)[0]>d["bmid"]=<ta::bBands(lastPrice, 20, 2, 2, 0)[1]>d["blow"]=<ta::bBands(lastPrice, 20, 2, 2, 0)[2]>Backtest::subscribeIndicator(context["engine"], "snapshot_kline", d)}

在 K 线回调函数 onBar 中,系统通过获取订阅的 RSI 和 布林带 指标生成开仓信号。并通过算法订单来实现止盈止损。onBar 函数的 msg 参数,为回测引擎传来的合成的 K 线行情,以及在 initialize 中定义的指标计算结果。msg 是一个字典,字典的 key 为期货标的名,而 value 为这支期货标的对应的行情信息以及指标计算结果。以下代码展示了买入开仓与卖出开仓的判断逻辑:

def onBar(mutable context, msg,indicator){istock=msg.keys()[0]msg_=msg[istock]askPrice0=msg_.offerPrice[0]bidPrice0=msg_.bidPrice[0]spread=askPrice0-bidPrice0indicator_=indicator[istock]blow=indicator_.blowbhigh=indicator_.bhighif(spread>context["maxSpread"]){return }rsi_=indicator_.rsiif(isNull(rsi_)){return}close=msg_.lastPricebmid=indicator_.bmidopen=msg_.openistock=msg_.symbolposition=Backtest::getPosition(context["engine"],istock)longpos = position.longPositionshortpos = position.shortPositionif(rsi_>70. and askPrice0>bhigh and close>open and longpos <1){Backtest::submitOrder(context["engine"], (istock,msg_.symbolSource ,context["barTime"],5, round(askPrice0,5), askPrice0 -context["sl"]+context['Slippage'] , askPrice0+ context["tp"]+context['Slippage'], 2, 1,context['Slippage'], 0, context["barTime"]+36000000),"openBuy", 5)return}if(rsi_<30. and bidPrice0<blow and close<open and shortpos <1){Backtest::submitOrder(context["engine"], (istock,msg_.symbolSource,context["barTime"],5, round(bidPrice0,5), bidPrice0+context["sl"]-context['Slippage'], bidPrice0 - context["tp"]-context['Slippage'], 2, 2, context['Slippage'] , 0, context["barTime"]+36000000),"openSell", 5)return}
}

这里的 Backtest::submitOrder 是回测引擎提供的下单接口,回测引擎内置了实时止盈止损的算法订单,配置项 enableAlgoOrder 设置为 true 时,可以开启算法订单:

Backtest::submitOrder(engine, orderMsg, label="", orderType = 5)

orderMsg 为元组类型,包含的成员变量分别是标的代码、交易所代码、时间、订单类型、委托订单价格、止损价、止盈价、委托订单数量、买卖方向、滑点、委托订单有效性,以及委托订单到期时间。算法订单的类型 orderType 的取值包括限价止盈订单(1),市价止盈订单(2),限价止损订单(3),市价止损订单(4),限价止盈止损订单(5),和市价止盈止损订单(6)。

2.2 根据策略设置相应的配置参数

回测的开始与结束日期、初始资金、手续费和印花税、行情类型、订单延时等均可以通过参数进行配置。这些参数允许用户灵活地调整回测条件,以模拟不同的市场环境和交易策略的效果。此外策略逻辑上下文 context 也可以通过参数设置策略中的全局变量,此案例中我们在 context 中设置了策略中需要的滑点、点差以及止盈止损价。具体的初始参数配置代码示例如下:

startDate=2018.12.31
endDate=2019.12.31
userConfig=dict(STRING,ANY)
userConfig["startDate"]=startDate
userConfig["endDate"]=endDate
userConfig["strategyGroup"]="universal"
userConfig["frequency"]= 3600000
userConfig["cash"]= 10000000
userConfig["dataType"]=1
userConfig["depth"] = 1;
userConfig["enableAlgoOrder"]= true
userConfig["latency"]= 1
userConfig["callbackForSnapshot"]=2
userConfig["matchingMode"]=3
Context=dict(STRING,ANY)
Context["opens"]=false
Context["Slippage"]=0.00002
Context["tp"]=0.01
Context["sl"]=0.001
Context["orderId"]=0
Context["maxSpread"]=2.
userConfig["context"]=Context

我们通过配置项 callbackForSnapshot 和 frequency,按指定频率触发 onBar 行情回调,从而驱动回测策略执行。以下是对这两个配置项的具体说明:

配置项配置项说明
callbackForSnapshot = 0表示 tick 行情:tick 行情触发 onSnapshot 行情回调
callbackForSnapshot = 1,frequency > 0表示 tick 行情:tick 行情触发 onSnapshot 行情回调;tick 行情按指定 frequency 频率合成的 K 线行情触发 onBar 行情回调
callbackForSnapshot = 2,frequency > 0表示 tick 行情:tick 行情按指定 frequency 频率合成的 K 线行情触发 onBar 行情回调

2.3 创建回测引擎

设置引擎名称、引擎配置项、相应的回调函数、合约基本信息表等相应参数之后,通过接口 createBacktester 创建模拟撮合引擎实例。其中,接口 createBacktester 的第四个参数为表示是否开启 JIT 优化。默认值为 false,表示不开启,若需要开启 JIT 优化,只需要设置此参数为 true 即可。

callbacks=dict(STRING,ANY)
callbacks["initialize"]=initialize
callbacks["beforeTrading"]=beforeTrading
callbacks["onBar"]=onBar
callbacks["onOrder"]=onOrder
callbacks["onTrade"]=onTrade
callbacks["afterTrading"]=afterTrading
callbacks["finalize"]=finalize
strategyName="ftxdemoStrategydemo333"
try{Backtest::dropBacktestEngine(strategyName)}catch(ex){print ex}
engine = Backtest::createBacktester(strategyName, userConfig, callbacks,false,basicInfo)

2.4 执行回测引擎

通过 Backtest::createBacktester 创建回测引擎之后,可以通过以下方式执行回测。backtestdata_ 为相应的分钟频率行情数据,行情数据字段和类型说明参考 回测插件的接口文档。

Backtest::appendQuotationMsg(engine, backtestdata_ )

2.5 获取回测结果

回测运行结束之后,可以通过相应的接口获取每日持仓、每日权益、收益概述、成交明细和策略中用户自定义的逻辑上下文。回测插件提供的完整回测结果接口可以参阅 回测插件的接口文档。下图为本例获得的交易明细结果:

3. 性能测试

为了更直观地展示 DolphinDB 高频回测引擎在实际场景下的执行性能,我们选取了一只外汇远期合约的一年历史数据作为测试样本。在单线程、非 JIT 模式下运行该策略示例,共处理了 29,317,091 条行情数据,生成 168 笔订单,整体回测耗时约为 8.2 秒。

4. 总结

在量化回测中,全面采用 tick 数据会带来较高的计算成本,而纯粹依赖中低频策略又容易忽略实盘中的滑点影响与风控响应延迟问题。为兼顾回测性能与交易精度,本文展示了一种将中低频决策逻辑与高频风控机制相结合的策略架构:策略核心逻辑基于分钟或小时级别的 K 线进行信号判断与下单操作,关键的止盈止损则通过 tick 行情回调实时监控并触发,从而更真实地还原实盘交易过程中的风控行为。展现了 DolphinDB 回测引擎优异的性能、丰富的策略触发机制以及全面的回测结果信息。

5. 附录

外汇 CTA 策略 demo 以及所需要的数据

  • FXDemo.dos
  • backtestdata_.zip

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

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

相关文章

【iOS】内存管理及部分Runtime复习

1.继承链关于继承链存在两个指针 类的superclass指向父类 父类的sp指向根类 根类的sp指向空 元类的sp指向父类的元类 最终指向根元类 而根元类的sp指向根类 而关于isa指针 对象的isa指针指向它所属的类 类的isa指针指向元类 元类的isa指针指向根元类 根元类的isa指针指向自己2.…

重置 Windows Server 2019 管理员账户密码

文章目录前言1. 重置方法2. 重置流程总结前言 之前因为参加华为存储的 HCIE 培训和考试&#xff0c;以及在项目上交付和运维&#xff0c;占用了较多的时间和精力&#xff0c;导致很长一段时间没有去写博客&#xff0c;前些天登录 CSDN 博客发现原力已失效&#xff0c;才知道平…

.Net Core Web 架构(管道机制)的底层实现

.Net Core Web 架构(管道机制)的底层实现 .NET Core Web 程序的底层实现是一个复杂的体系&#xff0c;但我们可以将其分解为几个核心部分来理解。它本质上是一个将 HTTP 请求转换为开发者代码执行&#xff0c;并将执行结果返回为 HTTP 响应的精密管道。 下图清晰地展示了这一处…

计算图的力量:从 PyTorch 动态图到 TensorFlow 静态图的全景与实战

计算图的力量:从 PyTorch 动态图到 TensorFlow 静态图的全景与实战 开篇引入 Python 从简洁优雅的脚本语言,成长为连接数据科学、机器学习与工程化部署的“胶水语言”。在这段进化中,深度学习框架把“数学表达式”变成可执行的“计算图”,让自动求导与高性能并行成为日常…

CentOS 7能联网但yum报错:Could not resolve host: mirrorlist.centos.org 终极解决方法

CentOS 7能联网但yum报错&#xff1a;Could not resolve host: mirrorlist.centos.org 终极解决方法关键词&#xff1a;CentOS 7, yum, Could not resolve host, mirrorlist.centos.org, 软件源, EOL问题描述大家好&#xff01;相信很多还在使用 CentOS 7 的朋友都遇到了这个问…

【解锁Photonics for AI:系统学习光学神经网络与超表面设计,成就下一代光芯片工程师】

### 光学神经网络基础 光学神经网络利用光子替代电子进行信息处理&#xff0c;具有低延迟、高带宽和低功耗优势。核心组件包括衍射光学元件&#xff08;DOE&#xff09;、马赫-曾德尔干涉仪&#xff08;MZI&#xff09;和微环谐振器。 衍射神经网络&#xff08;DNN&#xff09…

基于SrpingBoot和Vue的共享笔记管理系统-项目分享

基于SrpingBoot和Vue的共享笔记管理系统-项目分享项目介绍项目摘要用户管理实体图笔记分享管理实体图系统总体功能图写在最后项目介绍 使用者&#xff1a;管理员、用户 开发技术&#xff1a;MySQLJavaSpringBootVue 项目摘要 随着网络技术的普及和人们阅读习惯的改变&#x…

我的6年!

修改前&#xff1a;https://t.zsxq.com/ERUuD Data&#xff1a;2025/08/27 更新 你好&#xff0c;我是老成。我在星球中用红包&#x1f9e7;的方式鼓励大家发自我介绍&#xff0c;但是我又想&#xff0c;为带动大家&#xff0c;我得做个榜样&#xff0c;为此我重新修改一下我的…

深入理解事务一致性和隔离性

事务是数据库系统提供的高级抽象&#xff0c;利用事务可以让应用层付出较少的努力就能提供较高的一致性保障&#xff0c;而不用过度关心类似于竞争条件、不完全写入、数据丢失等问题。 稍微学过用过数据库的同学&#xff0c;大都接触过事务这个概念&#xff0c;通常也知道事务…

最优化方法学习笔记

什么是“最优化”&#xff1f;最优化方法的核心思想是&#xff1a;在给定的条件下&#xff0c;找到一个最佳的解决方案。这个“最佳”通常是指使得某个目标函数&#xff08;可以是最小化或最大化的数值&#xff09;达到极致的答案。简单来说&#xff0c;就是如何用最好的方式做…

多模态融合新纪元:Ovis2.5 本地部署教程,实现文本、图像与代码的深度协同推理

一、简介Ovis2.5 旨在实现原生分辨率的视觉感知和增强的多模态推理。它集成了一个原生分辨率的视觉变换器&#xff08;NaViT&#xff09;&#xff0c;可以处理原始、可变分辨率的图像&#xff0c;消除了固定分辨率切片的需要&#xff0c;并保留了精细细节和全局布局——这对于图…

力扣hot100:滑动窗口最大值优化策略及思路讲解(239)

记录一下今天完成的算法题&#xff0c;虽然这个难度是困难&#xff0c;但感觉没有那个560.和为k的子数组和难想&#xff0c;这个题主要就前期遇到个优先队列&#xff0c;因为之前没用过&#xff0c;不太熟悉&#xff0c;剩下的思路感觉都属于正常难度问题描述原始思路&#xff…

“互联网 +”时代下开源 AI 大模型 AI 智能名片 S2B2C 商城小程序:行业变革与未来展望

摘要&#xff1a;在“互联网 ”浪潮的推动下&#xff0c;各行业正经历着深度融合与变革。互联网、新零售、云计算等新兴技术成为行业发展的关键驱动力。本文聚焦开源 AI 大模型 AI 智能名片 S2B2C 商城小程序这一创新模式&#xff0c;分析其在“互联网 ”背景下的内涵与优势&am…

ROS2通信机制实战——从“单向传数据”到“双向发请求”(二)

第2天&#xff1a;ROS2通信机制实战——从“单向传数据”到“双向发请求” 做机器人开发时&#xff1a;“为什么控制机器人前进用话题&#xff0c;而让机器人报位置要用服务&#xff1f;”其实答案很简单——ROS2的通信机制是“按需设计”的&#xff1a;话题适合高频、单向的数…

Function Calling(智能客服)

目录 1.0.思路分析 1.1.基础CRUD 1.1.1.数据库表 1.1.2.引入依赖 1.1.3.配置数据库 1.1.4.基础代码 2.定义Function 2.1.课程表的字段&#xff1a; 2.2.定义Function 2.3.System提示词 2.4.配置ChatClient 3.编写Controller 3.1.解决兼容性问题 3.2.AlibabaOpenA…

探索淀粉深加工的无限可能:2026 济南展览会前瞻

在全球农产品加工的广阔版图中&#xff0c;淀粉深加工产业犹如一颗璀璨的明珠&#xff0c;散发着日益耀眼的光芒。其产品广泛渗透于食品、饮料、医药、化工、能源等诸多领域&#xff0c;宛如一条条无形的纽带&#xff0c;将各个行业紧密相连。随着技术的日新月异、政策的大力扶…

STAGEWISE实战指南:从集成到使用的完整解决方案

文章目录 一、前言 二、集成STAGEWISE的实战过程 1. 初始配置问题 2. 依赖冲突处理 3. 组件导入问题 四、标准集成方案 1. 完整安装步骤 2. Vue项目集成步骤 (1) 修改App.vue文件 (2) 配置文件说明 五、最佳实践 1. 开发规范 2. 常见问题排查 五、总结 一、前言 在前端开发中,…

使用astah制作专业状态图及C/C++实现解析

<摘要> 本文详细解析如何使用astah专业工具绘制高质量的UML状态图&#xff0c;并建立与C/C代码的完整映射关系。内容涵盖状态图核心概念、astah工具实操指南、触发机制(Trigger)、守卫条件(Guard)和动作(Action)的代码实现解析&#xff0c;并通过一个完整的用户登录状态机…

C语言————函数递归(通俗易懂)

我们在学习些新的函数时&#xff0c;首先我们得理解它是什么&#xff1f;是怎么定义的&#xff1f;然后去了解他的用途&#xff0c;最后我们自己要会用&#xff0c;知道用在什么地方&#xff1f;什么时候用&#xff1f;用的时候要注意些什么&#xff1f;有一个条理清晰的学习逻…

路由基础(三):静态路由、动态路由、默认路由

静态路由 静态路由&#xff1a;管理员使用手工方式为路由器添加路由 三种添加静态路由的方式&#xff1a; 配置下一跳配置出接口出接口和下一跳都配置 备注&#xff1a;不配置出接口时&#xff0c;路由器会进行路由递归查询 #添加去往10.1.1.0网段的静态路由&#xff0c;下一跳…