Align hedge UI/fees: drop 未启动, premium coin/U, equity incl perp margin, OKX option fees.
Option net uses Min(0.03%×coin, 7%×premium) with bid/ask fills (no slip); live PnL colors fixed. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+17
-4
@@ -7,7 +7,7 @@ import uuid
|
||||
from datetime import datetime
|
||||
from typing import Any, Callable
|
||||
|
||||
from lib.sim.pricing_lib import option_fill, perp_fill, sim_fee_rate
|
||||
from lib.sim.pricing_lib import option_fill, perp_fill, sim_fee_rate, sim_option_fee_rate
|
||||
from lib.sim.wallets_lib import InsufficientFunds, SimWallets
|
||||
|
||||
|
||||
@@ -109,7 +109,20 @@ class SimBroker:
|
||||
self.wallets = SimWallets(get_db)
|
||||
|
||||
def balances_header(self) -> dict[str, float]:
|
||||
return self.wallets.view()
|
||||
"""资金快照.trading_usdt=全仓权益(可用+永续占用保证金);trading_usdt_free=可开仓余额."""
|
||||
w = dict(self.wallets.view())
|
||||
free = float(w.get("trading_usdt") or 0)
|
||||
margin = 0.0
|
||||
try:
|
||||
for p in self.list_perp_positions():
|
||||
margin += float(p.get("margin_usdt") or 0)
|
||||
except Exception:
|
||||
margin = 0.0
|
||||
w["trading_usdt_free"] = free
|
||||
w["perp_margin_usdt"] = margin
|
||||
# 永续全仓:展示权益含占用保证金;期权逐仓权利金在币余额,不并入 USDT
|
||||
w["trading_usdt"] = round(free + margin, 8)
|
||||
return w
|
||||
|
||||
def list_perp_positions(self) -> list[dict[str, Any]]:
|
||||
conn = self.get_db()
|
||||
@@ -431,7 +444,7 @@ class SimBroker:
|
||||
n = int(sheets)
|
||||
if n < 1:
|
||||
return {"ok": False, "msg": "张数至少为 1"}
|
||||
fr = sim_fee_rate(fee_rate)
|
||||
fr = sim_option_fee_rate(fee_rate)
|
||||
bid, ask, ct_mult = _option_bid_ask(exchange_options, inst_id)
|
||||
if price is not None and float(price) > 0:
|
||||
# 限价: 用 min(limit, ask) 作为基准卖一近似, 仍走 option_fill 滑点
|
||||
@@ -540,7 +553,7 @@ class SimBroker:
|
||||
close_n = min(pos_s, float(n))
|
||||
if close_n <= 0:
|
||||
return {"ok": False, "msg": "平仓张数无效"}
|
||||
fr = sim_fee_rate(fee_rate)
|
||||
fr = sim_option_fee_rate(fee_rate)
|
||||
qty = close_n * ct_mult
|
||||
pr = option_fill(action="close", bid=bid, ask=ask, qty=qty, fee_rate=fr)
|
||||
credit = pr.notional - pr.fee
|
||||
|
||||
+8
-2
@@ -55,7 +55,11 @@ def apply_sim_hooks(app_module: Any) -> None:
|
||||
|
||||
def get_available_trading_usdt():
|
||||
if is_sim_mode(app_module.get_db):
|
||||
return float(broker().balances_header()["trading_usdt"])
|
||||
w = broker().balances_header()
|
||||
# 开仓可用=未占用保证金的 USDT(勿用全仓权益)
|
||||
if w.get("trading_usdt_free") is not None:
|
||||
return float(w.get("trading_usdt_free") or 0)
|
||||
return float(w.get("trading_usdt") or 0)
|
||||
return _orig_avail()
|
||||
|
||||
def get_live_position_contracts(exchange_symbol, direction):
|
||||
@@ -215,6 +219,7 @@ def _patch_okx_options_lib(app_module: Any) -> None:
|
||||
te = float(w.get("trading_eth") or 0)
|
||||
fb = float(w.get("funding_btc") or 0)
|
||||
tb = float(w.get("trading_btc") or 0)
|
||||
tu_free = float(w.get("trading_usdt_free") if w.get("trading_usdt_free") is not None else tu)
|
||||
return {
|
||||
"scope": "main",
|
||||
"funding_usdt": fu,
|
||||
@@ -227,12 +232,13 @@ def _patch_okx_options_lib(app_module: Any) -> None:
|
||||
"trading_btc": tb,
|
||||
"funding_usdt_avail": fu,
|
||||
"funding_usdc_avail": fc,
|
||||
"trading_usdt_avail": tu,
|
||||
"trading_usdt_avail": tu_free,
|
||||
"trading_usdc_avail": tc,
|
||||
"funding_eth_avail": fe,
|
||||
"trading_eth_avail": te,
|
||||
"funding_btc_avail": fb,
|
||||
"trading_btc_avail": tb,
|
||||
"perp_margin_usdt": float(w.get("perp_margin_usdt") or 0),
|
||||
}
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
+22
-10
@@ -1,8 +1,8 @@
|
||||
"""成交价与手续费.
|
||||
|
||||
永续:滑点=1×fee_rate,手续费=名义×fee_rate.
|
||||
期权(币本位):滑点仍按权利金价×fee_rate;手续费对齐 OKX=
|
||||
Min(fee_rate×标的币数量, 权利金×7%).
|
||||
期权(币本位):吃卖一/买一按报价成交(无额外滑点);手续费对齐 OKX=
|
||||
Min(fee_rate×标的币数量, 权利金×7%);普通用户 taker 默认 0.03%.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -32,6 +32,20 @@ def sim_fee_rate(override: float | None = None) -> float:
|
||||
return 0.0005
|
||||
|
||||
|
||||
def sim_option_fee_rate(override: float | None = None) -> float:
|
||||
"""OKX 币本位期权 taker 费率(默认 0.03%)."""
|
||||
if override is not None:
|
||||
return float(override)
|
||||
try:
|
||||
return float(
|
||||
os.getenv("SIM_OPTION_FEE_RATE")
|
||||
or os.getenv("OKX_OPTIONS_TAKER_FEE")
|
||||
or "0.0003"
|
||||
)
|
||||
except (TypeError, ValueError):
|
||||
return 0.0003
|
||||
|
||||
|
||||
def perp_fill(
|
||||
*,
|
||||
side: str,
|
||||
@@ -74,7 +88,7 @@ def option_fee_coin(
|
||||
Min(费率 × 张数对应标的币数量, 权利金×封顶比例).
|
||||
注意:费率作用在标的币面值上,不是权利金名义上.
|
||||
"""
|
||||
f = sim_fee_rate(fee_rate)
|
||||
f = sim_option_fee_rate(fee_rate)
|
||||
qty = abs(float(underlying_coin or 0.0))
|
||||
prem = abs(float(premium_coin or 0.0))
|
||||
if qty <= 0 and prem <= 0:
|
||||
@@ -92,20 +106,19 @@ def option_fill(
|
||||
bid: float,
|
||||
ask: float,
|
||||
qty: float,
|
||||
fee_rate: float,
|
||||
fee_rate: float | None = None,
|
||||
) -> PriceResult:
|
||||
"""开仓买入吃卖一; 平仓卖出吃买一.
|
||||
|
||||
qty = sheets × ct_mult(标的币数量).
|
||||
滑点仍按权利金价×费率;手续费按 OKX 币本位公式(标的币×费率,权利金7%封顶).
|
||||
成交价=买卖一(无额外滑点);手续费=OKX 币本位公式(标的币×费率,权利金7%封顶).
|
||||
"""
|
||||
f = float(fee_rate)
|
||||
f = sim_option_fee_rate(fee_rate)
|
||||
if action == "open":
|
||||
base = float(ask)
|
||||
fill = base * (1.0 + f)
|
||||
else:
|
||||
base = float(bid)
|
||||
fill = base * (1.0 - f)
|
||||
fill = base
|
||||
qty_f = abs(float(qty))
|
||||
notional = abs(fill * qty_f)
|
||||
fee = option_fee_coin(
|
||||
@@ -113,8 +126,7 @@ def option_fill(
|
||||
premium_coin=notional,
|
||||
fee_rate=f,
|
||||
)
|
||||
slip = abs(fill - base) * qty_f
|
||||
return PriceResult(base_px=base, fill_px=fill, fee=fee, slip=slip, notional=notional)
|
||||
return PriceResult(base_px=base, fill_px=fill, fee=fee, slip=0.0, notional=notional)
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
|
||||
Reference in New Issue
Block a user