Keep frozen research conclusions and code; raw ledgers and secrets stay out of git. Co-authored-by: Cursor <cursoragent@cursor.com>
84 lines
2.6 KiB
Python
84 lines
2.6 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
CCXT 轻量 L2 录音机(不依赖 Nautilus)
|
||
|
||
用途:在 Nautilus 节点未就绪时,先用代理拉 Binance USDT-M 盘口 + trades,
|
||
写入与 Maker Edge 相同的 jsonl schema(book history + 模拟 quote 心跳)。
|
||
|
||
用法:
|
||
cd nautilus_mm
|
||
source .venv/bin/activate
|
||
export PYTHONPATH=src
|
||
export HTTPS_PROXY=http://127.0.0.1:7897
|
||
python scripts/record_l2_ccxt.py
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import os
|
||
import sys
|
||
import time
|
||
from pathlib import Path
|
||
|
||
_ROOT = Path(__file__).resolve().parents[1]
|
||
sys.path.insert(0, str(_ROOT / "src"))
|
||
|
||
import ccxt # type: ignore
|
||
|
||
from nautilus_mm.recorder import MakerEdgeLogger
|
||
|
||
|
||
def main() -> None:
|
||
proxy = os.getenv("HTTPS_PROXY") or os.getenv("HTTP_PROXY") or "http://127.0.0.1:7897"
|
||
symbol = os.getenv("CCXT_SYMBOL", "BTC/USDT:USDT")
|
||
poll = float(os.getenv("POLL_SECS", "2"))
|
||
log_dir = os.getenv("MAKER_EDGE_LOG_DIR", str(_ROOT / "logs" / "maker_edge"))
|
||
|
||
ex = ccxt.binanceusdm(
|
||
{
|
||
"enableRateLimit": True,
|
||
"proxies": {"http": proxy, "https": proxy},
|
||
"options": {"defaultType": "future"},
|
||
}
|
||
)
|
||
lg = MakerEdgeLogger(log_dir=log_dir, levels=10)
|
||
last_mid = None
|
||
print(f"[ccxt-recorder] {symbol} proxy={proxy} log={log_dir}")
|
||
print("Ctrl+C to stop. This mode records book only (no live orders).")
|
||
|
||
while True:
|
||
try:
|
||
ob = ex.fetch_order_book(symbol, limit=10)
|
||
trades = ex.fetch_trades(symbol, limit=100)
|
||
snap = MakerEdgeLogger.snapshot_from_orderbook(
|
||
ob, levels=10, recent_trades=trades, last_mid=last_mid
|
||
)
|
||
if snap.mid:
|
||
last_mid = snap.mid
|
||
now = time.time()
|
||
lg.record_book(snap, now=now)
|
||
# 心跳 quote(不挂单,仅记录可报价位置)
|
||
if snap.best_bid:
|
||
lg.write(
|
||
{
|
||
"event": "book_tick",
|
||
"pair": symbol,
|
||
"inventory": 0,
|
||
**snap.to_book_fields(),
|
||
}
|
||
)
|
||
lg.update_paths(symbol, snap.mid or 0, now=now)
|
||
print(
|
||
f"\r mid={snap.mid:.1f} spread={snap.spread:.2f} obi={snap.obi:+.3f} "
|
||
f"timb={snap.trade_imbalance:+.3f} pending_fills={lg.pending_count}",
|
||
end="",
|
||
flush=True,
|
||
)
|
||
except Exception as e:
|
||
print(f"\nerror: {e}")
|
||
time.sleep(poll)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|