fix模拟盘流水重算卖回VWAP时同秒多笔配对去重,避免USDT重复计入。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-10-13 12:02:04 +08:00
parent 57ca5ebc8f
commit d42e1c7edf
2 changed files with 114 additions and 6 deletions
@@ -104,19 +104,37 @@ def _ledger_buy_sell(
""",
(u, f"{u}/USDT%", start_id, end_id),
).fetchall()
# 同秒多笔卖回时,按「币卖出 id → 下一笔 USDT 入账」配对,避免重复吃到同一笔 USDT
used_usdt_ids: set[int] = set()
for row in sells:
sid = int(row["id"])
usdt_row = conn.execute(
"""
SELECT amount FROM sim_ledger_entries
WHERE ccy='USDT' AND account='trading' AND kind='convert'
AND amount > 0 AND ts=? AND note LIKE 'from %'
AND id > ? AND id < ?
ORDER BY id LIMIT 1
SELECT id, amount FROM sim_ledger_entries
WHERE id = ? AND ccy='USDT' AND account='trading' AND kind='convert'
AND amount > 0 AND note LIKE 'from %'
""",
(row["ts"], start_id, end_id),
(sid + 1,),
).fetchone()
if usdt_row is None or int(usdt_row["id"]) in used_usdt_ids:
cands = conn.execute(
"""
SELECT id, amount FROM sim_ledger_entries
WHERE ccy='USDT' AND account='trading' AND kind='convert'
AND amount > 0 AND note LIKE 'from %'
AND id > ? AND id < ?
ORDER BY id
""",
(sid, end_id),
).fetchall()
usdt_row = next(
(r for r in cands if int(r["id"]) not in used_usdt_ids),
None,
)
if not usdt_row:
continue
uid = int(usdt_row["id"])
used_usdt_ids.add(uid)
sell_coin += abs(float(row["amount"]))
sell_usdt += float(usdt_row["amount"])
return (
@@ -0,0 +1,90 @@
# -*- coding: utf-8 -*-
"""repair_options_spot_vwap_from_sim_ledger:同秒多笔卖回不得重复配对 USDT."""
from __future__ import annotations
import importlib.util
import sqlite3
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
SCRIPT = ROOT / "scripts" / "repair_options_spot_vwap_from_sim_ledger.py"
def _load_repair():
spec = importlib.util.spec_from_file_location("repair_opt_vwap", SCRIPT)
assert spec and spec.loader
mod = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = mod
spec.loader.exec_module(mod)
return mod
def _mk_conn() -> sqlite3.Connection:
c = sqlite3.connect(":memory:")
c.row_factory = sqlite3.Row
c.executescript(
"""
CREATE TABLE sim_ledger_entries (
id INTEGER PRIMARY KEY,
ts TEXT, kind TEXT, ccy TEXT, account TEXT, amount REAL, note TEXT
);
"""
)
return c
def test_same_ts_multi_sell_pairs_distinct_usdt():
mod = _load_repair()
c = _mk_conn()
# 模拟 trade2:最后一笔 option_close 后同秒/连秒多笔 BTC→USDT
rows = [
(21, "2026-10-13 00:06:58", "option_close", "BTC", "trading", 0.01, "sell BTC-USD-261015-84000-P"),
(23, "2026-10-13 00:07:35", "option_close", "BTC", "trading", 0.008, "sell BTC-USD-261015-84000-P"),
(24, "2026-10-13 00:07:35", "convert", "BTC", "trading", -0.01123875, "BTC/USDT mkt 81411.8737"),
(25, "2026-10-13 00:07:35", "convert", "USDT", "trading", 914.967695545875, "from btc"),
(26, "2026-10-13 00:07:36", "convert", "BTC", "trading", -0.018413659934387205, "BTC/USDT mkt 81424.9671"),
(27, "2026-10-13 00:07:36", "convert", "USDT", "trading", 1499.3316552687493, "from btc"),
(28, "2026-10-13 00:07:36", "convert", "BTC", "trading", -1.8413659934386636e-05, "BTC/USDT mkt 81418.9702"),
(29, "2026-10-13 00:07:36", "convert", "USDT", "trading", 1.4992212285500766, "from btc"),
]
c.executemany(
"INSERT INTO sim_ledger_entries(id,ts,kind,ccy,account,amount,note) VALUES (?,?,?,?,?,?,?)",
rows,
)
buy_u, buy_c, sell_u, sell_c = mod._ledger_buy_sell(
c,
underly="BTC",
inst_id="BTC-USD-261015-84000-P",
open_ts="",
close_ts="",
)
assert buy_u is None and buy_c is None
assert sell_c is not None and abs(sell_c - 0.02967082359432159) < 1e-12
assert sell_u is not None and abs(sell_u - 2415.798572043174) < 1e-6
vwap = sell_u / sell_c
assert 81400 < vwap < 81450
def test_old_bug_would_double_count_large_fill():
"""对照:若按同 ts 永远取第一笔 USDT,会得到 ~3913 而非 ~2415."""
mod = _load_repair()
c = _mk_conn()
rows = [
(23, "t0", "option_close", "BTC", "trading", 0.01, "sell BTC-USD-X"),
(24, "t1", "convert", "BTC", "trading", -0.01, "BTC/USDT mkt 1"),
(25, "t1", "convert", "USDT", "trading", 900.0, "from btc"),
(26, "t2", "convert", "BTC", "trading", -0.02, "BTC/USDT mkt 1"),
(27, "t2", "convert", "USDT", "trading", 1500.0, "from btc"),
(28, "t2", "convert", "BTC", "trading", -0.0001, "BTC/USDT mkt 1"),
(29, "t2", "convert", "USDT", "trading", 1.5, "from btc"),
]
c.executemany(
"INSERT INTO sim_ledger_entries(id,ts,kind,ccy,account,amount,note) VALUES (?,?,?,?,?,?,?)",
rows,
)
_, _, sell_u, sell_c = mod._ledger_buy_sell(
c, underly="BTC", inst_id="BTC-USD-X", open_ts="", close_ts=""
)
assert sell_u == 2401.5
assert abs(float(sell_c) - 0.0301) < 1e-12