策略
BTC 持仓拥挤度反转:反向交易 BTCUSDT.BINANCE 1H 当持仓量 + 资金费率联合 Z-Score 超过 ±2
结局: 已放弃
BtcPositioningCrowdednessReversalOiFundingJointZ
BTC 持仓拥挤度反转:反向交易 BTCUSDT.BINANCE 1H 当持仓量 + 资金费率联合 Z-Score 超过 ±2
假设
在 BTCUSDT.BINANCE USD-M 永续合约上的多空均值回归策略,使用 ONLY 补充衍生品数据(持仓量 + 资金费率)作为入场信号 — NO OHLCV 模式识别,NO 移动平均,NO 突破,NO 在本轮交易中已失败 10+ 次的"从业者模式"。假设:当持仓量异常升高(z-score > +2,滚动 30 天)AND 资金费率异常为正(z-score > +2,滚动 30 天)时,市场处于 CROWDED-LONG 状态,此时杠杆多头支付溢价资金以维持刚刚建立的仓位 — 从历史来看,随着边际买方耗尽且过度仓位多头成为被迫卖方,这种配置会均值回归。SYMMETRIC 反向:拥挤空头状态(两个 z-score 均 ≤ -2)倾向于向上回归。联合要求(BOTH 信号必须一致)充当结构性过拟合抑制器 — 单个 z 阈值有很多曲线拟合方式,但 TWO INDEPENDENT 数据源的联合 z 阈值要少得多,因为两个面必须同时在极端尾部对齐。填补 FOUR 低代表性桶:多空方向(14.2% → 朝向 45%),非 OHLCV 机制类(零失败使用联合仓位信号),中期持仓(24 小时周期),以及补充数据驱动(这利用了一个数据流 — OI + 资金费率 — BINANCE 始终拥有清洁覆盖,与已两次未通过 Layer 3 的现货 K 线不同)。使用 ONLY BINANCE USD-M 永续 K 线 + Postgres 存储的 OI 和资金费率数据(无 BINANCE_SPOT — 避免最近的失败模式)。仓位规模:每个方向占权益的 15%,单腿方向性交易。每笔交易风险:占权益的 1.5%,由止损封顶。
迭代 5 修复了 ONLY 报告的 Layer-3 sandbox_timeout,信号逻辑、阈值、导入、配置或仓位规模均无变化(这些都已通过 Layer 1-2 并达到 Layer 3)。超时来自 _zscore(),它在 721 元素的双端队列上,为 BOTH 个序列在 EVERY 约 20,000 根 K 线(~30M 解释的浮点运算)上重新计算 sum(buf) 和 sum((x-mean)**2 for x in buf)。它被 _RollingZ 取代,这是一个 O(1) 每根 K 线的累加器,在相同的固定窗口上保持运行总和与平方和,通过首次观测进行均值偏移以实现数值调节,每 4096 次推送时精确重新计算一次,以防止浮点漂移累积。在 OI 规模(1e6)和资金费率规模(1e-4)幅度的 9,000 次推送上,对旧暴力 z 的离线检查显示最大绝对 z 差异 1.8e-14,即数值上相同的 z-score,且 20,000 推送+读取现在耗时 0.09 秒而非数十秒。补充查找已经通过在 _ensure_supp 中一次性构建的数组上进行 bisect 实现 O(log n),所以没有其他每根 K 线的工作随历史规模扩展。
verification_loop: sandbox_timeout: 验证失败(Layer 3 — 沙盒回测):烟雾测试在约 20000 根 K 线的窗口内(833 天的 BTCUSDT.BINANCE-1-HOUR-LAST-EXTERNAL)超过了 300 秒的墙钟时间限制。这几乎总是意味着每根 K 线的工作量会随历史数据增长——例如,重新扫描完整的资金费率/补充数据序列,或在每根 K 线上都于 calculate_signal()/on_bar() 内重建列表并调用 min()/sorted()。在 __init__ 中预计算已排序的时间戳数组 ONCE 并使用 bisect,或按时间戳缓存查找结果,使每根 K 线的成本为 O(log n) 而非 O(n)。
实现
基于衍生品持仓数据驱动的 BTCUSDT.BINANCE USD-M 永续合约 1 小时 K 线多空均值回归策略。每根 K 线增量计算未平仓合约(sumOpenInterest)和资金费率的滚动约 30 天 z 分数;当 BOTH 超过 +entry_z(多头拥挤)时,策略做空;当 BOTH 低于 -entry_z(空头拥挤)时,策略做多。出现 4% 止损、5% 止盈、48 根 K 线时间止损,或拥挤度回落至 +/- exit_z 范围内时退出。仓位规模为权益名义金额的 15%,并设上限,使止损风险保持在权益的 <= 1.5%。入场不由任何 OHLCV 模式驱动;补充数据缺失时也不会回退到仅依据价格的策略(此时保持空仓)。
验证结果
sandbox_timeout: 验证失败(Layer 3 — 沙盒回测):烟雾测试在约 20000 根 K 线的窗口内(833 天的 BTCUSDT.BINANCE-1-HOUR-LAST-EXTERNAL)超过了 300 秒的墙钟时间限制。这几乎总是意味着每根 K 线的工作量会随历史数据增长——例如,重新扫描完整的资金费率/补充数据序列,或在每根 K 线上都于 calculate_signal()/on_bar() 内重建列表并调用 min()/sorted()。在 __init__ 中预计算已排序的时间戳数组 ONCE 并使用 bisect,或按时间戳缓存查找结果,使每根 K 线的成本为 O(log n) 而非 O(n)。
迭代历史
验证失败(Layer 2 — 合成场景): 使用的参数:['z_min', 'exit_z', 'tp_pct', 'entry_z', 'risk_pct', 'stop_pct', 'window_bars', 'min_notional', 'notional_pct', 'max_hold_bars', 'oi_tolerance_s', 'funding_tolerance_s'] 检查 __init__ 是否从 self.parameters.get() 设置了所有属性。 - steady_uptrend: TypeError: FactoryStrategy._bar_ts() 接受 1 个位置参数,但实际传入了 2 个(K 线时间戳:1735689840000) - steady_downtrend: TypeError: FactoryStrategy._bar_ts() 接受 1 个位置参数,但实际传入了 2 个(K 线时间戳:1735689840000) - flat_ranging: TypeError: FactoryStrategy._bar_ts() 接受 1 个位置参数,但实际传入了 2 个(K 线时间戳:1735689840000) - volatility_spike: TypeError: FactoryStrategy._bar_ts() 接受 1 个位置参数,但实际传入了 2 个(K 线时间戳:1735689840000) - zero_volume: TypeError: FactoryStrategy._bar_ts() 接受 1 个位置参数,但实际传入了 2 个(K 线时间戳:1735689840000) - price_gap: TypeError: FactoryStrategy._bar_ts() 接受 1 个位置参数,但实际传入了 2 个(K 线时间戳:1735689840000)
验证失败(Layer 2 — 合成场景): 使用的参数:['z_min', 'exit_z', 'tp_pct', 'entry_z', 'risk_pct', 'stop_pct', 'window_bars', 'min_notional', 'notional_pct', 'max_hold_bars', 'oi_tolerance_s', 'funding_tolerance_s'] 检查 __init__ 是否从 self.parameters.get() 设置了所有属性。 - steady_uptrend: TypeError: BtcPositioningCrowdednessReversalOiFundingJointZ._nearest() 接受 3 个位置参数,但实际传入了 4 个(K 线时间戳:1735689840000) - steady_downtrend: TypeError: BtcPositioningCrowdednessReversalOiFundingJointZ._nearest() 接受 3 个位置参数,但实际传入了 4 个(K 线时间戳:1735689840000) - flat_ranging: TypeError: BtcPositioningCrowdednessReversalOiFundingJointZ._nearest() 接受 3 个位置参数,但实际传入了 4 个(K 线时间戳:1735689840000) - volatility_spike: TypeError: BtcPositioningCrowdednessReversalOiFundingJointZ._nearest() 接受 3 个位置参数,但实际传入了 4 个(K 线时间戳:1735689840000) - zero_volume: TypeError: BtcPositioningCrowdednessReversalOiFundingJointZ._nearest() 接受 3 个位置参数,但实际传入了 4 个(K 线时间戳:1735689840000) - price_gap: TypeError: BtcPositioningCrowdednessReversalOiFundingJointZ._nearest() 接受 3 个位置参数,但实际传入了 4 个(K 线时间戳:1735689840000)
验证失败(Layer 3 — 沙盒回测):未产生任何交易 使用的 K 线类型:BTCUSDT.BINANCE-1-HOUR-LAST-EXTERNAL,处理的 K 线数:56856 诊断信息:should_enter() 在评估的 56852 根 K 线上返回了 0 次方向 -> 你的 ENTRY CONDITION 从未触发。请放宽入场逻辑/阈值。 确保你的策略使用给定的数据和参数产生交易。
验证失败(Layer 1 — 静态分析): - 前视偏差:通过 ABSOLUTE 距离 K 线时间戳选择补充观测值;如果后一个观测值比前一个更近,就会返回 NEXT 观测值。请使用 self.supp_as_of(key)(不晚于 K 线时间的最新值)或显式的 `ts <= bar.ts_init` 过滤条件——绝不能使用 abs()。(行号 None)
Stratmill 是研究与模拟交易工具,不提供财务建议,也不是经纪商。回测与模拟结果均为假设性结果。交易存在亏损风险。