diff --git a/lib/instance/instance_dashboard_lib.py b/lib/instance/instance_dashboard_lib.py index 70df9c2..824065b 100644 --- a/lib/instance/instance_dashboard_lib.py +++ b/lib/instance/instance_dashboard_lib.py @@ -162,12 +162,12 @@ def _format_options_item(p: dict[str, Any], *, conn=None) -> dict[str, Any]: inst = str(p.get("inst_id") or p.get("instId") or "-").strip() or "-" opt_type = str(p.get("opt_type") or p.get("optType") or "").upper() label = "Call" if opt_type == "C" else "Put" if opt_type == "P" else (opt_type or "OPT") - # 看板期权列:优先买一净盈亏,残档回退交易所 upl + # 看板期权列:统一折成 U(币本位 BTC/ETH 权利金盈亏 × 指数) pnl = None try: - from lib.options.options_positions_lib import display_pnl_from_option_row + from lib.options.options_positions_lib import display_pnl_usdt_from_option_row - pnl = display_pnl_from_option_row(p) + pnl = display_pnl_usdt_from_option_row(p) except Exception: pnl = None pos = _safe_float(p.get("pos")) diff --git a/lib/options/options_hub_lib.py b/lib/options/options_hub_lib.py index 4e0cdd8..021778b 100644 --- a/lib/options/options_hub_lib.py +++ b/lib/options/options_hub_lib.py @@ -85,13 +85,13 @@ def build_options_hub_snapshot(cfg: dict[str, Any]) -> dict[str, Any]: conn.close() except Exception: target_monitors = [] - from lib.options.options_positions_lib import display_pnl_from_option_row + from lib.options.options_positions_lib import display_pnl_usdt_from_option_row upl_total = 0.0 has_upl = False for p in positions: - # 与持仓卡展示一致:优先买一净盈亏,残档回退交易所 upl - pnl = display_pnl_from_option_row(p) + # 合计一律折 U:币本位 × 指数,避免 BTC/ETH 币数量与 USDC 混加 + pnl = display_pnl_usdt_from_option_row(p) if pnl is None: continue has_upl = True diff --git a/lib/options/options_positions_lib.py b/lib/options/options_positions_lib.py index e97a762..fb9737f 100644 --- a/lib/options/options_positions_lib.py +++ b/lib/options/options_positions_lib.py @@ -125,11 +125,24 @@ def display_pnl_from_option_row(row: dict[str, Any]) -> float | None: def display_pnl_usdt_from_option_row(row: dict[str, Any]) -> float | None: - """顶栏「实时盈亏」用:币本位净盈亏按指数折 USDT;USDC 仓原样.""" + """顶栏/看板「实时盈亏」用:币本位净盈亏按指数折 USDT;USDC 仓原样. + + BTC/ETH 币本位若不折算,会被界面标成 U 而数值仍是币数量(BTC 尤为离谱). + """ pnl = display_pnl_from_option_row(row) if pnl is None: return None ccy = str(row.get("premium_ccy") or "USDC").strip().upper() or "USDC" + if not ccy or ccy == "USDC": + # 兜底:按合约推断币本位,避免 premium_ccy 缺失时把 BTC 盈亏当 U + inst = str(row.get("inst_id") or row.get("instId") or "") + mode = str(row.get("margin_mode") or "").strip().lower() + if mode == "coin" or ( + "-USD-" in inst.upper() and "_UM" not in inst.upper() + ): + underly = str(row.get("underlying") or (inst.split("-")[0] if inst else "") or "").upper() + if underly in ("ETH", "BTC"): + ccy = underly if ccy in ("ETH", "BTC"): idx = _safe_float(row.get("idx_px") or row.get("idxPx") or row.get("index_px")) if idx is None or idx <= 0: diff --git a/tests/test_options_btc_pnl_usdt.py b/tests/test_options_btc_pnl_usdt.py new file mode 100644 index 0000000..491d173 --- /dev/null +++ b/tests/test_options_btc_pnl_usdt.py @@ -0,0 +1,45 @@ +"""币本位期权浮盈折 U(BTC/ETH 不得把币数量直接当 U).""" +from __future__ import annotations + +import unittest + +from lib.options.options_positions_lib import display_pnl_usdt_from_option_row + + +class DisplayPnlUsdtTests(unittest.TestCase): + def test_btc_coin_pnl_times_index(self): + row = { + "inst_id": "BTC-USD-260327-100000-P", + "premium_ccy": "BTC", + "margin_mode": "coin", + "idx_px": 100000.0, + "upl": -0.001, + "close_preview": {"bid_invalid": True}, + } + # 残档回退 upl: -0.001 BTC × 100000 = -100 U + self.assertAlmostEqual(display_pnl_usdt_from_option_row(row), -100.0, places=4) + + def test_btc_infers_ccy_when_premium_ccy_missing(self): + row = { + "inst_id": "BTC-USD-260327-100000-C", + "margin_mode": "coin", + "underlying": "BTC", + "idx_px": 95000.0, + "upl": 0.002, + "close_preview": {"bid_invalid": True}, + } + self.assertAlmostEqual(display_pnl_usdt_from_option_row(row), 190.0, places=4) + + def test_usdc_unchanged(self): + row = { + "inst_id": "BTC-USD_UM-260327-100000-C", + "premium_ccy": "USDC", + "margin_mode": "usdc", + "upl": -12.5, + "close_preview": {"bid_invalid": True}, + } + self.assertAlmostEqual(display_pnl_usdt_from_option_row(row), -12.5, places=4) + + +if __name__ == "__main__": + unittest.main()