"""期权模块 SQLite 表.""" from __future__ import annotations import sqlite3 def init_options_tables(conn: sqlite3.Connection) -> None: from lib.options.options_review_db import init_options_review_tables conn.execute( """ CREATE TABLE IF NOT EXISTS options_trades ( id INTEGER PRIMARY KEY AUTOINCREMENT, inst_id TEXT NOT NULL, underlying TEXT NOT NULL, opt_type TEXT NOT NULL, strike REAL, exp_time TEXT, sheets INTEGER NOT NULL, eth_amount REAL NOT NULL, open_quote REAL, premium_paid REAL, status TEXT DEFAULT 'open', close_quote REAL, premium_received REAL, realized_pnl REAL, profit_alert_sent INTEGER DEFAULT 0, signal_note TEXT, exchange_ord_id TEXT, close_ord_id TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, closed_at TIMESTAMP ) """ ) conn.execute( """ CREATE TABLE IF NOT EXISTS options_convert_log ( id INTEGER PRIMARY KEY AUTOINCREMENT, from_ccy TEXT, to_ccy TEXT, rfq_sz REAL, received_sz REAL, quote_id TEXT, status TEXT, message TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) """ ) conn.execute( """ CREATE TABLE IF NOT EXISTS options_history_hidden ( history_key TEXT PRIMARY KEY, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) """ ) conn.execute( """ CREATE TABLE IF NOT EXISTS options_transfer_log ( id INTEGER PRIMARY KEY AUTOINCREMENT, ccy TEXT, amount REAL, from_account TEXT, to_account TEXT, status TEXT, message TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) """ ) conn.execute( """ CREATE TABLE IF NOT EXISTS options_target_monitors ( id INTEGER PRIMARY KEY AUTOINCREMENT, inst_id TEXT NOT NULL, underlying TEXT, opt_type TEXT, target_index REAL NOT NULL, trade_id INTEGER, sheets INTEGER, status TEXT DEFAULT 'active', trigger_idx REAL, close_ord_id TEXT, message TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, triggered_at TIMESTAMP ) """ ) conn.execute( """ CREATE INDEX IF NOT EXISTS idx_options_target_monitors_status ON options_target_monitors(status) """ ) for ddl in ( "ALTER TABLE options_trades ADD COLUMN wechat_open_sent INTEGER DEFAULT 0", "ALTER TABLE options_trades ADD COLUMN wechat_close_sent INTEGER DEFAULT 0", "ALTER TABLE options_trades ADD COLUMN profit_exit_enabled INTEGER DEFAULT 0", "ALTER TABLE options_trades ADD COLUMN profit_exit_mult REAL DEFAULT 1.0", "ALTER TABLE options_trades ADD COLUMN profit_exit_state TEXT DEFAULT 'idle'", "ALTER TABLE options_trades ADD COLUMN margin_mode TEXT DEFAULT 'usdc'", "ALTER TABLE options_trades ADD COLUMN premium_ccy TEXT DEFAULT 'USDC'", "ALTER TABLE options_trades ADD COLUMN bridge_id INTEGER", "ALTER TABLE options_trades ADD COLUMN budget_usdt REAL", # 分批平仓累计:全平前写在最早一笔 open 上,全平后并入 premium_received "ALTER TABLE options_trades ADD COLUMN close_recv_accum REAL DEFAULT 0", "ALTER TABLE options_trades ADD COLUMN close_sheets_accum INTEGER DEFAULT 0", "ALTER TABLE options_trades ADD COLUMN close_notional_accum REAL DEFAULT 0", ): try: conn.execute(ddl) except Exception: pass try: from lib.options.options_spot_bridge_lib import ensure_bridge_table ensure_bridge_table(conn) except Exception: pass try: from lib.options.options_cond_order_lib import ensure_cond_order_table ensure_cond_order_table(conn) except Exception: pass init_options_review_tables(conn) def sum_open_premium_paid(conn: sqlite3.Connection, inst_id: str) -> float | None: """同合约所有 open 腿权利金合计(加仓后显示/门控用).""" inst = (inst_id or "").strip() if not inst: return None row = conn.execute( """ SELECT SUM(premium_paid) AS total, COUNT(*) AS n FROM options_trades WHERE inst_id = ? AND status = 'open' AND premium_paid IS NOT NULL """, (inst,), ).fetchone() if not row or int(row["n"] or 0) < 1: return None # 币本位权利金常 <1e-4,保留 8 位避免被裁成 0 return round(float(row["total"] or 0), 8) def sum_open_sheets(conn: sqlite3.Connection, inst_id: str) -> int | None: """同合约所有 open 腿张数合计.""" inst = (inst_id or "").strip() if not inst: return None row = conn.execute( """ SELECT SUM(sheets) AS total, COUNT(*) AS n FROM options_trades WHERE inst_id = ? AND status = 'open' """, (inst,), ).fetchone() if not row or int(row["n"] or 0) < 1: return None return int(row["total"] or 0) def _earliest_open_trade_id(conn: sqlite3.Connection, inst_id: str) -> int | None: inst = (inst_id or "").strip() if not inst: return None row = conn.execute( """ SELECT id FROM options_trades WHERE inst_id = ? AND status = 'open' ORDER BY id ASC LIMIT 1 """, (inst,), ).fetchone() return int(row["id"]) if row else None def get_open_close_accum(conn: sqlite3.Connection, inst_id: str) -> dict[str, float | int | str | None]: """读取分批平仓累计(挂在最早一笔 open 上).""" tid = _earliest_open_trade_id(conn, inst_id) if tid is None: return {"recv": 0.0, "sheets": 0, "notional": 0.0, "close_ord_id": None} row = conn.execute( """ SELECT close_recv_accum, close_sheets_accum, close_notional_accum, close_ord_id FROM options_trades WHERE id = ? """, (tid,), ).fetchone() if not row: return {"recv": 0.0, "sheets": 0, "notional": 0.0, "close_ord_id": None} return { "recv": float(row["close_recv_accum"] or 0), "sheets": int(row["close_sheets_accum"] or 0), "notional": float(row["close_notional_accum"] or 0), "close_ord_id": str(row["close_ord_id"] or "").strip() or None, } def add_open_close_accum( conn: sqlite3.Connection, inst_id: str, *, recv: float, sheets: int, px: float, ord_id: str | None = None, ) -> bool: """分批平仓成交后累加收回权利金/张数/名义(供全平 VWAP 与总盈亏).""" tid = _earliest_open_trade_id(conn, inst_id) if tid is None: return False sheets_i = max(0, int(sheets or 0)) recv_f = float(recv or 0) px_f = float(px or 0) if sheets_i < 1 and abs(recv_f) < 1e-15: return False notional_add = px_f * sheets_i if sheets_i > 0 and px_f > 0 else 0.0 oid = str(ord_id or "").strip() prev = conn.execute( "SELECT close_ord_id FROM options_trades WHERE id = ?", (tid,) ).fetchone() prev_oids = str((prev["close_ord_id"] if prev else None) or "").strip() if oid: parts = [p for p in prev_oids.split(",") if p] if prev_oids else [] if oid not in parts: parts.append(oid) merged_oid = ",".join(parts) else: merged_oid = prev_oids or None conn.execute( """ UPDATE options_trades SET close_recv_accum = COALESCE(close_recv_accum, 0) + ?, close_sheets_accum = COALESCE(close_sheets_accum, 0) + ?, close_notional_accum = COALESCE(close_notional_accum, 0) + ?, close_ord_id = ? WHERE id = ? """, (recv_f, sheets_i, notional_add, merged_oid, tid), ) return True