影子测量改用框架吃单原语,并补齐容量与 maker 成交率两项测算

吃单查询换成 Hummingbot 的 OrderBook.get_vwap_for_volume:手写的 walk_book
返回的是按计价币吃单的加权均价,但框架的 get_price_for_quote_volume 返回
边际价、get_vwap_for_volume 收基础币量,两者语义不同。改为按基础币下单
(真实委托与 PositionExecutor.amount 均是基础币计价),深度不足由
query_volume/result_volume 判定,框架此时返回 nan 而非一个看似正常的
部分成交均价。

落盘完整盘口(双边 50 档)。此前只记三个固定名义额的成交价,这批数据的
寿命就等于那几个档位的寿命;存完整深度后任意资金量级的冲击都能离线重算。
仓位档同时从 1k/5k/20k 提到十万量级,此前低估真实仓位约两个数量级。

订阅成交流,按根按价位聚合。买卖分开存——多头在目标位挂卖出靠主动买盘
成交,混在一起会把成交率高估约一倍。BTC 每根总成交额中位与 210 天历史
的 volume×close 差 0.3%,可确认采集完整。

新增两项测算:
- 冲击不是绑定约束。32 万仓位单边冲击 0.19~2.39bp,对 8.58~20.64bp 的
  预算只占 1.6~14.2%,冲击反推的资金上限 100~500 万。
- maker 成交率才是。止盈位被首次触及时,限价在该根价格区间中的位置
  中位 k=0.28(63.9 万次触及,三币一致);合并每根成交额后,32 万仓位
  的全额成交率仅 30.1%/15.6%/1.5%。要 80% 全额成交,仓位须 ≤ 4.7 万
  /1.4 万/0.26 万——比冲击反推的上限低 40~370 倍。

回测把这些止盈按「全额成交在目标价」计,故预算所依据的收益流本身需重估。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
jack
2026-08-28 02:39:47 +08:00
co-authored by Cursor
parent 6259f7380b
commit 181bca303f
10 changed files with 1503 additions and 174 deletions
+9 -6
View File
@@ -5,9 +5,11 @@
的标准差。入场方向上还有系统性追价(信号触发往往伴随同向动量),所以随机
漂移只是下限,真实成本更高——这也是为什么最终仍要用真实盘口测滑点。
余量(bitget_baseline.py 得出,Bitget 原生基线减去手续费后剩下的空间):
BTC -0.13bp ETH +4.02bp SOL +2.92bp
BTC 本就为负,留着只作延迟测量的参照物,不作交易标的。
预算从 `lib/shadow_budget` import,不在这里写死。曾经写死的
`{BTC: -0.13, ETH: 4.02, SOL: 2.92}` 是错的——那是 `bitget_baseline.py`
按「毛均 − 6bp 双边 taker」算的,六处口径叠加(费率档位记高、余量没除
taker 名义额、用了 5m~30m 的出场参数、只有同向没有阶梯与 ATR 门控)。
正确值是 8.58 / 20.64 / 16.83ETH 差了五倍。
.venv/bin/python research/live/latency_compare.py
"""
@@ -23,8 +25,9 @@ HERE = Path(__file__).resolve().parent
RESEARCH = HERE.parent
sys.path.insert(0, str(RESEARCH))
from lib.shadow_budget import budget_of # noqa: E402
OUT = RESEARCH / "out"
BUDGET_BP = {"BTC": -0.13, "ETH": 4.02, "SOL": 2.92}
SYMS = ("BTC", "ETH", "SOL")
@@ -67,8 +70,8 @@ def describe(df: pd.DataFrame, name: str, vols: dict) -> None:
med, p90 = float(np.median(v)), float(np.percentile(v, 90))
vol = vols.get(s)
d = drift_bp(med, vol) if vol else float("nan")
b = BUDGET_BP[s]
share = f"{d / b * 100:.0f}%" if b > 0 else "(负)"
b = budget_of(s)
share = f"{d / b * 100:.0f}%" if np.isfinite(b) and b > 0 else ""
print(f"{s:<5}{len(v):>5}{med:>9.0f}{p90:>9.0f}{v.max():>9.0f}"
f"{d:>12.2f}{b:>9.2f}{share:>9}")