fix模拟盘流水重算卖回VWAP时同秒多笔配对去重,避免USDT重复计入。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -104,19 +104,37 @@ def _ledger_buy_sell(
|
|||||||
""",
|
""",
|
||||||
(u, f"{u}/USDT%", start_id, end_id),
|
(u, f"{u}/USDT%", start_id, end_id),
|
||||||
).fetchall()
|
).fetchall()
|
||||||
|
# 同秒多笔卖回时,按「币卖出 id → 下一笔 USDT 入账」配对,避免重复吃到同一笔 USDT
|
||||||
|
used_usdt_ids: set[int] = set()
|
||||||
for row in sells:
|
for row in sells:
|
||||||
|
sid = int(row["id"])
|
||||||
usdt_row = conn.execute(
|
usdt_row = conn.execute(
|
||||||
"""
|
"""
|
||||||
SELECT amount FROM sim_ledger_entries
|
SELECT id, amount FROM sim_ledger_entries
|
||||||
WHERE ccy='USDT' AND account='trading' AND kind='convert'
|
WHERE id = ? AND ccy='USDT' AND account='trading' AND kind='convert'
|
||||||
AND amount > 0 AND ts=? AND note LIKE 'from %'
|
AND amount > 0 AND note LIKE 'from %'
|
||||||
AND id > ? AND id < ?
|
|
||||||
ORDER BY id LIMIT 1
|
|
||||||
""",
|
""",
|
||||||
(row["ts"], start_id, end_id),
|
(sid + 1,),
|
||||||
).fetchone()
|
).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:
|
if not usdt_row:
|
||||||
continue
|
continue
|
||||||
|
uid = int(usdt_row["id"])
|
||||||
|
used_usdt_ids.add(uid)
|
||||||
sell_coin += abs(float(row["amount"]))
|
sell_coin += abs(float(row["amount"]))
|
||||||
sell_usdt += float(usdt_row["amount"])
|
sell_usdt += float(usdt_row["amount"])
|
||||||
return (
|
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
|
||||||
Reference in New Issue
Block a user