Featured image of post LynxCrypto 启程(下篇):我把策略写成代码,然后亲手证伪了它

LynxCrypto 启程(下篇):我把策略写成代码,然后亲手证伪了它

把 15m 区间均值回归写成可回测的事件驱动引擎,用 180 天真实 ZEC 数据亲手打脸:裸均值回归毛利边缘约等于零——不是风控没用,是手续费和滑点把它打成负期望。107 测试全绿、四条铁律焊死在代码里。

先说结论,也是这篇最值钱的一句话:我用 180 天真实 ZEC 数据,证明了我最初设想的"15 分钟裸均值回归"策略,毛利边缘约等于零——不是因为风控没用,而是因为手续费和滑点把那一点点均值回归倾向,直接打成了负期望。 这个结论比任何一次"回测爆赚"都更能救我的钱。


一、开工前的账:880 美金和一个不能输的系统

先对齐现状。上篇结尾我的账是:1080 美金,出了 200,手里剩 880 美金本金。我的目标还是那个激进的目标——每天 800 做到 1000、出 200。但上篇的深度研究已经告诉我,这个目标在数学上不可持续。

所以下篇的任务不是"赶紧把网格开起来赚钱",而是:把策略从一句口号变成一个可回测、可证伪、可复现的系统,先让它在历史数据上死给我看,再决定要不要让它上实盘替我去死。

这就是 LynxCrypto 这个项目干的事。代码在 [github 上(本地 /home/li/lynxcrypto)],技术栈按上篇的选型落地:

  • 语言 Python 3.12——15 分钟周期,延迟不是瓶颈,生态最全。
  • 数据 CCXT——公开端点拉 ZECUSDT 的 K 线和资金费率,不要 API key。
  • 回测自写事件驱动引擎——不用 backtrader(2023 年就停更了),自己保证无前视。
  • 指标纯 pandas——不装 TA-Lib,每个指标都可单测验算。

整个系统 48 个单元测试全绿,端到端在 17280 根真实 15 分钟 K 线上跑通。下面按模块讲我是怎么搭的,以及每一步踩到的坑。


二、四条铁律,焊死在代码里

上篇定的三条铁律,我在代码里加了第四条,变成:

  1. 永不马丁倍投——仓位只能走凯利分数,代码里没有任何"亏损后加仓"的路径。
  2. 永不无止损——每笔单进场就带 ATR 止损和强平价预检。
  3. 回测不过关不上实盘——WFO + MCPT + DSR/PBO 三重验证,一票否决。
  4. 永不前视(新增)——这是最容易自欺的一条:信号必须在 bar 收盘算出、在下一根 bar 开盘才成交。任何"用当前收盘价决定当前成交"的写法,都是在偷未来的钱。

第四条听着技术,其实是最多人回测造假的根源。我专门写了一个单元测试钉死它:在一个 100 → 120 跳涨的行情里,策略在 bar 0 发出信号,引擎必须在 bar 1 的开盘价 120 成交,而不是 bar 0 的收盘价 100。这个测试不过,整个引擎就是废的。


三、Phase 1:先把"真实世界的摩擦"建出来

太多人回测爆赚、实盘爆亏,差别就在成本模型。所以 LynxCrypto 的第一阶段不是写策略,是先把真实世界的摩擦力建出来,包括:

  • 手续费:taker 0.05%、maker 0.02%(ZECUSDT 实测)。
  • 滑点:用 Almgren-Chriss 的平方根市场冲击模型,冲击 ∝ σ·√(订单量/日均成交量)
  • 资金费:永续合约每 8 小时收一次,中性地板 +0.01%/8h ≈ 年化 10.95%,ZEC 这种波动大的币种资金费经常偏正,多头长期被抽血。
  • 强平价:逐仓保证金强平价公式,爆仓价必须落在网格/区间之外。

这里有个很多人算错的点:所有费用都是按名义价值(保证金×杠杆)收的,不是按保证金收。 所以保本价差这个"价格百分比"其实跟杠杆无关;但换成"保证金百分比"就要乘以杠杆。8 倍杠杆下,taker 一进一出的费用 + 滑点,大约要吃掉你 0.1% 的价格位移——15 分钟级别,这可不是小数目。

成本模型 10 个单测验算过数学,强平价公式对着交易所官方文档核过。这一步做扎实,后面的回测数字才可信。


四、Phase 2:把"区间 + 反手"翻译成状态机

这是我最初思路的核心,也是最需要修正的地方。

4.1 反手:上篇就标了红旗,这版默认关闭

我上篇查资料时标过一个坑:网上流传的"71.5% 胜率反手系统"实测是"平仓即空仓"(long-only-fade-then-flat),不是真的多头结束立马反手做空。真反手的证据很弱,而且均值处来回打脸(whipsaw)的风险极高。

所以 LynxCrypto 这版策略默认 flat 反手:平仓就停手,不做无条件翻转。反手作为 Phase 6 的可选增强,必须独立回测证明它有正边际才准开。

4.2 防单边:不是一个指标,是一个状态机

我上篇最怕的就是单边行情把网格/均值回归一次清零。防它的办法不是"设个止损"就完事,而是判断现在到底是震荡市还是趋势市,震荡市才准做均值回归,趋势市直接关掉

我实现的是一个多指标共谋 + 迟滞的状态机:

  • 趋势票:ADX>25、CHOP<38.2、Hurst>0.55、BB 带宽扩张、ATR 放大、EMA20>50>200、价格在 Supertrend 上方。
  • 震荡票:ADX<20、CHOP>61.8、Hurst<0.45、BB 带宽收窄、ATR 收缩。

关键设计两条:

  1. 至少 3 个指标同时翻面才切状态——单个指标跳变不触发,防被一根毛刺骗进去。
  2. 迟滞防抖——新状态必须连续确认 3 根 K 线才生效,防止在震荡/趋势边界上来回抖动。

状态机 6 个单测覆盖了:数据不足时保持中性、单指标翻面不切、连续确认才切、whipsaw 不抖。

4.3 进场:fade 极值,回到均值

在震荡市里,策略做经典的多空双向 fade:

  • 做多:价格跌破布林下轨、收盘收回带内、RSI<25、且价格在 VWAP 之下——确认这是"恐慌性超卖",进场赌它回到均值。
  • 做空:镜像,突破上轨收回、RSI>75、价格在 VWAP 之上。
  • 止损:穿透那根 K 线的极值之外再放 1 倍 ATR。
  • 止盈:回到 VWAP / 布林中轨,或者固定的 1.25R。
  • 时间止损:24 小时没回到均值,说明这个 fade 大概率错了,走人。

指标全部纯 pandas 实现,13 个单测对着手算值核:ATR 在恒定区间收敛到区间宽、全涨时 RSI=100、VWAP 在日界重置、Donchian 通道不含当前 bar(防止自引用)。


五、Phase 3:凯利仓位 + 三道保险丝

仓位是这套系统和马丁格尔最根本的分歧。马丁格尔是"亏了加倍",凯利是"赢了才加、且加多少由期望决定":

$$f^* = \frac{bp - q}{b}$$

p 是胜率,b 是盈亏比,q=1−p。算出来的是全凯利,实战用 1/4 凯利来对冲参数估错的误差。p 和 b 不能拍脑袋,必须来自样本外回测统计——这也是为什么 Kelly 的输入我先留成占位符,等 Phase 3 的 WFO 跑出真实 OOS 数据再填。

保险丝(熔断)是闩锁式的——跳闸后保持,只能人工复位,绝不自动恢复:

  • 档 1:日内回撤 −2% → 仓位减半。
  • 档 2:−3% → 停止开新仓。
  • 档 3:−5% → kill switch:撤所有挂单、平所有仓、停机。
  • 连亏 4 笔 → 暂停 + 强制重新评估 regime 是不是已经翻转了。

风险层 11 个单测,重点测"闩锁":−2% 跳闸后哪怕净值回到新高,仓位依然减半,直到人工 reset()。这就是网格马丁没有的东西——一个会喊停的底层


六、回测:我亲手证伪了自己的策略

铺垫完了,上数据。180 天 ZECUSDT、17280 根 15 分钟 K 线、真实资金费率、无前视、含全部成本。我跑了三个 preset:

配置笔数胜率盈亏比 PF毛利总成本净利
严格(RSI25/75 + VWAP,taker)250%6.2+0.440.15+0.29
放宽(RSI40/60,taker)17250.6%0.98+9.1311.98−2.84
放宽 + maker 限价21249.5%0.97+10.0715.42−5.49

三张表连起来看,结论非常扎心但非常清楚:

1. 严格过滤 → 几乎不交易。 RSI(25/75)+VWAP 双重过滤,180 天只触发 2 次。选择性是拉满了,但样本小到没有统计意义,等于没策略。

2. 放宽过滤 → 有了交易频率,毛利却接近零。 172 笔,胜率 50.6%,毛利 +9.13 美金——看起来还行?但成本 11.98,净利 −2.84。盈亏比 0.98,小于 1,这是个负期望策略

3. 换 maker 限价也救不回来。 我以为把 taker(0.05%)换成 maker(0.02%)能翻身,结果 212 笔、成本反而升到 15.42(因为单更多了),净利 −5.49

这一组实验最值钱的发现是:问题不在费别(maker/taker),在毛利本身。 15 分钟级别上,ZEC 的均值回归倾向太弱,弱到连 maker 的低费率都覆盖不了。换句话说——我最初"找 range、fade 极值、反手"的朴素想法,在真实成本和真实波动面前,是没有 alpha 的。

这就是为什么我昨天网格能赚 100 美、而今天这个"更聪明"的策略却亏钱:网格赚的不是方向的钱,是 maker 限价单把成本压到近零、且每格利润都大于保本阈值的钱;而我这个 fade 策略,既没有 maker 的成本优势,又频繁交易,把本金一点点喂给了手续费和滑点。


七、这笔"回测亏损"教会我的四件事

亏钱亏出了认知,这四条比 880 美金值钱:

1. 回测的第一要务是证伪,不是证实。 如果我的目标是"跑出好看的曲线",我完全可以调参调到爆赚(比如把趋势市那段 SMA 策略的 3.83 Sharpe 拿出来吹)。但那是在骗自己。让策略在历史数据上先死一遍,是它在实盘替我省钱。

2. 成本是 15 分钟策略的生死线。 高频一点、周期小一点,费用和滑点占比就指数级上升。任何 15m 策略,先把保本阈值 ΔP_be 算清楚,每格/每笔利润盖不过它,直接不做。

3. “高胜率"和"正期望"是两回事。 我昨天网格胜率很高,今天 fade 策略胜率也有 50%,但一个赚钱一个亏钱。差别在单笔期望 = 胜率×平均盈 − 败率×平均亏 − 成本,胜率只是其中一项。

4. Regime 过滤有用,但救不了一个没有毛利的信号。 状态机确实把我在趋势市里的亏损拦住了(趋势 preset 下几乎不交易),但它只能"避免错”,不能"制造对"。alpha 还是得从信号本身找。


八、下一步:真正的 alpha 在哪

证伪了裸均值回归,我的方向反而清晰了。LynxCrypto 的下一步:

  1. 成本结构改造:入场从 taker 市价单改成 maker 限价挂单,把成本压到近零——这是网格唯一做对的事,要继承。
  2. 更高选择性:宁可一天 0 笔,也不做负期望的交易。把 regime 共谋调得更严,只在"高质量震荡 + 极值 + 多指标确认"三者同时满足时出手。
  3. 回测纪律落地:把 WFO(滚动前推)+ MCPT(蒙特卡洛排列检验,p<0.01)+ DSR/PBO 这三重验证写完,任何策略过不了这关,一票否决,绝不进 Phase 4 实盘。
  4. 那 880 美金继续躺着:在新策略过验证之前,不动用实盘本金。昨天赚的 100 美我出了,这 880 留着当种子——但种子要种在验证过的策略上,不是种在幻觉上。

九、收盘:写给同样想"每日出金"的你

如果你和我一样,是从"每日盈利 200、稳定出金"这种目标进来的,我想把这套系统教我的最硬的一句话送给你:

“每日稳定出金"不是一个策略目标,是一个营销话术。 真实的量化是:长时间研究、大量证伪、严格控制回撤,然后接受收益是不均衡分布的——可能一周不出金,一个月出一笔大的。马丁格尔能给你"每天小赚"的幻觉,代价是把一次大的、足以清零的亏损推迟到未来某一天。

LynxCrypto 现在还不是一个赚钱的系统,它是一个诚实的系统——它会先告诉我"这个想法不赚钱”,而不是等我投了钱再告诉我。对我这 880 美金本金来说,这比什么都重要。

下篇见。等我跑完 WFO + MCPT,如果找到了真能过验证的信号,我再来写"上篇之之后:第一笔过验证的实盘"。如果找不到,我也会写——写一个"我继续没找到 alpha,但我的钱还在"的故事。后者可能才是常态。


代码:/home/li/lynxcrypto,48 个单元测试全绿,数据为 2026-03-09 至 2026-09-05 真实 ZECUSDT 永续。所有回测数字含手续费、滑点、资金费,无前视。本文不构成投资建议。