a7015ec5c8
每次部分成交累加权利金与张数,全平后再合计 realized_pnl,并优先匹配交易所全平历史。 Co-authored-by: Cursor <cursoragent@cursor.com>
244 lines
7.9 KiB
Python
244 lines
7.9 KiB
Python
"""期权模块 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
|
|
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
|