策略
ETH OKX vn.py AtrRsiStrategy——冻结源默认参数的转换
结局: 已放弃
EthOkxFrozenAtrRsiStrategy
结局总结
EthOkxFrozenAtrRsiStrategy 尝试以相对于资金的仓位规模,忠实转换 vn.py 的 ATR/RSI 策略。五天验证冒烟测试的每笔交易结果为 -0.139%,共平仓 38 笔,盈利因子为 0.626。经过三轮迭代后,QA 仍发现入场和跟踪止损的执行与源策略不一致,因此在完整回测或优化前放弃。
假设
忠实转换用Python的交易员的 AtrRsiStrategy 信号和订单,采用 MIT 许可。来源:https://github.com/vnpy/vnpy_ctastrategy/blob/6ef76981624bf55b2ea978f8587f74d633aafc72/vnpy_ctastrategy/strategies/atr_rsi_strategy.py. 保留 atr_length=22、atr_ma_length=10、rsi_length=5、rsi_entry=16、trailing_percent=0.8 以及 fixed_size=1。使用 ETHUSDT.OKX 永续合约和已完成的 1-MINUTE K线,与源策略默认的逐笔到分钟 BarGenerator 一致。不进行更高周期聚合、不增加筛选条件,也不拟合参数。平台仓位规模是明确授权的适配:fixed_size=1 表示一个相对于资金的配置,入场时按当前权益的 10% 名义金额计算,并向下取整至交易品种数量精度。持仓数量保持不变,直至退出;绝不加仓。配置杠杆=1.0。初始权益为 $100,000。源策略初始化时请求十天历史K线;维护一个滚动的 100 根K线 ArrayManager 等效缓冲区,并在其初始化前禁止交易。日志和事件回调不产生信号;订单及止损单回调除此之外均不执行操作。
提交内容给出了可执行的入场和出场规则。用户对忠实复现的要求优先于为了满足多样性配额而另造机制。OKX 的占比为 2.3%,低于 5% 的目标;该策略允许双向交易,而该投资组合则设为 82.6% 的纯多头组合。语料集中度为空,因此无法确认品种层面的新颖性。ETH 使固定的五个价格单位订单偏移相比低价山寨币更为适度。这是在检验波动扩张动量,而非失败的 BTC Connors-RSI 均值回归。经济可行性仍未经验证;必须允许源策略默认参数失败,不得事后补救。
verification_loop:验证失败(第 4 层 — QA审查)[类别=hypothesis_mismatch]: - [edge_concern] 五天冒烟测试在 38 个已平仓头寸中录得每笔交易 -0.139%,并有 PF 0.626。完整历史评估应检查换手率和移动止损回吐;这些结果本身不会阻止该策略。 - [严重] 穿越止损的回退处理未能保留源执行方式。_submit_exit() 会立即调用 close_position();OKX 配置的延迟为零,因此 Nautilus 会在决策 K 线收盘时按当前市场价格执行,而不是在下一根 K 线开盘时执行。此外,vn.py 会根据下一根 K 线的区间检查重新设置的止损:价格跳空回到多头止损位上方,可能导致止损未触发。无条件市价平仓改变了执行时机和触发条件。来源:https://raw.githubusercontent.com/vnpy/vnpy_ctastrategy/6ef76981624bf55b2ea978f8587f74d633aafc72/vnpy_ctastrategy/backtesting.py(第 163 行)— 修复:实现按源逻辑运行的待触发止损,并根据后续市场数据进行评估,以保留条件触发和跳空价格执行。如有必要,添加引擎执行钩子;不要替换为立即市价平仓。验证两个方向上的普通穿越、跳空穿越和跳空远离情况。 - [严重] BUY 在收盘价+$5处的限价单和 SELL 在收盘价-$5处的限价单,提交到 Nautilus 当前收盘价订单簿时都属于可成交订单。在 post_only=False 且 OKX 延迟为零的情况下,它们可能在信号 K 线上成交。源回测器会先撮合已有订单,再调用 on_bar,因此新生成的限价单最早要到后续 K 线才符合成交条件,同时仍受价格限制。这会改变入场、跳空处理和之后的移动止损状态。来源:https://raw.githubusercontent.com/vnpy/vnpy_ctastrategy/6ef76981624bf55b2ea978f8587f74d633aafc72/vnpy_ctastrategy/backtesting.py(第 144 行)— 修复:按原始限价和按入场规模确定的数量,在后续 K 线上激活订单。验证入场不会在信号 K 线上成交;如果下一根 K 线跳空越过限价,则除非之后的价格区间触及限价,否则开盘时不得成交。
实现
对 vn.py AtrRsiStrategy 的冻结翻译,使用 ETHUSDT.OKX 1 分钟 K 线。当 ATR(22) 高于其 10 根 K 线均值,且 RSI(5) 高于 66(或低于 34)时,以收盘价 +/- $5(空头则取镜像方向)提交限价单入场。唯一的退出方式是每根 K 线都会更新的 0.8%移动止损。每次入场的名义金额按权益的 10% 确定。
第 3 轮修复了 QA 的严重缺陷。场所会拒绝已经越过K线收盘价的更新跟踪止损(reject_stop_orders=True),这使仓位没有退出方式。现在,如果止损价位已经越过(多头 stop >= 收盘价,空头 stop <= 收盘价),策略会在下一根K线上通过仅减仓市价单平仓。这与 vn.py 的行为一致:此类止损会在下一根K线上触发,成交价约为开盘价。否则,更新后的 STOP_MARKET 会像之前一样留在场所等待成交。作为安全措施,如果任何 STOP_MARKET 被拒绝,on_order_rejected 会将仓位平掉。入场逻辑、指标、仓位规模和所有冻结参数均未改变。QA 还提出了边界问题:1 分钟K线、两边都按吃单方费率成交、每笔交易最多回吐 0.8%。这是冻结源默认参数的特性;假设要求允许其失败,不做补救。没有进行调优。
验证结果
验证失败(第 4 层 — QA审查)[类别=hypothesis_mismatch]: - [edge_concern] 五天冒烟测试在 38 个已平仓头寸中录得每笔交易 -0.139%,并有 PF 0.626。完整历史评估应检查换手率和移动止损回吐;这些结果本身不会阻止该策略。 - [严重] 穿越止损的回退处理未能保留源执行方式。_submit_exit() 会立即调用 close_position();OKX 配置的延迟为零,因此 Nautilus 会在决策 K 线收盘时按当前市场价格执行,而不是在下一根 K 线开盘时执行。此外,vn.py 会根据下一根 K 线的区间检查重新设置的止损:价格跳空回到多头止损位上方,可能导致止损未触发。无条件市价平仓改变了执行时机和触发条件。来源:https://raw.githubusercontent.com/vnpy/vnpy_ctastrategy/6ef76981624bf55b2ea978f8587f74d633aafc72/vnpy_ctastrategy/backtesting.py(第 163 行)— 修复:实现按源逻辑运行的待触发止损,并根据后续市场数据进行评估,以保留条件触发和跳空价格执行。如有必要,添加引擎执行钩子;不要替换为立即市价平仓。验证两个方向上的普通穿越、跳空穿越和跳空远离情况。 - [严重] BUY 在收盘价+$5处的限价单和 SELL 在收盘价-$5处的限价单,提交到 Nautilus 当前收盘价订单簿时都属于可成交订单。在 post_only=False 且 OKX 延迟为零的情况下,它们可能在信号 K 线上成交。源回测器会先撮合已有订单,再调用 on_bar,因此新生成的限价单最早要到后续 K 线才符合成交条件,同时仍受价格限制。这会改变入场、跳空处理和之后的移动止损状态。来源:https://raw.githubusercontent.com/vnpy/vnpy_ctastrategy/6ef76981624bf55b2ea978f8587f74d633aafc72/vnpy_ctastrategy/backtesting.py(第 144 行)— 修复:按原始限价和按入场规模确定的数量,在后续 K 线上激活订单。验证入场不会在信号 K 线上成交;如果下一根 K 线跳空越过限价,则除非之后的价格区间触及限价,否则开盘时不得成交。
实现待处理的源策略风格止损,并根据后续市场数据评估,保留有条件触发和跳空价格执行。必要时添加引擎执行钩子;不要替换成即时市价平仓。验证多空双方的普通穿价、跳空穿越和跳空远离情形。
交叉止损回退方案未能保留源策略的执行方式。_submit_exit() 会立即调用 close_position();OKX 配置的延迟为零,因此 Nautilus 会在决策K线收盘时按当前市场价格执行,而不是在下一根K线开盘时执行。此外,vn.py 会根据下一根K线的区间检查更新后的止损:价格跳空回到多头止损位上方时,止损可能不会触发。无条件市价平仓改变了执行时机和触发条件。来源:https://raw.githubusercontent.com/vnpy/vnpy_ctastrategy/6ef76981624bf55b2ea978f8587f74d633aafc72/vnpy_ctastrategy/backtesting.py
按原始限价和按入场规模确定的数量,设置在后续K线上生效。验证信号K线上不会有入场成交;若下一根K线跳空越过限价,除非之后的区间触及限价,否则开盘时不得成交。
BUY 在收盘价+$5处的限价单和 SELL 在收盘价-$5处的限价单,提交到 Nautilus 当前收盘价订单簿时都属于可成交订单。在 post_only=False 且 OKX 延迟为零的情况下,它们可能在信号 K 线上成交。源回测器会先撮合已有订单,再调用 on_bar,因此新生成的限价单最早要到后续 K 线才符合成交条件,同时仍受价格限制。这会改变入场、跳空处理和之后的移动止损状态。来源:https://raw.githubusercontent.com/vnpy/vnpy_ctastrategy/6ef76981624bf55b2ea978f8587f74d633aafc72/vnpy_ctastrategy/backtesting.py
迭代历史
验证失败(第 1.5 层——假设/配置一致性)[类别=hypothesis_mismatch]: - optimization_plan 将杠杆固定为 1.0
调用 _submit_stop_market 前,检查止损是否已经越过。多头检查 stop >= current_close;空头检查 stop <= current_close。若已越过,则调用 self._submit_exit(position)(仅减仓市价平仓),这与 vn.py 下一根K线触发止损的行为一致。否则,像现在一样提交等待中的止损。作为安全措施,也应跟踪被拒绝的止损订单,例如在 on_order_rejected 中,并将仓位平掉。
移动止损每根 K 线都会作为独立的 STOP_MARKET 重新提交,多头止损位为 intra_trade_high*(1-0.8%)(空头则为 intra_trade_low*(1+0.8%))。该价位包含当前 K 线的最高价(或最低价)。如果 K 线收盘价比自身最高价低超过 0.8%,新的多头止损在提交时就已经处于市场中。OKX 回测场所使用 NautilusTrader 的默认设置 reject_stop_orders=True;在 engine.pyx 的 _process_stop_market_order 中,已触发的止损会被 REJECTED,而不是成交。should_exit() 总是返回 False,因此该头寸在该 K 线上没有任何平仓操作。后续 K 线上,止损价位只会上升(多头)或下降(空头),因此它会持续处于市场中并不断被拒绝,直到价格回升至其上方。该头寸可能无限亏损。在 vn.py 中,同一止损会在下一根 K 线上触发,并以接近开盘价的价格成交。因此,假设中唯一的退出方式——0.8%移动止损——未能可靠实现。这恰好影响策略所选择的波动性 ATR>ATR_MA市场状态,包括信号 K 线带有长影线并成为首个止损 K 线的情况。为期 5 天的沙盒测试恰好没有遇到这种情况(最大亏损为名义金额的 -0.96%),但在约 2,444 天的 1 分钟 ETH 数据中就会遇到。
无需更改;已记录,供分析人员参考。
entry_price_offset 是固定的 $5。这约为 ETH 在其整个历史价格中的 0.13-0.33%,因此入场限价总会穿越并在下一根 K 线上以吃单方身份成交。这忠实于源逻辑,不是缺陷。请注意,vn.py 按 min(限价, 下一根 K 线开盘价) 成交,Nautilus 的表现也类似。
结局总结
忠实转换必须保留后续K线订单的生效资格、有条件的止损触发、跳空执行以及指标计算。
经过三次迭代,Layer 4 QA 因假设不匹配而拒绝了该译文:止损触发后的市价退出改变了策略执行时机和触发条件,而可成交的入场限价单可能会在信号所在的K线内成交。冒烟测试中的亏损是关于策略优势的顾虑,并非独立的阻碍。
将 vn.py 的源默认 ATR/RSI 策略转换至 ETHUSDT.OKX 一分钟永续合约K线,保留其信号和订单,并以 10% 的权益及 1.0 杠杆确定入场仓位规模。
一项为期五天的验证冒烟测试记录了 38 个已平仓头寸,每笔交易 -0.139%,盈利因子为 0.626。尚未进行完整回测、优化、分析师评估和风险审查。
放弃原因
verification_loop:验证失败(第 4 层——QA审查)[类别=hypothesis_mismatch]: - [edge_concern] 五天冒烟测试的每笔交易结果为 -0.139%,共平仓 38 笔,PF 0.626。完整历史评估应检查换手率和跟踪止损回吐;这些结果本身不会阻止该策略。 - [严重] 交叉止损回退方案未能保留源策略的执行方式。_submit_exit() 会立即调用 close_position();OKX 配置的延迟为零,因此 Nautilus 会在决策K线收盘时按当前市场价格执行,而不是在下一根K线开盘时执行。此外,vn.py 会根据下一根K线的区间检查更新后的止损:价格跳空回到多头止损位上方时,止损可能不会触发。无条件市价平仓改变了执行时机和触发条件。来源:https://raw.githubusercontent.com/vnpy/vnpy_ctastrategy/6ef76981624bf55b2ea978f8587f74d633aafc72/vnpy_ctastrategy/backtesting.py(第 163 行)——修复:实现待处理的源策略风格止损,并根据后续市场数据评估,保留有条件触发和跳空价格执行。必要时添加引擎执行钩子;不要替换成即时市价平仓。验证多空双方的普通穿价、跳空穿越和跳空远离情形。 - [严重] BUY 的收盘价+$5限价单和 SELL 的收盘价-$5限价单,在提交至 Nautilus 当前收盘价订单簿时都是可立即成交的限价单。由于 post_only=False 且 OKX 延迟为零,它们可能在信号K线上成交。源回测器会先撮合已有订单,再调用 on_bar,因此新生成的限价单最早要到下一根K线才具备成交资格,同时仍受限价约束。这会改变入场、跳空处理及后续跟踪止损状态。来源:https://raw.githubusercontent.com/vnpy/vnpy_ctastrategy/6ef76981624bf55b2ea978f8587f74d633aafc72/vnpy_ctastrategy/backtesting.py(第 144 行)——修复:按原始限价和按入场规模确定的数量,设置在后续K线上生效。验证信号K线上不会有入场成交;若下一根K线跳空越过限价,除非之后的区间触及限价,否则开盘时不得成交。
分析
AtrRsiStrategy
Stratmill 是研究与模拟交易工具,不提供财务建议,也不是经纪商。回测与模拟结果均为假设性结果。交易存在亏损风险。