Show option bid as price/size and option leverage on plan and trades.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -101,6 +101,36 @@ def _move_points(g: dict, fills: list) -> float | None:
|
|||||||
return round(float(close_px) - e, 2)
|
return round(float(close_px) - e, 2)
|
||||||
|
|
||||||
|
|
||||||
|
def _option_entry_px(fills: list) -> float | None:
|
||||||
|
for row in fills:
|
||||||
|
f = dict(row) if not isinstance(row, dict) else row
|
||||||
|
if str(f.get("leg") or "") != "option" or str(f.get("action") or "") != "open":
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
v = float(f.get("fill_px") or 0)
|
||||||
|
if v > 0:
|
||||||
|
return v
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
pass
|
||||||
|
break
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _option_leverage(g: dict, fills: list) -> float | None:
|
||||||
|
"""开仓期权杠杆 = 开仓指数 ÷ 期权开仓均价(与选约门限口径一致)。"""
|
||||||
|
from ..strategy.selection import option_leverage
|
||||||
|
|
||||||
|
try:
|
||||||
|
entry = float(g.get("entry_index_px") or 0)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
return None
|
||||||
|
opt_px = _option_entry_px(fills)
|
||||||
|
if entry <= 0 or opt_px is None:
|
||||||
|
return None
|
||||||
|
lev = option_leverage(entry, opt_px)
|
||||||
|
return round(float(lev), 1) if lev is not None else None
|
||||||
|
|
||||||
|
|
||||||
def _enrich_group(g: dict, fills: list) -> dict:
|
def _enrich_group(g: dict, fills: list) -> dict:
|
||||||
summary = summarize_fills_pnl(fills)
|
summary = summarize_fills_pnl(fills)
|
||||||
# LIVE:优先 groups.realized_pnl(已按交易所回写,含资金费)
|
# LIVE:优先 groups.realized_pnl(已按交易所回写,含资金费)
|
||||||
@@ -124,6 +154,7 @@ def _enrich_group(g: dict, fills: list) -> dict:
|
|||||||
mp = _move_points(g, fills)
|
mp = _move_points(g, fills)
|
||||||
g["move_points"] = mp
|
g["move_points"] = mp
|
||||||
g["close_index_px"] = _close_index_px(g, fills)
|
g["close_index_px"] = _close_index_px(g, fills)
|
||||||
|
g["option_leverage"] = _option_leverage(g, fills)
|
||||||
return g
|
return g
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1034,6 +1034,7 @@ class Matcher:
|
|||||||
option_upl = 0.0
|
option_upl = 0.0
|
||||||
est_opt_close_fee = 0.0
|
est_opt_close_fee = 0.0
|
||||||
opt_mark = None
|
opt_mark = None
|
||||||
|
opt_bid_sz = None
|
||||||
if oq and oq.bid is not None:
|
if oq and oq.bid is not None:
|
||||||
bid = float(oq.bid)
|
bid = float(oq.bid)
|
||||||
of = option_fill(
|
of = option_fill(
|
||||||
@@ -1045,10 +1046,12 @@ class Matcher:
|
|||||||
)
|
)
|
||||||
est_opt_close_fee = of.fee
|
est_opt_close_fee = of.fee
|
||||||
opt_mark = bid
|
opt_mark = bid
|
||||||
|
opt_bid_sz = float(oq.bid_sz) if oq.bid_sz is not None else None
|
||||||
# 浮盈亏:买一×数量 − 初始权利金(对齐可市价卖出)
|
# 浮盈亏:买一×数量 − 初始权利金(对齐可市价卖出)
|
||||||
option_upl = bid * opt_qty - initial_premium
|
option_upl = bid * opt_qty - initial_premium
|
||||||
elif oq:
|
elif oq:
|
||||||
opt_mark = oq.bid or oq.mark_px
|
opt_mark = oq.bid or oq.mark_px
|
||||||
|
opt_bid_sz = float(oq.bid_sz) if oq.bid_sz is not None else None
|
||||||
if opt_mark is not None:
|
if opt_mark is not None:
|
||||||
option_upl = float(opt_mark) * opt_qty - initial_premium
|
option_upl = float(opt_mark) * opt_qty - initial_premium
|
||||||
|
|
||||||
@@ -1063,6 +1066,11 @@ class Matcher:
|
|||||||
leverage = self.ledger.get_setting_float("leverage", s.leverage)
|
leverage = self.ledger.get_setting_float("leverage", s.leverage)
|
||||||
notional = abs(perp_entry * perp_qty)
|
notional = abs(perp_entry * perp_qty)
|
||||||
margin = notional / leverage if leverage > 0 else None
|
margin = notional / leverage if leverage > 0 else None
|
||||||
|
from ..strategy.selection import option_leverage as _opt_lev
|
||||||
|
|
||||||
|
opt_lev = _opt_lev(entry_idx, opt_entry) if entry_idx > 0 and opt_entry > 0 else None
|
||||||
|
if opt_lev is not None:
|
||||||
|
opt_lev = round(float(opt_lev), 1)
|
||||||
|
|
||||||
group_id = pos.get("group_id")
|
group_id = pos.get("group_id")
|
||||||
g = (
|
g = (
|
||||||
@@ -1105,6 +1113,8 @@ class Matcher:
|
|||||||
"option_qty_eth": opt_qty,
|
"option_qty_eth": opt_qty,
|
||||||
"option_qty_contracts": float(pos["option_qty_contracts"] or 0),
|
"option_qty_contracts": float(pos["option_qty_contracts"] or 0),
|
||||||
"option_mark_px": float(opt_mark) if opt_mark is not None else None,
|
"option_mark_px": float(opt_mark) if opt_mark is not None else None,
|
||||||
|
"option_bid_sz": float(opt_bid_sz) if opt_bid_sz is not None else None,
|
||||||
|
"option_leverage": float(opt_lev) if opt_lev is not None else None,
|
||||||
"strike": strike,
|
"strike": strike,
|
||||||
"expiry_ymd": expiry_ymd,
|
"expiry_ymd": expiry_ymd,
|
||||||
"expiry_ms": expiry_ms,
|
"expiry_ms": expiry_ms,
|
||||||
|
|||||||
@@ -273,6 +273,8 @@ export type PlanState = {
|
|||||||
option_qty_eth?: number;
|
option_qty_eth?: number;
|
||||||
option_qty_contracts?: number;
|
option_qty_contracts?: number;
|
||||||
option_mark_px?: number | null;
|
option_mark_px?: number | null;
|
||||||
|
option_bid_sz?: number | null;
|
||||||
|
option_leverage?: number | null;
|
||||||
strike?: number | null;
|
strike?: number | null;
|
||||||
expiry_ymd?: string | null;
|
expiry_ymd?: string | null;
|
||||||
expiry_ms?: number | null;
|
expiry_ms?: number | null;
|
||||||
|
|||||||
@@ -14,6 +14,14 @@ function fmtTop(px: number | null | undefined, sz: number | null | undefined) {
|
|||||||
return `${fmt(px)}(${s})`;
|
return `${fmt(px)}(${s})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 持仓买一:价格/流动性张数,如 17.00/4000 */
|
||||||
|
function fmtBidLiq(px: number | null | undefined, sz: number | null | undefined) {
|
||||||
|
if (px == null || Number.isNaN(px)) return "—";
|
||||||
|
if (sz == null || Number.isNaN(sz)) return fmt(px);
|
||||||
|
const s = sz >= 100 ? sz.toFixed(0) : sz >= 10 ? sz.toFixed(1) : sz.toFixed(2);
|
||||||
|
return `${fmt(px)}/${s}`;
|
||||||
|
}
|
||||||
|
|
||||||
function pnlClass(n: number | null | undefined) {
|
function pnlClass(n: number | null | undefined) {
|
||||||
if (n == null || Number.isNaN(n) || n === 0) return "";
|
if (n == null || Number.isNaN(n) || n === 0) return "";
|
||||||
return n > 0 ? "pos-pnl-profit" : "pos-pnl-loss";
|
return n > 0 ? "pos-pnl-profit" : "pos-pnl-loss";
|
||||||
@@ -638,6 +646,9 @@ export default function PlanPage() {
|
|||||||
<span className="pos-meta-item mono">
|
<span className="pos-meta-item mono">
|
||||||
{fmt(pos?.option_qty_eth, 2)} ETH · {fmt(pos?.option_qty_contracts, 0)} 张
|
{fmt(pos?.option_qty_eth, 2)} ETH · {fmt(pos?.option_qty_contracts, 0)} 张
|
||||||
</span>
|
</span>
|
||||||
|
<span className="pos-meta-item mono" title="开仓指数÷开仓均价">
|
||||||
|
杠杆 {fmt(pos?.option_leverage, 0)}x
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="pos-grid">
|
<div className="pos-grid">
|
||||||
<div className="pos-cell">
|
<div className="pos-cell">
|
||||||
@@ -646,7 +657,9 @@ export default function PlanPage() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="pos-cell">
|
<div className="pos-cell">
|
||||||
<span className="pos-label">买一</span>
|
<span className="pos-label">买一</span>
|
||||||
<span className="pos-value mono">{fmt(pos?.option_mark_px)}</span>
|
<span className="pos-value mono">
|
||||||
|
{fmtBidLiq(pos?.option_mark_px, pos?.option_bid_sz)}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="pos-cell">
|
<div className="pos-cell">
|
||||||
<span className="pos-label">
|
<span className="pos-label">
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ type Group = {
|
|||||||
entry_index_px?: number | null;
|
entry_index_px?: number | null;
|
||||||
close_index_px?: number | null;
|
close_index_px?: number | null;
|
||||||
move_points?: number | null;
|
move_points?: number | null;
|
||||||
|
option_leverage?: number | null;
|
||||||
exec_mode?: string | null;
|
exec_mode?: string | null;
|
||||||
expiry_settle?: ExpirySettle | null;
|
expiry_settle?: ExpirySettle | null;
|
||||||
pnl_summary?: PnlSummary;
|
pnl_summary?: PnlSummary;
|
||||||
@@ -207,6 +208,9 @@ export default function TradesPage() {
|
|||||||
开 {fmtTime(openMs)} · 平 {fmtTime(closeMs)} · 周期{" "}
|
开 {fmtTime(openMs)} · 平 {fmtTime(closeMs)} · 周期{" "}
|
||||||
{fmtHold(g.hold_ms)}
|
{fmtHold(g.hold_ms)}
|
||||||
{g.move_points != null ? ` · 波动 ${fmtMovePoints(g.move_points)}` : ""}
|
{g.move_points != null ? ` · 波动 ${fmtMovePoints(g.move_points)}` : ""}
|
||||||
|
{g.option_leverage != null
|
||||||
|
? ` · 期权杠杆 ${fmt(g.option_leverage, 0)}x`
|
||||||
|
: ""}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className={`trade-row-pnl mono ${pnlClass(listPnl)}`}>
|
<div className={`trade-row-pnl mono ${pnlClass(listPnl)}`}>
|
||||||
@@ -255,6 +259,7 @@ export default function TradesPage() {
|
|||||||
<th>开仓时间</th>
|
<th>开仓时间</th>
|
||||||
<th>平仓时间</th>
|
<th>平仓时间</th>
|
||||||
<th>持仓时长</th>
|
<th>持仓时长</th>
|
||||||
|
<th>期权杠杆</th>
|
||||||
<th>波动点数</th>
|
<th>波动点数</th>
|
||||||
<th>盈亏金额</th>
|
<th>盈亏金额</th>
|
||||||
<th>平仓方式</th>
|
<th>平仓方式</th>
|
||||||
@@ -281,6 +286,11 @@ export default function TradesPage() {
|
|||||||
<td className="mono">{fmtTime(openMs)}</td>
|
<td className="mono">{fmtTime(openMs)}</td>
|
||||||
<td className="mono">{fmtTime(closeMs)}</td>
|
<td className="mono">{fmtTime(closeMs)}</td>
|
||||||
<td className="mono">{fmtHold(g.hold_ms)}</td>
|
<td className="mono">{fmtHold(g.hold_ms)}</td>
|
||||||
|
<td className="mono">
|
||||||
|
{g.option_leverage != null
|
||||||
|
? `${fmt(g.option_leverage, 0)}x`
|
||||||
|
: "—"}
|
||||||
|
</td>
|
||||||
<td className="mono">{fmtMovePoints(g.move_points)}</td>
|
<td className="mono">{fmtMovePoints(g.move_points)}</td>
|
||||||
<td className={`mono ${pnlClass(listPnl)}`}>
|
<td className={`mono ${pnlClass(listPnl)}`}>
|
||||||
{fmt(listPnl)}
|
{fmt(listPnl)}
|
||||||
@@ -402,6 +412,14 @@ export default function TradesPage() {
|
|||||||
{fmtHold(selectedGroup.hold_ms)}
|
{fmtHold(selectedGroup.hold_ms)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="kv">
|
||||||
|
<span>期权杠杆</span>
|
||||||
|
<span className="mono">
|
||||||
|
{selectedGroup.option_leverage != null
|
||||||
|
? `${fmt(selectedGroup.option_leverage, 0)}x`
|
||||||
|
: "—"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
<div className="kv">
|
<div className="kv">
|
||||||
<span>波动点数</span>
|
<span>波动点数</span>
|
||||||
<span className="mono">
|
<span className="mono">
|
||||||
|
|||||||
Reference in New Issue
Block a user