修复比特币期权浮盈把币数量当成 U:看板/中控改为按指数折 USDT。
币本位 BTC/ETH 净盈亏须 × 指数后再标 U;并兜底从合约推断 premium_ccy,避免缺失时漏折算。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -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 "-"
|
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()
|
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")
|
label = "Call" if opt_type == "C" else "Put" if opt_type == "P" else (opt_type or "OPT")
|
||||||
# 看板期权列:优先买一净盈亏,残档回退交易所 upl
|
# 看板期权列:统一折成 U(币本位 BTC/ETH 权利金盈亏 × 指数)
|
||||||
pnl = None
|
pnl = None
|
||||||
try:
|
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:
|
except Exception:
|
||||||
pnl = None
|
pnl = None
|
||||||
pos = _safe_float(p.get("pos"))
|
pos = _safe_float(p.get("pos"))
|
||||||
|
|||||||
@@ -85,13 +85,13 @@ def build_options_hub_snapshot(cfg: dict[str, Any]) -> dict[str, Any]:
|
|||||||
conn.close()
|
conn.close()
|
||||||
except Exception:
|
except Exception:
|
||||||
target_monitors = []
|
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
|
upl_total = 0.0
|
||||||
has_upl = False
|
has_upl = False
|
||||||
for p in positions:
|
for p in positions:
|
||||||
# 与持仓卡展示一致:优先买一净盈亏,残档回退交易所 upl
|
# 合计一律折 U:币本位 × 指数,避免 BTC/ETH 币数量与 USDC 混加
|
||||||
pnl = display_pnl_from_option_row(p)
|
pnl = display_pnl_usdt_from_option_row(p)
|
||||||
if pnl is None:
|
if pnl is None:
|
||||||
continue
|
continue
|
||||||
has_upl = True
|
has_upl = True
|
||||||
|
|||||||
@@ -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:
|
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)
|
pnl = display_pnl_from_option_row(row)
|
||||||
if pnl is None:
|
if pnl is None:
|
||||||
return None
|
return None
|
||||||
ccy = str(row.get("premium_ccy") or "USDC").strip().upper() or "USDC"
|
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"):
|
if ccy in ("ETH", "BTC"):
|
||||||
idx = _safe_float(row.get("idx_px") or row.get("idxPx") or row.get("index_px"))
|
idx = _safe_float(row.get("idx_px") or row.get("idxPx") or row.get("index_px"))
|
||||||
if idx is None or idx <= 0:
|
if idx is None or idx <= 0:
|
||||||
|
|||||||
@@ -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()
|
||||||
Reference in New Issue
Block a user