Files
crypto_monitor/scripts/dedupe_strategy_snapshots.py
T
dekun e71bfe095c Prevent duplicate strategy trade snapshots on plan close.
Finalize plans before writing snapshots, dedupe on startup and page load, and add a cleanup script for existing repeated rows.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-08 09:00:51 +08:00

68 lines
2.2 KiB
Python

#!/usr/bin/env python3
"""清理 strategy_trade_snapshots 重复行(同计划 + 同结果仅保留 id 最大的一条)。
用法(在实例目录,如 crypto_monitor_gate_bot):
python ../scripts/dedupe_strategy_snapshots.py
python ../scripts/dedupe_strategy_snapshots.py --db crypto.db
"""
from __future__ import annotations
import argparse
import os
import sqlite3
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))
from strategy_snapshot_lib import dedupe_strategy_snapshots, init_strategy_snapshot_table # noqa: E402
def main() -> int:
parser = argparse.ArgumentParser(description="Dedupe strategy_trade_snapshots rows.")
parser.add_argument(
"--db",
default=os.getenv("DB_PATH", "crypto.db"),
help="SQLite database path (default: DB_PATH or crypto.db)",
)
parser.add_argument("--dry-run", action="store_true", help="Count only, do not delete")
args = parser.parse_args()
db_path = Path(args.db)
if not db_path.is_file():
print(f"DB not found: {db_path}", file=sys.stderr)
return 1
conn = sqlite3.connect(str(db_path))
conn.row_factory = sqlite3.Row
init_strategy_snapshot_table(conn)
before = conn.execute("SELECT COUNT(*) AS c FROM strategy_trade_snapshots").fetchone()["c"]
dup_groups = conn.execute(
"""SELECT strategy_type, source_id, result_label, COUNT(*) AS n
FROM strategy_trade_snapshots
GROUP BY strategy_type, source_id, result_label
HAVING n > 1
ORDER BY n DESC"""
).fetchall()
extra = sum(int(r["n"]) - 1 for r in dup_groups)
print(f"snapshots total={before}, duplicate rows to remove={extra}, groups={len(dup_groups)}")
for r in dup_groups[:20]:
print(
f" {r['strategy_type']} plan={r['source_id']} "
f"{r['result_label']} x{r['n']}"
)
if args.dry_run:
conn.close()
return 0
removed = dedupe_strategy_snapshots(conn)
conn.commit()
after = conn.execute("SELECT COUNT(*) AS c FROM strategy_trade_snapshots").fetchone()["c"]
conn.close()
print(f"removed={removed}, remaining={after}")
return 0
if __name__ == "__main__":
raise SystemExit(main())