Persist options review deletes across local resync.
Hide deleted rows by history key and contract/close fingerprint so local options_trades imports no longer resurrect them. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -83,11 +83,35 @@ def set_sync_state(conn: sqlite3.Connection, key: str, value: str) -> None:
|
||||
)
|
||||
|
||||
|
||||
def _purge_review_trade_by_key(conn: sqlite3.Connection, history_key: str) -> bool:
|
||||
"""删除已导入的复盘快照(含复盘内容)."""
|
||||
key = str(history_key or "").strip()
|
||||
if not key:
|
||||
return False
|
||||
existing = conn.execute(
|
||||
"SELECT id FROM options_review_trades WHERE history_key=?", (key,)
|
||||
).fetchone()
|
||||
if not existing:
|
||||
return False
|
||||
tid = int(existing["id"])
|
||||
conn.execute("DELETE FROM options_review_entries WHERE trade_id=?", (tid,))
|
||||
conn.execute("DELETE FROM options_review_trades WHERE id=?", (tid,))
|
||||
return True
|
||||
|
||||
|
||||
def upsert_option_history_row(conn: sqlite3.Connection, row: dict[str, Any]) -> str:
|
||||
"""幂等写入纯期权快照;不触碰 options_review_entries."""
|
||||
"""幂等写入纯期权快照;不触碰 options_review_entries;已隐藏的不再导入."""
|
||||
history_key = str(row.get("history_key") or "").strip()
|
||||
if not history_key:
|
||||
return "skip"
|
||||
if is_review_hidden(
|
||||
conn,
|
||||
history_key,
|
||||
inst_id=str(row.get("inst_id") or "").strip() or None,
|
||||
closed_at=row.get("closed_at") or row.get("created_at"),
|
||||
):
|
||||
# 若此前已导入,清掉,避免列表残留
|
||||
return "purged" if _purge_review_trade_by_key(conn, history_key) else "hidden"
|
||||
opened_at = row.get("created_at") or row.get("opened_at")
|
||||
closed_at = row.get("closed_at")
|
||||
pnl = _safe_float(row.get("realized_pnl"))
|
||||
@@ -133,6 +157,120 @@ def upsert_option_history_row(conn: sqlite3.Connection, row: dict[str, Any]) ->
|
||||
return "inserted"
|
||||
|
||||
|
||||
def _close_fingerprint(inst_id: Any, closed_at: Any) -> str | None:
|
||||
inst = str(inst_id or "").strip()
|
||||
if not inst:
|
||||
return None
|
||||
closed = str(closed_at or "").strip()
|
||||
if not closed:
|
||||
return f"inst:{inst}"
|
||||
# 精确到分钟,避免秒差导致漏匹配
|
||||
return f"inst_close:{inst}:{closed[:16]}"
|
||||
|
||||
|
||||
def is_review_hidden(
|
||||
conn: sqlite3.Connection,
|
||||
history_key: str,
|
||||
*,
|
||||
inst_id: str | None = None,
|
||||
closed_at: Any = None,
|
||||
) -> bool:
|
||||
init_options_review_tables(conn)
|
||||
key = str(history_key or "").strip()
|
||||
if key and conn.execute(
|
||||
"SELECT 1 FROM options_review_hidden WHERE history_key=? LIMIT 1", (key,)
|
||||
).fetchone():
|
||||
return True
|
||||
fp = _close_fingerprint(inst_id, closed_at)
|
||||
if fp and conn.execute(
|
||||
"SELECT 1 FROM options_review_hidden WHERE history_key=? LIMIT 1", (fp,)
|
||||
).fetchone():
|
||||
return True
|
||||
# 期权历史页删除:options_history_hidden,按合约指纹或原 key
|
||||
try:
|
||||
if key and conn.execute(
|
||||
"SELECT 1 FROM options_history_hidden WHERE history_key=? LIMIT 1", (key,)
|
||||
).fetchone():
|
||||
return True
|
||||
if fp and conn.execute(
|
||||
"SELECT 1 FROM options_history_hidden WHERE history_key=? LIMIT 1", (fp,)
|
||||
).fetchone():
|
||||
return True
|
||||
# 仅隐藏了 ex:posId 时,用合约+平仓时间在历史隐藏表无直接命中;
|
||||
# 若指纹已写入 options_review_hidden(新删除路径)上面已覆盖.
|
||||
# 兼容:inst 级隐藏
|
||||
if inst_id:
|
||||
inst_fp = f"inst:{str(inst_id).strip()}"
|
||||
if conn.execute(
|
||||
"SELECT 1 FROM options_review_hidden WHERE history_key=? LIMIT 1",
|
||||
(inst_fp,),
|
||||
).fetchone():
|
||||
return True
|
||||
if conn.execute(
|
||||
"SELECT 1 FROM options_history_hidden WHERE history_key=? LIMIT 1",
|
||||
(inst_fp,),
|
||||
).fetchone():
|
||||
return True
|
||||
except Exception:
|
||||
pass
|
||||
return False
|
||||
|
||||
|
||||
def hide_review_keys(
|
||||
conn: sqlite3.Connection,
|
||||
*,
|
||||
history_key: str,
|
||||
inst_id: str | None = None,
|
||||
closed_at: Any = None,
|
||||
) -> None:
|
||||
init_options_review_tables(conn)
|
||||
keys = [str(history_key or "").strip()]
|
||||
fp = _close_fingerprint(inst_id, closed_at)
|
||||
if fp:
|
||||
keys.append(fp)
|
||||
for k in keys:
|
||||
if not k:
|
||||
continue
|
||||
conn.execute(
|
||||
"""
|
||||
INSERT OR IGNORE INTO options_review_hidden(history_key, inst_id, closed_at)
|
||||
VALUES (?, ?, ?)
|
||||
""",
|
||||
(k, (inst_id or None), str(closed_at or "")[:19] or None),
|
||||
)
|
||||
try:
|
||||
conn.execute(
|
||||
"INSERT OR IGNORE INTO options_history_hidden(history_key) VALUES (?)",
|
||||
(k,),
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def hide_review_trade(conn: sqlite3.Connection, trade_id: int) -> dict[str, Any]:
|
||||
"""从复盘列表删除并持久隐藏,刷新本地源也不会再回来."""
|
||||
init_options_review_tables(conn)
|
||||
row = conn.execute(
|
||||
"SELECT * FROM options_review_trades WHERE id=?", (int(trade_id),)
|
||||
).fetchone()
|
||||
if not row:
|
||||
return {"ok": False, "msg": "记录不存在"}
|
||||
d = _row_to_dict(row)
|
||||
hide_review_keys(
|
||||
conn,
|
||||
history_key=str(d.get("history_key") or ""),
|
||||
inst_id=str(d.get("inst_id") or "").strip() or None,
|
||||
closed_at=d.get("closed_at") or d.get("opened_at"),
|
||||
)
|
||||
entry = conn.execute(
|
||||
"SELECT * FROM options_review_entries WHERE trade_id=?", (int(trade_id),)
|
||||
).fetchone()
|
||||
conn.execute("DELETE FROM options_review_entries WHERE trade_id=?", (int(trade_id),))
|
||||
conn.execute("DELETE FROM options_review_trades WHERE id=?", (int(trade_id),))
|
||||
return {"ok": True, "entry": _row_to_dict(entry) if entry else None, "history_key": d.get("history_key")}
|
||||
|
||||
|
||||
|
||||
def sync_options_from_local_trades(conn: sqlite3.Connection) -> dict[str, Any]:
|
||||
"""从本地 options_trades 已平仓记录导入复盘快照(不访问交易所)."""
|
||||
init_options_review_tables(conn)
|
||||
@@ -282,6 +420,13 @@ def upsert_hedge_plan_row(
|
||||
return "skip"
|
||||
opened_at = plan.get("opened_at") or plan.get("created_at")
|
||||
closed_at = plan.get("closed_at")
|
||||
if is_review_hidden(
|
||||
conn,
|
||||
history_key,
|
||||
inst_id=None,
|
||||
closed_at=closed_at,
|
||||
):
|
||||
return "purged" if _purge_review_trade_by_key(conn, history_key) else "hidden"
|
||||
total = _safe_float(plan.get("realized_pnl_total"))
|
||||
hold = _hold_seconds(opened_at, closed_at)
|
||||
fields = {
|
||||
|
||||
Reference in New Issue
Block a user