模拟盘对齐币本位:钱包支持 ETH/BTC,现货桥与期权权利金走本地撮合。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-08-20 15:16:51 +08:00
parent c8688a11ae
commit 6f721d1e6d
6 changed files with 836 additions and 516 deletions
+87 -3
View File
@@ -64,6 +64,19 @@ def _contract_size(exchange: Any, symbol: str) -> float:
return 1.0
def _premium_ccy_for_inst(inst_id: str) -> str:
try:
from lib.options.options_margin_mode_lib import (
margin_mode_from_inst_id,
premium_ccy_for_mode,
)
underly = (str(inst_id or "").split("-")[0] or "ETH").upper()
return premium_ccy_for_mode(margin_mode_from_inst_id(inst_id), underly)
except Exception:
return "USDC"
class SimBroker:
def __init__(self, get_db: Callable) -> None:
self.get_db = get_db
@@ -377,9 +390,10 @@ class SimBroker:
qty = n * ct_mult
pr = option_fill(action="open", bid=bid, ask=ask, qty=qty, fee_rate=fr)
cost = pr.notional + pr.fee
prem_ccy = _premium_ccy_for_inst(inst_id)
try:
self.wallets.debit_trading(
"USDC",
prem_ccy,
cost,
kind="option_open",
note=f"buy {inst_id} x{n}@{pr.fill_px}",
@@ -490,8 +504,9 @@ class SimBroker:
conn.close()
if credit > 0:
prem_ccy = _premium_ccy_for_inst(inst_id)
self.wallets.credit_trading(
"USDC",
prem_ccy,
credit,
kind="option_close",
note=f"sell {inst_id} x{close_n}@{pr.fill_px}",
@@ -552,6 +567,67 @@ class SimBroker:
)
return result
def convert_usdt_coin(
self,
exchange: Any,
*,
underlying: str,
direction: str,
amount: float,
fee_rate: float | None = None,
account: str = "trading",
) -> dict[str, Any]:
"""模拟 ETH/BTC-USDT 现货市价兑换(交易账户)."""
from lib.options.options_margin_mode_lib import spot_quote_inst_id
from lib.sim.pricing_lib import spot_coin_usdt_fill
coin = (underlying or "ETH").strip().upper() or "ETH"
if coin not in ("ETH", "BTC"):
return {"ok": False, "msg": f"不支持标的 {coin}"}
# spot_quote_inst_id → ETH-USDTccxt 常用 ETH/USDT
inst = spot_quote_inst_id(coin)
symbol = inst.replace("-", "/") if inst else f"{coin}/USDT"
fr = sim_fee_rate(fee_rate)
bid, ask = _ticker_bid_ask(exchange, symbol)
fill = spot_coin_usdt_fill(
direction=direction,
amount=float(amount),
bid=bid,
ask=ask,
fee_rate=fr,
coin=coin,
)
result = SimWallets(self.get_db).convert(
from_ccy=fill.from_ccy,
to_ccy=fill.to_ccy,
amount=fill.from_amount,
account=account or "trading",
to_amount=fill.to_amount,
rate=fill.fill_px,
fee=fill.fee,
note=f"{symbol} mkt {fill.fill_px:.4f} (bid {bid:.4f}/ask {ask:.4f})",
)
if not result.get("ok"):
return result
result.update(
{
"direction": fill.direction,
"underlying": coin,
"bid": bid,
"ask": ask,
"base_px": fill.base_px,
"fill_px": fill.fill_px,
"fee_rate": fr,
"symbol": symbol,
"inst_id": inst,
"coin_bought": fill.to_amount if fill.direction == "usdt_to_coin" else None,
"coin_sold": fill.from_amount if fill.direction == "coin_to_usdt" else None,
"usdt_spent": fill.from_amount if fill.direction == "usdt_to_coin" else None,
"usdt_recovered": fill.to_amount if fill.direction == "coin_to_usdt" else None,
}
)
return result
def _index_px_for_option(
self,
exchange: Any,
@@ -645,6 +721,14 @@ class SimBroker:
else:
intrinsic_u = 0.0
prem_ccy = _premium_ccy_for_inst(inst_id)
# 币本位到期兑付用币数量: 实值/指数 × 张数 × 乘数
if prem_ccy in ("ETH", "BTC") and float(spot) > 0:
settle_recv = round(
max(0.0, (intrinsic_u / float(spot)) * sheets * ct_mult),
8,
)
conn = self.get_db()
try:
conn.execute("DELETE FROM sim_option_positions WHERE inst_id=?", (inst_id,))
@@ -681,7 +765,7 @@ class SimBroker:
if settle_recv > 1e-12:
self.wallets.credit_trading(
"USDC",
prem_ccy,
settle_recv,
kind="option_expiry",
note=f"expiry settle {inst_id} @{spot:g} recv={settle_recv}",