配置写着 starting_capital: 100000,图表的 y 轴写着 USD。日志里每一笔成交都是一个 USDC 数字。那次运行的十一个月里,这两件事住在同一个格子里,没人有理由把它们拆开。
然后硅谷银行倒了,Circle 说有 $3.3 billion 的 USDC 储备卡在那里,USDC 成交到了 87 美分。我们的「美元」账本涨了。以 USDC 计价的 BTC 暴拉。永续打出绿色。我们当成无风险 100,000 的那笔现金,才是真正在动的东西。
我现在还会抓到把 USDC、USDT 和 USD 标成同一列的研究流水线。这就是那个周末,按账本看见的顺序拆开。
写着 $100,000 的那一行
模拟账户,USDC 保证金的 BTC 永续,小幅做多。BTC 名义 30,000 USDC,按周五接近 $20,150 的标记价大约 1.5 BTC。另外 70,000 作为 USDC 保证金闲着。故意低仓。我们在给一套策略热身。其余部分都躺在现金里。
NAV 函数做了大多数同类函数会做的事。它把 USDC 现金加上 USDC 未实现 pnl,把合计写进名为 equity_usd 的序列。配置里有一条我自己写的注释:
稳定币 = 1 美元。不要把 FX 算两遍。
我本意是:别把一笔 USDT 资金费换算两次,变成第二下美元波动。我实际做的,是把整份文件余下部分的 FX 汇率冻在了 1.0。
quote_asset = "USDC"
这家交易所是 USDC 交易所。成交、保证金、资金费、强平标记、手数、最小名义,全是。Hyperliquid、dYdX v3、Coinbase International,还有十来家,同一套结构。研究笔记本导入了一根 BTCUSDC K 线和一根 BTCUSD K 线,交易用前者,图上标后者,因为用美元画图看起来更专业。
还有一件我现在半夜还会想到的小事、蠢事:绘图库默认的坐标轴标题是「USD」。我从没覆盖过它。有人路过屏幕,读到的单位,这条序列根本没有。
周五夜里,Circle 的推文
2023 年 3 月 10 日。SVB 已经没了。Circle 披露,当时约 $40 billion 的 USDC 储备里,有 $3.3 billion 停在那家倒闭的银行,大约 8%。Coinbase 当晚暂停 USDC 兑换。赎回,真正的锚定机制,整个周末关着。
回测对这些事情一行都没有。没有赎回暂停标志,没有发行方储备字段,没有「周一之前我能不能把这枚代币换成美元」。它只有收盘价。周五的收盘在我们的 FX 文件里仍是 1.0000,因为那份 FX 文件是个桩,对任何 ticker 以 USD 开头的东西都返回 1.0。
我曾经把 USDT 溢价当成教科书式噪声,脚注里提一句然后忽略的那种。我们有一次在厨房里吵了二十分钟,争 1.03 算不算「值得入账」。我们都在做主观裁剪。这个交易对就是一条序列。存下来。别投票了。
0.8789
周六早上。CoinGecko 上 USDC 的最低价是 $0.8789。别的盘口打出 $0.87。几个 DEX 池子穿过 $0.80。DAI 的抵押品里塞满了 USDC,跟着往下掉。USDT 往另一边走,有的屏幕上 $1.03,Kraken 上 $1.06。
桩 FX 文件仍返回 1.0。回测的时钟知道今天是周六。它不知道账本的单位现在是一枚出了问题的代币。
Kraken 打出的 26,000
Bitstamp 的 BTC/USD 在 $20,200 附近转圈。Kraken 的 BTC/USDC 打出 $26,000 以上。那是同一枚比特币。第二个数字是美元价格除以一个坏掉的锚定,再加上周六单薄的 USDC 盘口多出来的那点空气。
我们的交易所按 USDC 给永续做标记。取一个保守盘口,BTC/USDC 约 $23,000,也就是 $20,200 / 0.88。这 1.5 BTC 多头大约赚了 4,300 USDC。按原生单位计的账户:104,300 USDC。引擎报出 $104,300,一个上涨 4.3% 的周末,一笔资金费还以同一单位叠在上面。
按美元计,这 70,000 USDC 闲置保证金大约值 $61,600。整笔 104,300 USDC 大约值 $91,800。这本「赚了」4.3% 的账,在大部分时间躺在现金里的时候,亏掉了 8% 的美元本金。
这个周末的收益是单位变了,不是运气变了。USDC 下跌的日子里做多 BTC/USDC,机制上就是做多脱锚。你可以想下这个注。你不能事后在一条标成 USD 的序列里发现它。
cash_usd = cash_usdc * 1.0
我一直留着的就是这一行。它在每一根 bar 上都跑,包括 USDCUSD 为 0.87 的那些根。乘以 1.0 感觉像空操作,所以它能过代码审查。这是一笔 FX 计价。冻住的那种。
这 70,000 USDC 保证金从没触发过一笔交易,所以滑点模型从没看过它,没有手续费表,没有资金费。现金本该是那列无聊的数字。在这本账上,它是最大的风险,也是我们唯一没有定价的那一项。
那个周末 BTC 成交上的 maker 返佣是 2 或 3 bps,前提是你成交了。计价资产的波动是 1,300 bps。我们为这 3 建了整套栈,为这 1,300 留了个桩。
图表上那个绿色的周末
周一早上的 Slack,还没人打开 USDCUSD:我们隔夜打出了 4%。有人问要不要把模拟盘放大。我看了图表,然后看 Kraken,然后看那个桩。
| 账本项目 | 引擎存下的 | 周六,原生单位 | 同一时刻,按美元 |
|---|---|---|---|
| 闲置保证金 | 70,000 USDC × 1.00 | 70,000 USDC | ~$61,600 |
| BTC 永续标记价 | BTCUSDC 最新价 | ~23,000 USDC(Kraken 上 26,000) | BTCUSD ~$20,200 |
| 1.5 BTC 上的未实现盈亏 | +4,300 USDC | +4,300 USDC | 多半是锚定,一点比特币 |
| 报告的 NAV | 104,300「USD」 | 104,300 USDC | ~$91,800 |
USDT 账本是反向的漫画。USDT 溢价成交,所以一个 USDT 保证金、空仓的账户也显示了它并没赚到的美元收益,以及一个相对 BTCUSD 过低的 BTCUSDT 标记价。如果你那个周末给两份「一模一样」的 BTC 永续排名,一份在 USDC 交易所、一份在 USDT 交易所,你排的是计价代币,却把它叫成了 alpha。
真正持有 USDC 的那个模拟账户,比研究看板更接近真相。它从未自称是美元。是我们在导出时这么干的。
我们周一发出去的导出
财政部、美联储和 FDIC 表示会让 SVB 储户全额受偿,Circle 也表示会补上缺口之后,USDC 爬回 $1 附近。到周一,锚定大体补上了。那份错了 48 小时的桩 FX 文件,又对了。
但日线把它藏起来了。3 月 11 日 00:00 UTC 的采样抓住的 USDC,已经偏离,或者已经在反弹,取决于数据商;3 月 12 日的采样则是另一部片子。如果你只存了 NAV、没存计价标记,你还原不出是哪一种。那个难看的周末被压成一个小到可以忽略的毛刺,而我们确实忽略了,因为我们按日采样。
我们现在账上始终留三条序列,哪怕它们叠在一起好几个月:
- 交易所计价资产下的 NAV,你真正能提出去的单位。
- 计价资产对 USD,一条真实盘口,包括周六,包括 0.87,包括 Coinbase 没有在兑换的那些小时。
- 美元 NAV,作为派生序列,这样图上标 USD 才有一个父项。
如果是智能体在写回测,检查也一样。问它每一笔仓位和现金的计价资产。如果它在 USDC 交易所上回答 USD,这次运行就不是美元运行。有人跟我说这个区分不会撼动 Sharpe 的时候,我回放的就是 2023 年 3 月这一周。它把这一次挪动的幅度比策略本身还大,而策略才是我们有模型的那一部分。
← 全部文章


