diff --git a/lib/common/static/options_panel.js b/lib/common/static/options_panel.js
index 35716c4..21bf756 100644
--- a/lib/common/static/options_panel.js
+++ b/lib/common/static/options_panel.js
@@ -444,6 +444,7 @@
'张数: ' + fmt(p.pos, 0) + " · 币量 " + fmt(p.eth_amount, 4) + "" +
"" +
'
' +
+ '
权利金' + fmt(p.premium_paid, 4) + " USDC
" +
'
开仓均价' + fmt(p.avg_px, 4) + "
" +
'
标记价' + fmt(p.mark_px, 4) + "
" +
'
指数价' + fmt(p.idx_px, 0) + "
" +
diff --git a/lib/exchange/okx_options_lib.py b/lib/exchange/okx_options_lib.py
index 62df52d..8d002cb 100644
--- a/lib/exchange/okx_options_lib.py
+++ b/lib/exchange/okx_options_lib.py
@@ -216,6 +216,17 @@ def inst_family_from_inst_id(inst_id: str) -> str | None:
return "-".join(parts[:-3])
+def option_fields_from_inst_id(inst_id: str) -> tuple[str | None, float | None]:
+ """从 instId 解析 optType 与 strike,如 ETH-USD_UM-260709-1700-P。"""
+ parts = (inst_id or "").strip().split("-")
+ if len(parts) < 2:
+ return None, None
+ tail = parts[-1].upper()
+ opt_type = tail if tail in ("C", "P") else None
+ strike = _safe_float(parts[-2]) if len(parts) >= 2 else None
+ return opt_type, strike
+
+
def fetch_option_instrument_meta(ex: ccxt.okx, inst_id: str) -> dict[str, Any] | None:
family = inst_family_from_inst_id(inst_id)
if not family:
@@ -778,6 +789,7 @@ def format_position_row(pos: dict[str, Any], ct_mult: float = 0.01) -> dict[str,
close_breakeven_idx,
expiry_breakeven_px,
idx_distance_to_be,
+ total_premium,
)
sheets = _safe_float(pos.get("pos")) or 0.0
@@ -786,8 +798,18 @@ def format_position_row(pos: dict[str, Any], ct_mult: float = 0.01) -> dict[str,
upl = _safe_float(pos.get("upl"))
upl_ratio = _safe_float(pos.get("uplRatio"))
idx_px = _safe_float(pos.get("idxPx"))
+ inst_id = str(pos.get("instId") or "")
opt_type = pos.get("optType")
strike = _safe_float(pos.get("stk"))
+ parsed_type, parsed_strike = option_fields_from_inst_id(inst_id)
+ if not opt_type:
+ opt_type = parsed_type
+ if strike is None:
+ strike = parsed_strike
+ eth_amount = round(abs(sheets) * ct_mult, 8)
+ premium_paid = (
+ round(total_premium(avg, eth_amount), 4) if avg is not None and eth_amount > 0 else None
+ )
delta_pa = _safe_float(pos.get("deltaPA"))
expiry_be = expiry_breakeven_px(
opt_type=str(opt_type or ""),
@@ -805,12 +827,13 @@ def format_position_row(pos: dict[str, Any], ct_mult: float = 0.01) -> dict[str,
ct_mult=ct_mult,
)
return {
- "inst_id": pos.get("instId"),
+ "inst_id": inst_id or pos.get("instId"),
"pos": sheets,
- "eth_amount": round(abs(sheets) * ct_mult, 8),
+ "eth_amount": eth_amount,
"avg_px": avg,
"mark_px": mark,
"idx_px": idx_px,
+ "premium_paid": premium_paid,
"upl": upl,
"upl_ratio_pct": round(upl_ratio * 100, 2) if upl_ratio is not None else None,
"exp_time": pos.get("expTime"),
diff --git a/lib/options/options_register.py b/lib/options/options_register.py
index 45903e3..d17e508 100644
--- a/lib/options/options_register.py
+++ b/lib/options/options_register.py
@@ -306,6 +306,24 @@ def register_options_routes(app: Flask, cfg: dict[str, Any]) -> None:
return jsonify({"ok": False, "msg": err})
raw = cfg["fetch_option_positions"](ex)
rows = [cfg["format_position_row"](p) for p in raw]
+ conn = cfg["get_db"]()
+ try:
+ for row in rows:
+ inst = row.get("inst_id")
+ if not inst:
+ continue
+ rec = conn.execute(
+ """
+ SELECT premium_paid FROM options_trades
+ WHERE inst_id = ? AND status = 'open'
+ ORDER BY id DESC LIMIT 1
+ """,
+ (inst,),
+ ).fetchone()
+ if rec and rec["premium_paid"] is not None:
+ row["premium_paid"] = round(float(rec["premium_paid"]), 4)
+ finally:
+ conn.close()
return jsonify({"ok": True, "positions": rows})
@app.route("/api/options/close", methods=["POST"])
diff --git a/lib/options/templates/options_panel.html b/lib/options/templates/options_panel.html
index 2a1b8d3..40aa664 100644
--- a/lib/options/templates/options_panel.html
+++ b/lib/options/templates/options_panel.html
@@ -136,4 +136,4 @@
-
+
diff --git a/tests/test_options_pricing.py b/tests/test_options_pricing.py
index 295bdb9..df94e80 100644
--- a/tests/test_options_pricing.py
+++ b/tests/test_options_pricing.py
@@ -202,6 +202,25 @@ def test_format_options_breakeven_line():
assert "指数3480" in s
+def test_format_position_row_premium_and_inst_parse():
+ from lib.exchange.okx_options_lib import format_position_row
+
+ row = format_position_row(
+ {
+ "instId": "ETH-USD_UM-260709-1700-P",
+ "pos": "20",
+ "avgPx": "6.2",
+ "markPx": "6.3241",
+ "idxPx": "1746",
+ "upl": "0.0248",
+ "uplRatio": "0.02",
+ }
+ )
+ assert row["opt_type"] == "P"
+ assert row["strike"] == 1700.0
+ assert row["premium_paid"] == 1.24
+
+
def test_format_position_row_breakeven():
from lib.exchange.okx_options_lib import format_position_row