syyyyy

OOS-Gauntlet 数据驱动审计方法(仅供参考)

  •  
  •   syyyyy · 12h 56m ago · 184 views

    OOS-Gauntlet 数据驱动审计方法

    一套用于"决定要不要改策略"的证伪流程。核心一句话:任何"改动会变好"的假说, 先用它自己的数据尽力推翻它,推翻不掉才部署。 2026-06-05 整理,源自黑名单审计 / WLD 调查 / range_break_probe 关闭等一系列实战。


    1. 背景:为什么需要这套方法

    量化策略的每一次改动——加黑名单、加 gate 、关闭某个 mode 、按某指标缩 sizing—— 背后都是一个假说:"这样改,整体会变好"。这些假说往往来自对历史数据的观察: 某个币一直亏、某个信号胜率低、某个 confidence 区间表现差。

    陷阱在于:历史数据里看到的"规律",大部分是假的。 它可能是:

    • 单日/单时段的运气:某币在某一天爆亏 -24,看起来很差,但那是当天的市场事件,不可外推。
    • 单个 symbol 的巧合:某"类型"的币赚钱,拆开发现整类只有 1 个币在赚,其余在亏。
    • 聚合数字的假象:"全市场关闭 X 改善 +98%",拆到 symbol 级发现主流币其实在赚,+98% 是被少数大亏 symbol 拉出来的。
    • 不携带 edge 的维度:confidence 看起来高就该赚,但 held-out 测试发现 confidence 根本不 rank edge(甚至反向)。

    这个项目反复栽在这些坑里(都有记录):confidence floor 假说被双轮 OOS 证伪、 funding-squeeze 信号三重收敛却死于 90 天全市场 OOS 、多个"利润集中"结论其实是 STG/LAB 两个币的尾部运气。每一次"我从数据里发现了规律"的兴奋,都需要先被 怀疑。 这套方法就是把怀疑系统化。


    2. 核心方法:OOS-Gauntlet(样本外多重关卡)

    OOS = Out-Of-Sample(样本外)。Gauntlet = 一连串必须逐个通过的关卡。一个假说要 活下来,必须连续通过下面每一关——任何一关翻车,假说就被否决。

    假说(从 in-sample 数据挖出)
      │
      ├─ 关卡 1: in-sample 时段分布  —— 亏损/盈利是集中单日(regime),还是跨多日(系统性)?
      │
      ├─ 关卡 2: OOS 多窗口          —— 换 2-3 个独立时段(fetch --end-date)重测,方向一致吗?
      │
      ├─ 关卡 3: 多 symbol           —— 同一结论在 ≥3 个不同 symbol 上都成立,还是单 symbol 假象?
      │
      ├─ 关卡 4: 对照基准            —— 同期 crypto 对照(SOL/AVAX)是什么表现?排除大盘 regime 。
      │
      ├─ 关卡 5: 拆穿聚合            —— 整体数字拆到 symbol/时段级,赢家是不是少数尾部撑的?
      │
      └─ 关卡 6: 端到端 live 验证    —— 部署后真在 live 生效吗?(不只单元测/backtest)
    

    关键原则:每加一关,样本就更"样本外"一点。 in-sample 是你挖假说的那段数据 (必然支持假说,因为假说是从它挖的);OOS 多窗口排除时段运气;多 symbol 排除单币 巧合;对照排除大盘;拆聚合排除尾部;端到端排除"代码根本没生效"。


    3. 用了哪些模块的数据,为什么这样用

    数据源 是什么 在方法里的角色 为什么用它
    reports/runtime/income_ledger/ 交易所返回的真实已实现 PnL(REALIZED_PNL 事件) 实盘真值:某币/某 mode 真实赚亏 唯一不掺假的真金白银;但必须聚合回 trade(事件级会被分批止盈骗)
    reports/runtime/shadow_trades/ 影子交易:被 gate block / HOLD 的信号的 counterfactual(假如开了会怎样)的模拟 PnL 黑名单/关闭候选的"假如交易"依据 黑名单币不实盘→信号被 block→shadow 记录"假如不黑会怎样",这是判断"该不该解黑"的直接证据
    reports/runtime/decision_journal/ 每个决策的完整 metadata(regime/strategy_mode/confidence/各质量指标/git_sha/blocked_by) 归因 + live 验证:某改动 live 是否生效、决策按 git_sha 分布 含 git_sha,能区分"部署前 vs 部署后"的决策,做 live A/B;含丰富质量指标供 rank-edge 分析
    reports/backtests/*/trades.csv 回测逐笔成交(symbol/side/pnl/confidence/regime/strategy_mode/entry_time) OOS 多窗口 + 多 symbol 的主力:可控时段(--end-date)、可控 flag(env) 一体记录"入场条件 + 出场 PnL",无手动平仓污染,可批量跑多 symbol × 多时段
    Binance exchangeInfo(underlyingType / underlyingSubType) 交易所对每个 symbol 的官方分类(EQUITY/COIN/COMMODITY / DeFi/AI/Layer-1/Infrastructure...) 跨 symbol 归类:把单 symbol 结论提升到"类型"维度验证 当内部 symbol_group 全是 default 无区分力时,交易所的官方分类提供了正交的归类维度(但要防单 symbol 假象)

    为什么 shadow 和 income 要分开看: income 是实盘开了仓的真值,shadow 是被拦下来 的 counterfactual 。黑名单币不实盘(income 没数据),只能靠 shadow 判断"解黑后会怎样"; 而"该不该加黑"要看实盘 income + backtest 。两者互补,缺一不可。

    为什么必须聚合回 trade: income_ledger 是 REALIZED_PNL 事件流,一笔仓分批止盈 会产生多个事件。如果按事件算胜率/payoff,会被"小额分批止盈"骗出虚高胜率。必须 按 symbol+时间窗聚合回 trade 级再统计。


    4. 两个具体事例

    事例 A:DRIFT 该不该加黑名单 —— in-sample 假阳性被 OOS 推翻

    假说(从 in-sample 挖出): DRIFT 是黑名单候选。shadow 看它 -16.5 、实盘 income -8.5,合计昨日 -24.6,是当天最差的 symbol,看起来铁定该黑。

    逐关验证:

    1. 关卡 1(时段分布): DRIFT 的 -24.6 全部集中在 06-04 单日,其余日期几乎无活动 → 强烈的单日 regime 信号,不像系统性。
    2. 关卡 2(OOS 多窗口):fetch --end-date 拉两个独立时段回测 DRIFT:
      • OOS 窗口 1(04-30~05-10):+13.15
      • OOS 窗口 2(04-05~04-15):+90.66
      • 两个样本外时段 DRIFT 都大赚!
    3. 结论: in-sample 的 -24.6 是 06-04 单日市场事件,不可外推。加黑名单会错失 OOS 那 +90 的盈利。DRIFT 不加黑。

    这就是 in-sample 假阳性的典型:单日爆亏被误读成"这币系统性差"。如果只看挖假说 的那一天就拍板,会做出完全错误的决定。

    事例 B:range_break_probe 该不该关闭 —— subType 单 symbol 假象被多 symbol OOS 拆穿

    假说演进(层层深入): range_break_probe(RANGING regime + 均值回归失败后转去追 区间突破)整体负 EV,该关。但"整体关闭"在某些 symbol 上反而亏(主流币的 probe 在 赚),于是怀疑 EV 是 symbol 依赖的。进一步用 Binance underlyingSubType 拆,发现:

    subType in-sample(少 symbol) 看起来
    Infrastructure +29(wr75%) 赚!该保留
    Layer-1 +20(wr57%) 赚!该保留

    看起来可以做"subType-aware gate":只关亏的 subType,保留赚的。但加一关:

    1. 关卡 3(多 symbol): Infrastructure 之前的 +29 全部来自 LINK 一个 symbol。 换成多 symbol(BAT/LINK/MASK)跑 OOS:
      • Infrastructure: +29 → -32(wr 0%) ← 完全反转!
      • Layer-1: +20 → +0.4(breakeven) ← edge 消失
      • 所有 subType 多 symbol OOS 全部亏或打平。
    2. 结论: "subType 区分"是单 symbol 假象——Infrastructure=LINK 、AI=WLD 、 DeFi=DRIFT,每类只 1 个 symbol 时,"subType 信号"其实是"那个 symbol 的信号" 伪装的。range_break_probe 普遍负 EV(概念性:RANGING 追假突破),全局关闭。

    这是事例 A 的同一个陷阱换了维度:单日 → 单 symbol 。用户的洞察(用交易所 subType 数据细分)方向对,但必须配多 symbol OOS,否则会被单 symbol 假象骗去做一个 错误的 subType gate 。


    5. "OOS 一致"的作用:照妖镜

    整套方法的判据可以浓缩成一句话:

    跨窗口、跨 symbol 一致 = 真信号;一翻转/只靠单点 = 方差假象。

    • DRIFT:in-sample -24.6 但 OOS 两窗口 +13/+90 → 不一致(翻转) → 假阳性,不加黑。
    • BZ/NATGAS:in-sample shadow 负 + OOS-1 负 + OOS-2 负,三窗口一致 + 多 symbol + 对照 SOL 同期正 → 真系统性亏 → 加黑。
    • Infrastructure:LINK 单 symbol +29,换多 symbol → -32 → 不一致 → 单 symbol 假象。
    • range_break_probe:所有 subType 多 symbol OOS 一致亏 → 真普遍负 EV → 关闭。

    "一致"之所以是照妖镜,是因为方差(运气)在不同时段/不同 symbol 上方向随机—— 你换个窗口、换批 symbol,运气就洗掉了,只有真实的 edge/loss 才会在所有切片上同向 保留。一个结论能在 3 个独立时段 + 3 个不同 symbol + 对照组上都同向,它是运气的概率 就极低了。

    反过来,任何"只在一个时段/一个 symbol 上成立"的结论,默认当方差,不部署。 这也解释了为什么聚合数字(全市场 +98%)危险:聚合把不一致藏起来了,必须拆开看每个 切片是否一致。


    6. 我是如何想到这套方法的

    不是一开始就有的,是被历次失败逼出来的:

    1. confidence floor 的双轮 OOS 死亡让我学到:in-sample 挖出的"好区间",必须用 pre-registered 的 held-out OOS 去打——而且要双轮(0.62 死于 OOS-1,我换 0.65 又死于 OOS-2)。一轮 OOS 不够,赢家会"刚好"过第一轮。→ 催生多窗口

    2. funding-squeeze 三重收敛却死于全市场 OOS让我学到:机制合理 + 学术支持 + 样本验证(三重收敛)都不等于 robust,横截面 demean(扣大盘)后才见真章。→ 催生 对照基准(排除大盘 regime)。

    3. STG/LAB 尾部运气让我学到:"整体盈利"可能是 2 个币撑的,去掉就转负。聚合 会骗人。→ 催生拆穿聚合(拆到 symbol/时段级)。

    4. momentum_tilt 的 stale-code 事故(单元测过、reviewer 过,但部署后 count 仍 0, 因为改动根本没进数据流)让我学到:observability/flag 改动,单元测和 source-guard 都可能放过"代码没真生效"。→ 催生端到端 live 验证(这次也立刻抓到了 "flag-on/off backtest 完全相同 = 云端没 pull 新代码")。

    5. 这次 range_break_probe 里单 symbol 假象(Infrastructure=LINK)是新增的一关: 当我想用 subType 做精细化时,意识到"每个 subType 几个 symbol?"——只 1 个就是 symbol 伪装。→ 催生多 symbol关卡。

    一句话总结思路: 每次我对一个数据发现感到兴奋、想立刻部署时,就强迫自己问 "这个结论,换个时段还成立吗?换批 symbol 还成立吗?拆开看每个切片还一致吗? 部署后真生效吗?"——把每一次踩过的坑变成一道固定关卡。方法的价值不在于找到新 alpha,而在于拦住那些看起来像 alpha 、实际会亏钱的假象


    7. 落地工具速查

    • 拉独立时段数据:fetch_backtest_inputs.py --symbol X --end-date YYYY-MM-DD --exchange-kind binance
    • 控 flag 跑回测:GENERAL_XXX_ENABLED=false python run_backtest.py --csv ... --symbol X
    • 实盘归因:reports/runtime/{income,shadow_trades,decision_journal}_ledger,decision_journal 按 git_sha 切 live A/B
    • 交易所分类:Binance fapi/v1/exchangeInfounderlyingType / underlyingSubType
    • 黑名单/cohort 正道:EDGE_DISABLED_COHORTS(cohort 级 holdout-validated),优于手动 symbol blacklist
    • 实盘改动(.env flag 翻转、mode 禁用)需当前对话明确授权 + 可回滚 + 部署后 live 监控
    No Comments Yet
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   1151 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 42ms · UTC 23:45 · PVG 07:45 · LAX 16:45 · JFK 19:45
    ♥ Do have faith in what you're doing.