主口径仓位定为 10 万 USDT,并量出限价单前方的排队量
用户 2026-08-28 确认资金规模不会更大,故仓位档改为 25k/50k/100k/200k (上下留档是为了读出局部斜率,单点看不出再大一倍会怎样)。该规模下两条 约束都不绑定:冲击占预算 0.1~11.1%,成交量效应使预算降幅不足 1%。 新增 queue_ahead:排队是唯一还没建模的成本项,exit_fill 假定我们能吃到该 价位的全部对手方成交量。10 万仓位相对最优档为 BTC 0.2 倍、ETH 0.7 倍、 SOL 69.7 倍。SOL 畸高是 tick 更细所致(同样的量摊到约 10 倍价位上), 对它应看 5bp 档(0.17 倍),但仍是三币中排队压力最大者。 同时在 shadow_depth 模块头标注:composite_fill 只算首次触及那一根的可成交 量,系统性偏悲观,不作为成交率结论——真实成交率见 lib/exit_fill.py。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,4 +1,16 @@
|
|||||||
"""从落盘的完整盘口与成交流,算资金容量与 maker 腿成交率。
|
"""从落盘的完整盘口与成交流,算资金容量、排队量与单根成交率。
|
||||||
|
|
||||||
|
## 结论先行(2026-08-28)
|
||||||
|
|
||||||
|
主口径仓位 **10 万 USDT**。该规模下两条约束都不绑定:
|
||||||
|
|
||||||
|
冲击 单边 0.01~1.87bp,占预算 0.1~11.1%,冲击反推上限 100~500 万
|
||||||
|
成交率 按逐根累积结算,预算降幅 BTC −0% / ETH −0% / SOL −1.1%
|
||||||
|
|
||||||
|
⚠ 本文件里的 `composite_fill` 曾给出「10 万仓位全额成交率仅 7~63%」这种数,
|
||||||
|
那个口径只算**首次触及那一根**的可成交量,系统性偏悲观,已不作为结论。
|
||||||
|
真实成交率见 lib/exit_fill.py(挂单常驻多根逐步成交)。
|
||||||
|
|
||||||
|
|
||||||
这两个数都不该等实盘暴露:
|
这两个数都不该等实盘暴露:
|
||||||
|
|
||||||
@@ -71,10 +83,51 @@ def impact_bp(levels: list, notional: float, mid: float) -> float | None:
|
|||||||
return (cost / qty / mid - 1.0) * 1e4
|
return (cost / qty / mid - 1.0) * 1e4
|
||||||
|
|
||||||
|
|
||||||
|
def queue_ahead(books_path: Path, notional: float = 1e5) -> None:
|
||||||
|
"""限价单排在多少量之后。
|
||||||
|
|
||||||
|
这是唯一还没建模的成本项。exit_fill 假定我们能吃到该价位的全部对手方
|
||||||
|
成交量,实际上我们排在该价位既有挂单之后。
|
||||||
|
|
||||||
|
这里量不了 3ATR 处的排队——3ATR 约 30bp,而 50 档盘口只覆盖 1.4~4.5bp,
|
||||||
|
那个价位远在可见深度之外。但价格走到我们的限价时,我们的单就成了盘口
|
||||||
|
最优档附近的一员,所以「最优档通常趴着多少量」是个有用的上界参照。
|
||||||
|
"""
|
||||||
|
per: dict[str, dict[str, list[float]]] = {}
|
||||||
|
for r in read_jsonl_gz(books_path):
|
||||||
|
asks, bids = r["asks"], r["bids"]
|
||||||
|
if not asks or not bids:
|
||||||
|
continue
|
||||||
|
mid = (asks[0][0] + bids[0][0]) / 2.0
|
||||||
|
d = per.setdefault(r["sym"], {"top": [], "b1": [], "b5": []})
|
||||||
|
d["top"].append(asks[0][0] * asks[0][1])
|
||||||
|
for tag, bp in (("b1", 1.0), ("b5", 5.0)):
|
||||||
|
lim = mid * (1 + bp / 1e4)
|
||||||
|
d[tag].append(sum(p * a for p, a in asks if p <= lim))
|
||||||
|
if not per:
|
||||||
|
return
|
||||||
|
print(f"\n\n########## 限价单前方的排队量 ##########")
|
||||||
|
print(f" 主口径仓位 {notional:,.0f} USDT\n")
|
||||||
|
for sym, d in sorted(per.items()):
|
||||||
|
top = np.array(d["top"]); b1 = np.array(d["b1"])
|
||||||
|
b5 = np.array(d["b5"])
|
||||||
|
print(f" {sym} 最优档 {np.median(top):>10,.0f} · "
|
||||||
|
f"1bp 内累计 {np.median(b1):>10,.0f} · "
|
||||||
|
f"5bp 内累计 {np.median(b5):>10,.0f}")
|
||||||
|
print(f" 我们的 {notional:,.0f} 相当于最优档的 "
|
||||||
|
f"{notional / max(np.median(top), 1):.1f} 倍、"
|
||||||
|
f"1bp 内总量的 {notional / max(np.median(b1), 1):.2f} 倍")
|
||||||
|
print("\n 倍数远小于 1 则排队可忽略;接近或超过 1 则我们本身就是那一档的")
|
||||||
|
print(" 主要挂单,exit_fill 的成交量假设需要打折。")
|
||||||
|
print(" SOL 的最优档倍数畸高是 tick 更细所致(Bitget 的 SOL tick 比同类")
|
||||||
|
print(" 细约 10 倍,同样的量摊到 10 倍多的价位上),所以对 SOL 该看 5bp")
|
||||||
|
print(" 档而非最优档;但即便如此它仍是三个币里排队压力最大的一个")
|
||||||
|
|
||||||
|
|
||||||
def capacity(books_path: Path, budgets: dict[str, float],
|
def capacity(books_path: Path, budgets: dict[str, float],
|
||||||
pctl: float = 10.0) -> None:
|
pctl: float = 10.0) -> None:
|
||||||
"""报各币的深度曲线与「冲击吃掉预算多少」的资金上限。"""
|
"""报各币的深度曲线与「冲击吃掉预算多少」的资金上限。"""
|
||||||
grid = [1e4, 5e4, 1e5, 2e5, 3.2e5, 5.3e5, 1e6, 2e6, 5e6]
|
grid = [1e4, 2.5e4, 5e4, 1e5, 2e5, 5e5, 1e6, 2e6]
|
||||||
per: dict[str, dict[float, list[float]]] = {}
|
per: dict[str, dict[float, list[float]]] = {}
|
||||||
n = 0
|
n = 0
|
||||||
for r in read_jsonl_gz(books_path):
|
for r in read_jsonl_gz(books_path):
|
||||||
@@ -130,7 +183,7 @@ def capacity(books_path: Path, budgets: dict[str, float],
|
|||||||
|
|
||||||
|
|
||||||
def maker_fill(tape_path: Path, mults=(3.0, 8.0),
|
def maker_fill(tape_path: Path, mults=(3.0, 8.0),
|
||||||
notionals=(1e5, 3.2e5, 5.3e5)) -> None:
|
notionals=(5e4, 1e5, 2e5)) -> None:
|
||||||
"""限价单挂在离场目标位,本根内有多少主动量打到那里。
|
"""限价单挂在离场目标位,本根内有多少主动量打到那里。
|
||||||
|
|
||||||
这里只回答「量够不够」。真实成交还要看排队位置——我们的单排在该价位
|
这里只回答「量够不够」。真实成交还要看排队位置——我们的单排在该价位
|
||||||
@@ -208,8 +261,15 @@ def tape_shape(tape_path: Path, kgrid: np.ndarray) -> dict[str, np.ndarray]:
|
|||||||
|
|
||||||
|
|
||||||
def composite_fill(tape_path: Path, pen_path: Path, cache: Path,
|
def composite_fill(tape_path: Path, pen_path: Path, cache: Path,
|
||||||
notionals=(1e5, 3.2e5, 5.3e5)) -> None:
|
notionals=(5e4, 1e5, 2e5)) -> None:
|
||||||
"""把穿透深度分布与成交量曲线合并,出真实 maker 成交率。"""
|
"""把穿透深度分布与成交量曲线合并,出**单根**内的 maker 成交率。
|
||||||
|
|
||||||
|
⚠ 这个数只回答「限价单若仅有首次触及那一根可以成交,能否成交」。真实的
|
||||||
|
挂单是常驻的:它在那儿放最多 48 根,每根都在成交,且价格决定性穿过限价
|
||||||
|
时整根成交量都可用。所以本函数系统性**偏悲观**,不能当作成交率结论。
|
||||||
|
真实成交率见 lib/exit_fill.walk_filled 与 step43_fill_aware_budget.py,
|
||||||
|
那里按逐根累积结算,10 万仓位下预算降幅不足 1%。
|
||||||
|
"""
|
||||||
if not pen_path.exists():
|
if not pen_path.exists():
|
||||||
print("\n没有 penetration.csv,先跑 penetration.py")
|
print("\n没有 penetration.csv,先跑 penetration.py")
|
||||||
return
|
return
|
||||||
@@ -276,8 +336,9 @@ def main() -> None:
|
|||||||
d = out_dir()
|
d = out_dir()
|
||||||
from lib.shadow_budget import BUDGET_BP
|
from lib.shadow_budget import BUDGET_BP
|
||||||
tape = Path(a.tape) if a.tape else d / "shadow_tape.jsonl.gz"
|
tape = Path(a.tape) if a.tape else d / "shadow_tape.jsonl.gz"
|
||||||
capacity(Path(a.books) if a.books else d / "shadow_books.jsonl.gz",
|
books = Path(a.books) if a.books else d / "shadow_books.jsonl.gz"
|
||||||
BUDGET_BP)
|
capacity(books, BUDGET_BP)
|
||||||
|
queue_ahead(books)
|
||||||
maker_fill(tape)
|
maker_fill(tape)
|
||||||
composite_fill(tape, d / "penetration.csv",
|
composite_fill(tape, d / "penetration.csv",
|
||||||
Path(__file__).resolve().parent / "cache")
|
Path(__file__).resolve().parent / "cache")
|
||||||
|
|||||||
@@ -77,10 +77,11 @@ BOOK_KEEP_S = 30 # 缓冲保留 30 秒,够回查到 +5s
|
|||||||
BOOK_TOL_MS = 250 # 回查容差:10Hz 正常 ≤100ms,留些余量
|
BOOK_TOL_MS = 250 # 回查容差:10Hz 正常 ≤100ms,留些余量
|
||||||
BOOK_DEPTH = 50 # 双边各 50 档,实测能撑 78 万~261 万美元
|
BOOK_DEPTH = 50 # 双边各 50 档,实测能撑 78 万~261 万美元
|
||||||
DELAYS_S = (0.5, 1.0, 2.0, 5.0) # 回查点
|
DELAYS_S = (0.5, 1.0, 2.0, 5.0) # 回查点
|
||||||
# 便利视图用的仓位档。**真正的答案在 shadow_books.jsonl.gz 里**——完整盘口
|
# 主口径 10 万名义额(2026-08-28 定:不会有更大资金)。上下各留两档是为了
|
||||||
# 落了盘,任意资金量级的冲击都能离线算,换个规模不必重测。这里的档位只是
|
# 读出局部斜率——单点看不出「再大一倍会怎样」。
|
||||||
# 为了让 CSV 直接可读,覆盖到按 2ATR 止损反推的十万量级真实仓位
|
# **真正的答案在 shadow_books.jsonl.gz 里**:完整盘口已落盘,任意资金量级的
|
||||||
NOTIONALS = (50_000.0, 100_000.0, 320_000.0, 530_000.0)
|
# 冲击都能离线重算,换规模不必重测,这里的档位只为让 CSV 直接可读
|
||||||
|
NOTIONALS = (25_000.0, 50_000.0, 100_000.0, 200_000.0)
|
||||||
NUM_COLS = ["timestamp", "open", "high", "low", "close", "volume"]
|
NUM_COLS = ["timestamp", "open", "high", "low", "close", "volume"]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user