跳至正文
全部策略

策略

Binance USD-M 日内波动率扩张突破(主流币种,15 分钟,ATR 触发的大幅波动过滤器,ATR 跟踪止损,多空)

结局: 已放弃

IntradayVolatilityExpansionBreakoutMajorsLS15m

语义审计器发现的代码↔假设错位——代码并未 NOT 实现该假设。请重新编写策略以实现假设 EXACTLY(标的、时间框架、方向、所命名的优势/机制、sizing)。具体问题:假设预先将过滤器的选择性注册为设计属性("严格的过滤器将交易频次保持在较低水平(每个标的每周数笔,而非每天数百笔)"),但实现的过滤器并不具有该选择性:total_trades=16069,且 src/backtesting/metrics.py:724 中的…

假设

在 15 分钟K线上的短周期、多空趋势/突破策略,覆盖 Binance USD-M 三大主流品种(BTC、ETH、SOL),旨在填补代表性不足的 short_1m_15m 周期区间 WITHOUT,即落入手续费主导陷阱(该陷阱会扼杀所有天真的日内K线策略)的区间。核心思路:仅参与 GENUINE 波动率扩张——K线以 ATR 的 LARGE 倍数突破近期日内区间,因此每笔入场都跟随一笔远超 ~0.10% 往返手续费的行情变动;严格的过滤器将交易频次保持在较低水平(每个标的每周数笔,而非每天数百笔)。这与工厂所推广的优势(即夏普-1.48 趋势篮子)使用相同的、经验证的趋势/突破原语,只是改为日内节奏,以捕捉日线策略所遗漏的短周期延续。该策略刻意只在唯一可可靠回测的表面上运行——Binance USD-M 主流品种、纯 OHLCV、完整历史——避开本次会话遭遇的每一项基础设施障碍(Deribit 期权、COIN-M 反向合约 sizing、Hyperliquid 山寨币K线、清算 live-WS-only、多腿资金费率 primary-only)以及每一类已被反驳的策略(无资金费率、无基差、无比率 MR、无期权)。多空(每个标的的方向性突破)改善了组合的 87%-long 偏度;ATR 门控的大幅波动要求即为明确的手续费主导防御;少量参数可抗过拟合。

这是一次代码未变的干净重启,而未变的哈希值会直接导致验证失败,因此我没有做表面修改,而是查找实际缺陷。我在订单仓位规模计算中发现了一个问题。所有资产的数量都使用统一的默认精度 2 位小数进行舍入,这不仅比交易场所允许的精度更粗,而且在小数量时会造成彻底破坏:我确认 Python 的 round(0.0049, 2) 等于 0.0,因此任何低于约 0.005 BTC 的 BTC 入场数量都会归零,并被现有的 `if qty <= 0: return` 守卫条件静默丢弃,既无日志,也无诊断计数器。这不是假设——风险平价仓位规模计算会用固定风险预算除以基于 ATR 的止损距离,因此本策略专门设计来交易的高波动率市场恰好会产生最小数量;任何回撤导致权益缩水后,这种影响还会叠加。我查阅了目录中的合约定义,而不是凭空假设:BTCUSDT size_precision 5,ETHUSDT 4,SOLUSDT 3。修复方法是增加一个小型缓存辅助函数 _prec_for(),先使用合约自身的 size_precision 进行舍入;若无则回退到已配置的 qty_precision 映射,最后再回退到 default_qty_precision;每种资产只解析一次,因此每根 K 线的处理路径仍为 O(1)。我还在配置中明确设置了每种资产的正确精度,作为额外的后备措施。其余代码与已通过前序层验证的代码逐字节一致:唐奇安突破门槛、ATR 扩张过滤器、跟踪止损和最大持仓时长退出、风险平价预算、单仓和总敞口上限、解决此前墙钟超时问题的增量式 ATR/唐奇安通道缓存,以及无实际作用的单仓挂钩。导入项未变,也没有引入禁用的导入。我添加了覆盖优化器所有可调整参数的 _param_bounds,确保其搜索范围不超出预期区间。

再次清算——不可优化,且此前已因同一原因放弃过。账户在与第 1 轮完全相同的日期(2020-12-30)归零(LIQUIDATED),再次在第一年内爆仓(total_return -100%,max_drawdown 100%,随后约 5.7 年处于持平/停摆状态),这证明第 -2 轮的订单规模精度调整只是转移视线,并未解决根本原因。其机制是 15 分钟级过度交易导致手续费灾难:15,962 笔交易,手续费占毛收益的 20.23%($80k),另有 $68k 冲击成本;avg_trade_return_pct -0.023%(净值为负),profit_factor 0.70,夏普比率 -1.06(CI [-2.99,-0.86]),PSR 0.0,return_kurtosis 1982,在每种波动率状态下均为负值——ATR 扩张门槛未能充分减少交易次数,无法摆脱手续费主导,而风险仓位计算又使亏损不断累积,最终导致爆仓。这是 L18/L30 纯-OHLCV 15 分钟级手续费坟场;账户归零后,任何参数调整都无法挽救。失败模式:risk_reject/fee_edge 清算的 15 分钟过度交易突破策略,重演第 -1 轮放弃时的情况。

实现

在 15 分钟 K 线上运行的日内多空波动率扩张突破策略,覆盖 Binance 流动性最高的三个 USD-M 主流币种(BTC、ETH、SOL),采用纯 OHLCV。每种资产独立管理,并由各自 K 线到达事件驱动。入场需要同时满足两个条件:K 线必须突破前 channel_length 根 K 线的唐奇安通道(创出 N 根 K 线新高则做多,创出 N 根 K 线新低则做空)AND 且 K 线的方向性实体必须大于 expansion_atr_mult x ATR,因此只有真正的波动率扩张——即已远超约 0.10% 往返手续费的走势——才能触发交易。这种双重过滤可防止手续费主导,并将交易次数控制在每种资产每周几笔,而非每天数百笔。盈利头寸通过 ATR 跟踪止损持有,止损锚定入场后的最佳有利变动,并受 32 根 K 线(约 8 小时)最大持仓时长限制。仓位采用风险平价:调整每个交易簿的规模,使其止损距离对应的风险等于权益的 risk_frac,单个头寸上限为 max_position_frac,整个组合总敞口上限为 1.0x,因此不使用杠杆。ATR 和唐奇安通道均增量维护,并按资产每根 K 线缓存一次,使每根 K 线的计算成本为 O(1),热路径中不使用 numpy。

验证结果

CLEAN RESTART 2026-09-04——本次运行的判定历史和学习记录已移除,并从验证阶段重新启动。此前放弃该策略是由流水线问题导致,而非市场因素:Layer-2 测试框架错误绑定了 @staticmethod 辅助函数(已修复);QA 在未经优化的冒烟测试上给出了终局性能判定(已移除——现在 QA 只判断正确性);沙盒超时则源于回测槽位匮乏(已修复)。假设和策略代码均未改变。请根据代码本身的优劣进行验证;性能将在之后由完整回测和优化器判定。

回测评审

夏普
-1.06
总收益率
-100.00%
最大回撤
100.00%
总交易数
15962
胜率
33.9%
盈利因子
0.70

简洁的增量式 ATR/唐奇安通道工程实现;大量交易使负面结果在统计上具有决定性

在 SAME 日期(2020-12-30)以迭代 1 再次复盘账户 LIQUIDATED:total_return -100%,max_drawdown 100%,CAGR -100%——精度修复并未触及根本原因

手续费/冲击成本灾难:手续费占毛收益的 20.23%($80k),另有 $68k 冲击成本,涉及 15,962 笔交易;avg_trade_return_pct -0.023%(负值),profit_factor 0.70

结论明确为负:夏普比率 -1.06(CI [-2.99,-0.86]),PSR 0.0,return_kurtosis 1982,连续亏损 28 笔,在每种波动率状态下均为负值

L18/L30 纯-OHLCV 15 分钟级过度交易手续费坟场;ATR 扩张门槛未能将交易次数控制在足够低的水平,无法摆脱手续费主导

分析

语义审计器发现的代码↔假设错位——代码并未 NOT 实现该假设。请重新编写策略以实现假设 EXACTLY(标的、时间框架、方向、所命名的优势/机制、sizing)。具体问题:假设预先将过滤器的选择性注册为设计属性("严格的过滤器将交易频次保持在较低水平(每个标的每周数笔,而非每天数百笔)"),但实现的过滤器并不具有该选择性:total_trades=16069,且 src/backtesting/metrics.py:724 中的 `total_trades = len(positions_report)` 统计的是已完成的往返交易,而非成交。三个声明标的的目录历史为 BTCUSDT 15m 2019-12-31→2026-09-02,ETHUSDT 类似,SOLUSDT 2020-09-14→2026-09-02 ≈ 19 asset-years ≈ 1000 asset-weeks,每标的每周约 16 笔往返交易(约每标每天 2.3 笔)——约为所述节奏的 5x 倍,若窗口结束前权益被清零(total_return=-100%),则更高。expansion_atr_mult=1.0 处的 close>donch_high AND |close-open| >= 1.0*ATR 过滤器放行约 2% 的K线事件,因此代码并未交付假设所指定的交易频率属性。

迭代历史

验证失败(Layer 2——合成场景): 使用的参数:['assets', 'risk_frac', 'atr_period', 'trail_mult', 'min_notional', 'max_hold_bars', 'qty_precision', 'channel_length', 'gross_cap_frac', 'max_position_frac', 'expansion_atr_mult', 'default_qty_precision'] 请检查 __init__ 是否从 self.parameters.get() 设置了所有属性。 - steady_uptrend: TypeError: super(type, obj): obj must be an instance or subtype of type(K 线时间戳:1735689600000) - steady_downtrend: TypeError: super(type, obj): obj must be an instance or subtype of type(K 线时间戳:1735689600000) - flat_ranging: TypeError: super(type, obj): obj must be an instance or subtype of type(K 线时间戳:1735689600000) - volatility_spike: TypeError: super(type, obj): obj must be an instance or subtype of type(K 线时间戳:1735689600000) - zero_volume: TypeError: super(type, obj): obj must be an instance or subtype of type(K 线时间戳:1735689600000) - price_gap: TypeError: super(type, obj): obj must be an instance or subtype of type(K 线时间戳:1735689600000)

验证失败(Layer 3——沙盒回测):冒烟测试超过了 300 秒的墙钟时间限制。这几乎总是意味着每根 K 线的工作量会随历史长度增长——例如反复扫描完整的资金费率/补充序列,或在每根 K 线上于 calculate_signal()/on_bar() 内重建列表并调用 min()/sorted()。在 __init__ 中预先计算已排序的时间戳数组 ONCE 并使用 bisect,或按时间戳缓存查询结果,使每根 K 线的成本为 O(log n),而非 O(n)。

Stratmill 是研究与模拟交易工具,不提供财务建议,也不是经纪商。回测与模拟结果均为假设性结果。交易存在亏损风险。