From latency-hunter
量化回测代码的"照妖镜"——逐项审查会让回测虚高、实盘亏钱的工程陷阱(未来函数/前视偏差、过拟合/数据窥探、成交真实性/成本、收益口径错误),按严重度(致命/高危/中/低)输出一张"回测体检报告"。 何时触发:用户把量化策略/回测代码、信号生成、数据加载、参数寻优脚本丢过来让你审查可信度;或问"这个回测能信吗/为什么实盘对不上回测/帮我查未来函数/有没有过拟合"。 触发词(中):回测审查、回测照妖镜、回测体检、未来函数、前视偏差、数据泄漏、过拟合、数据窥探、幸存者偏差、回测陷阱、回测可信度、实盘对不上回测。 触发词(英):backtest audit、backtest review、look-ahead bias、lookahead、data leakage、overfitting、survivorship bias、curve fitting、backtest-guard。 不适用场景:实时实盘下单/风控逻辑本身的 bug、单纯策略调参或求 alpha、行情数据源运维、非量化的通用代码审查、要你"预测收益/荐股/给买卖建议"——这些都不在本 skill 范围。
How this skill is triggered — by the user, by Claude, or both
Slash command
/latency-hunter:backtest-guardThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
一个只做一件事的工程审查工具:把一份回测/策略代码当"嫌疑犯"过堂,逐项揪出会让回测虚高、实盘还回去的陷阱。
一个只做一件事的工程审查工具:把一份回测/策略代码当"嫌疑犯"过堂,逐项揪出会让回测虚高、实盘还回去的陷阱。
核心理念:让回测虚高 0.x 个夏普的坑,实盘会一次性还给你。 回测的默认假设是"乐观"——零成本、零延迟、能看到未来、永远成交;实盘的默认假设是"敌意"。本 skill 的工作就是把每一处"乐观假设"暴露出来,标注严重度,而不是替你优化收益。
不启用:让你预测收益、荐股、给买卖点、调参求更高夏普、修实盘下单/风控逻辑、运维数据源。这些不在本 skill 职责内。
铁律:所有结论必须基于真实代码,定位到 文件:行,不臆测、不脑补。找不到证据就标"未发现/需人工确认",绝不假设"应该没问题"或"应该有问题"。
更高一层的铁律:命中可疑模式只是"线索"不是"判决"。 任何 Grep 命中后必须读上下文,区分真坑与合法用法,否则报告会被假阳性淹没、失去可信度。下文每条都标注了"合法例外",审查时务必核对。
read_csv/download/fillna/resample/merge/复权)shift/rolling/rank/指标计算/标准化)buy/sell/order/fill/commission/slippage/止盈止损)train_test_split/GridSearch/TimeSeriesSplit/argmax/sharpe/年化/复利)bfill、center=True、commission=0、StandardScaler().fit_transform 在 split 前等),命中后读上下文确认,区分真坑与合法用法(例:shift(-1) 构造 label 合法,进特征矩阵就是致命未来函数;bfill 静态元数据合法,bfill 行情列致命)。references/backtest-pitfalls.md,本文只列每类最致命的几条。每条格式:陷阱名 — 怎么发现(含合法例外) — 修复方向。完整 50+ 条检测点与正则/AST 提示见 references/backtest-pitfalls.md。
\.shift\(\s*-、diff(-、pct_change(-;进特征/信号即致命。合法例外:仅在显式构造 label/target/fwd_ret/y 时合法 — 修:进 signal/feature 的列一律 shift(>=1) 滞后,未来收益严格隔离在 y 列且绝不进 X。close[t],成交价也取 close[t](同索引);backtesting.py 默认当根 close 成交、set_coc(True) 重点查 — 修:close[t] 算信号、open[t+1] 成交,信号统一 .shift(1) 再喂引擎。resample(...).last()/agg() 把 bar 结束才知道的聚合值挂到 bar 开始;跨市场/跨时区合并(UTC 与本地时区错位)导致信号比成交早一根。合法例外:bar 标注收盘时间、且下游统一在 t 收盘后才用 t 的值,合法 — 修:统一 bar 时间戳语义(推荐标注收盘),resample 结果整体 .shift(1) 或显式注明"收盘后可用",跨市场对齐到同一时区并核对夏令时。StandardScaler/MinMaxScaler/PCA/QuantileTransformer.fit_transform 出现在 train_test_split 之前,或 fit 对象不是 X_train;手写 (df-df.mean())/df.std() 整列同理 — 修:scaler 只在训练集 fit,放进 Pipeline + TimeSeriesSplit 每折独立 fit;在线场景用 rolling/expanding point-in-time 统计。bfill/backfill 把未来值灌进当前;interpolate( 对序列中间缺失用前后点 → 引入未来值(须显式 limit_direction='forward' 才安全);停牌标的最常中招。合法例外:对静态/历史不变的元数据(行业分类、合约乘数 multiplier、tick size、上市前常量属性)做 bfill 无害——必须读上下文确认该列是"时变行情"还是"静态属性",只对前者判致命 — 修:时变行情列只允许 ffill,插值 limit_direction='forward',缺失统计量取自训练集。center=True / 全列聚合当特征 — center=True 用到未来 w/2 根;整列 .mean()/.std()/.quantile()/.rank() 直接进信号 — 修:时序窗口 center=False 用过去,全历史统计用 expanding(),横截面 rank 按 date groupby 不跨时间。abs>0.99 重点查,非判决——强自相关特征如价格本身、慢动量、隔夜跳空与未来收益天然中高相关却合法;高相关≠leakage) — 修:命中高相关后回到"该列在 t 时点真能算出吗"做 point-in-time 可得性确认;Target encoding 用 out-of-fold,提交前跑"特征-标签相关性体检 + 可得性核对"。train_test_split 缺 shuffle=False,KFold/GridSearchCV 用在时序而非 TimeSeriesSplit — 修:时序 shuffle=False,CV 用 TimeSeriesSplit/Purged K-Fold(带 embargo)。zigzag/fractal/pivot_high/find_peaks(对整段序列找极值=未来函数)/自实现 supertrend,事后回溯重画 — 修:换因果版本(只用历史确认),对每个指标做"截断到 t 重算,t 处值变了即 repaint"稳定性测试。train/test、无 walk-forward — 修:按时间切,headline 指标只来自从未参与调参的数据;用 walk-forward / anchored 滚动重优。argmax/idxmax/study.best_params 紧跟一次大网格扫描后直接当"策略";无 deflated/PBO/Bonferroni 惩罚 — 修:算 Deflated Sharpe(计入试验次数 N、收益偏度峰度)或 Benjamini-Hochberg/Bonferroni,优先选参数高原而非尖峰,报 OOS 分布而非单个赢家。rsi<27.3、vol>0.0184)、上百次追指标的提交 — 修:CSCV 估 PBO,预注册假设与参数范围,锁一个只碰一次的 lockbox 期。df.dropna() 跨标的丢未上市/已退市名 — 修:universe 按时点用 trailing 数据选,绝不要求标的有超过当前 bar 的数据。pvalue<0.05 留显著的,无 fdr_bh/deflated_sharpe — 修:Benjamini-Hochberg FDR 或 Deflated Sharpe haircut,提高显著阈值(新因子 t>3),披露筛了几个候选。commission/fees/set_commission 或值为 0;换手越高误差越离谱 — 修:按交易所真实分层费率建模(Binance 现货 taker 0.1%、合约 taker 0.04%),做成本翻倍敏感性。slippage/set_slippage,成交价直接取 close/open 无点差;净值曲线异常平滑 — 修:至少建模半个~一个 spread + 与下单量挂钩冲击成本(平方根法则 σ·(Q/ADV)^0.5)。high、止损用 low;同 bar 同时触发时,先核实该引擎的同 bar 撮合顺序假设——若引擎默认盈利方向先成交即为坑,若引擎本已止损优先则合法 — 修:确认乐观后,按最坏假设(同 bar 双触止损优先)重估;细化到 tick 还原 bar 内路径。volume_limit/participation 约束 — 修:加参与率上限(单 bar ≤ 该 bar volume 的 1%-10%),超量拆单,画资金规模-夏普衰减曲线定容量。latency/queue — 修:信号到成交加延迟(高频按真实 RTT),被动限价引入排队/成交概率模型,要求价格穿过而非仅触及。limit_up/limit_down/halt/volume==0 过滤,在一字板(open=high=low)上成交 — 修:封板不成交、停牌(volume=0)不成交,极端行情回撤才真实。liquidation/maintenance_margin,权益可深度为负仍持仓回本 — 修:每 bar mark-to-market,权益 < 维持保证金触发强平清零;报告必须统计"爆仓次数",一次清零即判失败。borrow_fee、永续无 funding_rate、跨除权日用未复权价或前复权(未来信息) — 修:空头计提借券费、永续每结算点按 名义×funding×方向 入账、用后复权或分红现金入账口径。buying_power 校验 — 修:下单前校验购买力。注意区分场景:单边/无对冲策略可硬约束总仓位 ≤ 权益;多空对冲/市场中性策略 gross 敞口本就 >1(net≈0)属正常,不可用 gross ≤ 权益误杀——应约束 net 敞口与维持保证金,融资买入计利息。* np.sqrt(252)/* 252/annualize 核对频率 — 修:annualization factor 必须匹配真实 bar 频率与该资产的交易日历,crypto 7×24 不用 252。returns.sum()/cumsum 当总收益而非 (1+r).prod()-1;跨再平衡频率或跨标的直接拼接收益序列 — 修:复利用 (1+r).cumprod(),统一收益频率口径,杠杆下注意几何收益拖累(volatility drag)。固定模板,直接产出(可截图、可复制)。严重度 用 emoji + 中文档级,定位精确到 文件:行。
══════════════════════════════════════════
回测体检报告 · backtest-guard
══════════════════════════════════════════
受检对象: <仓库/文件名> 扫描文件: N 个 代码行: ~X
总评: 🔴 致命 a 项 · 🟠 高危 b 项 · 🟡 中 c 项 · 🔵 低 d 项
判语: 「<这是一个策略,还是一次对历史的过拟合?>」
—— 一句不留情面但克制的整体结论
────────────── 问题清单(按严重度) ──────────────
[🔴 致命] 负数 shift 引入未来值
位置: src/features.py:84
问题: df['mom'] = df['close'].shift(-5) 将 t+5 收盘移到 t,
该列进入了 X 特征矩阵(features.py:131)。
修复: 进特征的列改 shift(>=1);未来收益只留 y/label,绝不进 X。
[🔴 致命] 全样本 fit 预处理(数据泄漏)
位置: src/train.py:42
问题: StandardScaler().fit_transform(X) 在 train_test_split(:57) 之前,
测试期 mean/std 泄漏进训练。
修复: scaler 放进 Pipeline,TimeSeriesSplit 每折独立 fit。
[🟠 高危] 零手续费 + 零滑点
位置: backtest/engine.py:––(全文件未发现 commission/slippage)
问题: 成交按 close 原值记账,日内策略年换手 ~900 次,成本被完全忽略。
修复: 按 taker 费率建模 + 半个 spread 滑点,做成本翻倍敏感性。
[🟠 高危] 年化因子用错(crypto 套用 252)
位置: metrics.py:31
问题: sharpe = mean/std * np.sqrt(252),但数据为 BTC 1h bar(7×24),
年化被低估、跨频比较失真。
修复: 按真实频率年化(crypto 用 √年化小时数),并复核复利口径。
[🟡 中] 单一 regime 验证
位置: backtest/run.py:20 (回测区间 2020-10 ~ 2021-04)
问题: 仅覆盖一段 crypto 单边牛市,无熊市/震荡压力测试。
修复: 至少覆盖一个完整周期 + 一段 2022 压力期,按 regime 拆分表现。
────────────── 偏差影响(方向判断,非收益预测) ──────────────
说明:以下仅为"剔除偏差后表现往哪边走"的方向性判断,不是收益预测、
不承诺任何数字。存在 ≥1 项致命未来函数/泄漏时,当前 headline 夏普
不可作为样本外预期。修复"负数 shift + 全样本 fit + 零成本 + 年化口径"
后,样本外表现通常会**显著低于**当前回测——具体幅度需重跑确认。
建议优先级: 先堵致命未来函数 → 再修口径/补成本滑点 → 最后做
walk-forward 重验。在致命项清零前,不建议投入实盘资金。
══════════════════════════════════════════
报告原则:每条必带 位置;找不到证据的项标"未发现/需人工确认",不硬凑;命中可疑模式但读上下文后判为合法用法的,不写进清单(或写入"已排除"附注);判语克制、不羞辱、不夸张;"偏差影响"只给方向(变低/不可信),绝不承诺具体收益数字。
| 严重度 | 含义 | 处置 |
|---|---|---|
| 🔴 致命 | 直接让回测看到未来或系统性虚高,实盘必然复现不了(未来函数、时间戳语义前视、全样本 fit、幸存者偏差、忽略爆仓、零滑点理论价成交) | 阻断——清零前回测结果不可信,禁止上实盘资金 |
| 🟠 高危 | 显著高估收益或低估风险,方向性失真(零手续费、无限流动性、单报最优参、样本量不足、年化/复利口径错误) | 强烈建议修——修复后预期大幅缩水 |
| 🟡 中 | 口径不严谨、特定场景失真(收益统计混用、单一 regime、tick/lot 未取整、夏普分母口径) | 建议修——影响精度与稳健性 |
| 🔵 低 | 风格/边界/工程整洁问题(warm-up 未截断、对齐告警、缺断言) | 可选——提升可信度与可维护性 |
判定基准:"这个值在该时点真能算出来吗?这笔成交实盘真能成吗?这个指标口径对吗?" 三问任一为否,按影响幅度归入致命/高危。
本 skill 是工程审查工具,只对回测/策略代码的可信度与工程缺陷做尽职调查,目的是帮你"防自欺、做 due diligence",识别会让回测虚高、实盘亏钱的技术陷阱。
Searches MemPalace before answering questions about past work, people, projects, or prior decisions. Returns verbatim stored content instead of guessing from model memory.
Guides Payload CMS config (payload.config.ts), collections, fields, hooks, access control, APIs. Debugs validation errors, security, relationships, queries, transactions, hook behavior.
Implements vector databases with Pinecone, Weaviate, Qdrant, Milvus, pgvector for semantic search, RAG, recommendations, and similarity systems. Optimizes embeddings, indexing, and hybrid search.
npx claudepluginhub paidaxing1234/latency-hunter-toolkit --plugin latency-hunter