fix(hub): merge strategy snapshots into archive for gate_bot
Include strategy_trade_snapshots when trade_records is empty, harden SQL for older schemas, and show per-exchange sync errors in the archive UI. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
"""档案交易:strategy_trade_snapshots 补全 gate_bot 漏记。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sqlite3
|
||||
import tempfile
|
||||
from datetime import datetime, timedelta
|
||||
from pathlib import Path
|
||||
|
||||
from hub_trades_lib import fetch_trades_for_archive
|
||||
|
||||
|
||||
def _init_db(path: Path) -> sqlite3.Connection:
|
||||
conn = sqlite3.connect(str(path))
|
||||
conn.row_factory = sqlite3.Row
|
||||
conn.execute(
|
||||
"""
|
||||
CREATE TABLE trade_records (
|
||||
id INTEGER PRIMARY KEY,
|
||||
symbol TEXT,
|
||||
direction TEXT,
|
||||
result TEXT,
|
||||
pnl_amount REAL,
|
||||
opened_at TEXT,
|
||||
closed_at TEXT,
|
||||
opened_at_ms INTEGER,
|
||||
closed_at_ms INTEGER,
|
||||
created_at TEXT,
|
||||
trend_plan_id INTEGER
|
||||
)
|
||||
"""
|
||||
)
|
||||
conn.execute(
|
||||
"""
|
||||
CREATE TABLE strategy_trade_snapshots (
|
||||
id INTEGER PRIMARY KEY,
|
||||
strategy_type TEXT,
|
||||
source_id INTEGER,
|
||||
symbol TEXT,
|
||||
direction TEXT,
|
||||
result_label TEXT,
|
||||
status_at_close TEXT,
|
||||
opened_at TEXT,
|
||||
closed_at TEXT,
|
||||
pnl_amount REAL,
|
||||
snapshot_json TEXT,
|
||||
created_at TEXT
|
||||
)
|
||||
"""
|
||||
)
|
||||
return conn
|
||||
|
||||
|
||||
def test_merge_snapshot_when_trade_record_missing():
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
conn = _init_db(Path(td) / "t.db")
|
||||
closed = (datetime.now() - timedelta(days=1)).strftime("%Y-%m-%d %H:%M:%S")
|
||||
conn.execute(
|
||||
"""
|
||||
INSERT INTO strategy_trade_snapshots (
|
||||
id, strategy_type, source_id, symbol, direction,
|
||||
result_label, opened_at, closed_at, pnl_amount, snapshot_json, created_at
|
||||
) VALUES (?,?,?,?,?,?,?,?,?,?,?)
|
||||
""",
|
||||
(7, "trend_pullback", 42, "ONDO/USDT", "long", "止损", closed, closed, -1.2, "{}", closed),
|
||||
)
|
||||
conn.commit()
|
||||
trades = fetch_trades_for_archive(conn, days=30, limit=50)
|
||||
conn.close()
|
||||
assert len(trades) == 1
|
||||
assert trades[0]["symbol"] == "ONDO/USDT"
|
||||
assert trades[0]["id"] == -7
|
||||
assert trades[0].get("from_snapshot") is True
|
||||
|
||||
|
||||
def test_skip_snapshot_when_trade_record_exists():
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
conn = _init_db(Path(td) / "t.db")
|
||||
closed = (datetime.now() - timedelta(days=1)).strftime("%Y-%m-%d %H:%M:%S")
|
||||
conn.execute(
|
||||
"""
|
||||
INSERT INTO trade_records (
|
||||
id, symbol, direction, result, pnl_amount,
|
||||
opened_at, closed_at, opened_at_ms, closed_at_ms, created_at, trend_plan_id
|
||||
) VALUES (?,?,?,?,?,?,?,?,?,?,?)
|
||||
""",
|
||||
(1, "ONDO/USDT", "long", "止损", -1.2, closed, closed, 1, 2, closed, 42),
|
||||
)
|
||||
conn.execute(
|
||||
"""
|
||||
INSERT INTO strategy_trade_snapshots (
|
||||
id, strategy_type, source_id, symbol, direction,
|
||||
result_label, opened_at, closed_at, pnl_amount, snapshot_json, created_at
|
||||
) VALUES (?,?,?,?,?,?,?,?,?,?,?)
|
||||
""",
|
||||
(7, "trend_pullback", 42, "ONDO/USDT", "long", "止损", closed, closed, -1.2, "{}", closed),
|
||||
)
|
||||
conn.commit()
|
||||
trades = fetch_trades_for_archive(conn, days=30, limit=50)
|
||||
conn.close()
|
||||
assert len(trades) == 1
|
||||
assert trades[0]["id"] == 1
|
||||
Reference in New Issue
Block a user