fix模拟盘期权手续费按OKX币本位公式计费,并纠正复盘旧单展示。
费率作用在标的币数量上并以权利金7%封顶,不再误用权利金×费率。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -280,6 +280,148 @@ def hide_review_trade(conn: sqlite3.Connection, trade_id: int) -> dict[str, Any]
|
||||
return {"ok": True, "entry": _row_to_dict(entry) if entry else None, "history_key": d.get("history_key")}
|
||||
|
||||
|
||||
def _sum_sim_order_fees(conn: sqlite3.Connection, ord_ids: list[str]) -> float | None:
|
||||
"""从 sim_option_orders 汇总手续费(权利金币种,正数)."""
|
||||
ids = [str(x).strip() for x in (ord_ids or []) if str(x).strip()]
|
||||
if not ids:
|
||||
return None
|
||||
try:
|
||||
conn.execute("SELECT 1 FROM sim_option_orders LIMIT 1").fetchone()
|
||||
except Exception:
|
||||
return None
|
||||
total = 0.0
|
||||
n = 0
|
||||
for oid in ids:
|
||||
try:
|
||||
row = conn.execute(
|
||||
"SELECT fee FROM sim_option_orders WHERE ord_id=?",
|
||||
(oid,),
|
||||
).fetchone()
|
||||
except Exception:
|
||||
continue
|
||||
if not row:
|
||||
continue
|
||||
fee = _safe_float(row["fee"] if hasattr(row, "keys") else row[0])
|
||||
if fee is None:
|
||||
continue
|
||||
total += abs(float(fee))
|
||||
n += 1
|
||||
return round(total, 8) if n else None
|
||||
|
||||
|
||||
def _estimate_okx_option_fee_coin(
|
||||
*,
|
||||
underlying_coin: float | None,
|
||||
premium_coin: float | None,
|
||||
) -> float:
|
||||
"""按 OKX 币本位公式估算期权手续费(权利金币种)."""
|
||||
try:
|
||||
from lib.sim.pricing_lib import option_fee_coin
|
||||
|
||||
return float(
|
||||
option_fee_coin(
|
||||
underlying_coin=float(underlying_coin or 0.0),
|
||||
premium_coin=float(premium_coin or 0.0),
|
||||
)
|
||||
)
|
||||
except Exception:
|
||||
return 0.0
|
||||
|
||||
|
||||
def _fee_looks_like_legacy_premium_rate(
|
||||
fee_coin: float,
|
||||
*,
|
||||
premium_coin: float | None,
|
||||
underlying_coin: float | None,
|
||||
) -> bool:
|
||||
"""旧模拟盘把手续费算成权利金×费率,约为正确值的 premium/underlying 倍."""
|
||||
if fee_coin <= 0:
|
||||
return True
|
||||
prem = abs(float(premium_coin or 0.0))
|
||||
uly = abs(float(underlying_coin or 0.0))
|
||||
if prem <= 0 or uly <= 0:
|
||||
return False
|
||||
# 正确量级 ~ uly * fee_rate; 错误量级 ~ prem * fee_rate
|
||||
# 若 fee << uly*1e-4 且接近 prem*5e-4,视为旧算法
|
||||
try:
|
||||
from lib.sim.pricing_lib import sim_fee_rate
|
||||
|
||||
fr = float(sim_fee_rate())
|
||||
except Exception:
|
||||
fr = 0.0005
|
||||
expect_okx = uly * fr
|
||||
expect_legacy = prem * fr
|
||||
if expect_okx <= 0:
|
||||
return False
|
||||
# 比 OKX 估算小一个数量级以上,且靠近旧公式
|
||||
if fee_coin < expect_okx * 0.25 and abs(fee_coin - expect_legacy) <= max(expect_legacy * 0.5, 1e-10):
|
||||
return True
|
||||
if fee_coin < expect_okx * 0.05:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _resolve_option_fees_coin(
|
||||
conn: sqlite3.Connection,
|
||||
row: Any,
|
||||
*,
|
||||
open_fee: float,
|
||||
close_fee: float,
|
||||
premium_ccy: str,
|
||||
) -> tuple[float, float]:
|
||||
"""解析期权开/平手续费(权利金币种);修正模拟盘旧算法偏小值."""
|
||||
ccy = (premium_ccy or "").strip().upper()
|
||||
paid = _safe_float(row["premium_paid"] if hasattr(row, "keys") else None)
|
||||
recv = _safe_float(row["premium_received"] if hasattr(row, "keys") else None)
|
||||
uly = _safe_float(row["eth_amount"] if hasattr(row, "keys") else None)
|
||||
if uly is None or uly <= 0:
|
||||
sheets = _safe_float(row["sheets"] if hasattr(row, "keys") else None) or 0.0
|
||||
# BTC 期权约 0.01,ETH 约 0.1
|
||||
ct = 0.01 if ccy == "BTC" else 0.1
|
||||
uly = float(sheets) * ct if sheets > 0 else None
|
||||
|
||||
open_oids = [
|
||||
p.strip()
|
||||
for p in str(row["exchange_ord_id"] if hasattr(row, "keys") else "").split(",")
|
||||
if p.strip()
|
||||
]
|
||||
close_oids = [
|
||||
p.strip()
|
||||
for p in str(row["close_ord_id"] if hasattr(row, "keys") else "").split(",")
|
||||
if p.strip()
|
||||
]
|
||||
|
||||
ofee = abs(float(open_fee or 0.0))
|
||||
cfee = abs(float(close_fee or 0.0))
|
||||
|
||||
# 优先用订单表(若订单本身仍是旧算法,下面会再纠正)
|
||||
sim_open = _sum_sim_order_fees(conn, open_oids)
|
||||
sim_close = _sum_sim_order_fees(conn, close_oids)
|
||||
if sim_open is not None and sim_open > 0:
|
||||
ofee = sim_open
|
||||
if sim_close is not None and sim_close > 0:
|
||||
cfee = sim_close
|
||||
|
||||
if ccy in ("ETH", "BTC"):
|
||||
if _fee_looks_like_legacy_premium_rate(ofee, premium_coin=paid, underlying_coin=uly):
|
||||
est = _estimate_okx_option_fee_coin(underlying_coin=uly, premium_coin=paid)
|
||||
if est > 0:
|
||||
ofee = est
|
||||
if _fee_looks_like_legacy_premium_rate(cfee, premium_coin=recv, underlying_coin=uly):
|
||||
est = _estimate_okx_option_fee_coin(underlying_coin=uly, premium_coin=recv)
|
||||
if est > 0:
|
||||
cfee = est
|
||||
elif cfee <= 0 and recv is not None and recv > 0:
|
||||
est = _estimate_okx_option_fee_coin(underlying_coin=uly, premium_coin=recv)
|
||||
if est > 0:
|
||||
cfee = est
|
||||
if ofee <= 0 and paid is not None and paid > 0:
|
||||
est = _estimate_okx_option_fee_coin(underlying_coin=uly, premium_coin=paid)
|
||||
if est > 0:
|
||||
ofee = est
|
||||
|
||||
return round(ofee, 8), round(cfee, 8)
|
||||
|
||||
|
||||
def sync_options_from_local_trades(
|
||||
conn: sqlite3.Connection,
|
||||
@@ -317,11 +459,11 @@ def sync_options_from_local_trades(
|
||||
rows = conn.execute(
|
||||
"""
|
||||
SELECT id, inst_id, underlying, opt_type, strike, exp_time, sheets,
|
||||
open_quote, close_quote, premium_paid, premium_received, realized_pnl,
|
||||
realized_pnl_usdt, close_index_px, open_index_px, budget_usdt,
|
||||
premium_ccy, created_at, closed_at, signal_note, status,
|
||||
eth_amount, open_quote, close_quote, premium_paid, premium_received,
|
||||
realized_pnl, realized_pnl_usdt, close_index_px, open_index_px,
|
||||
budget_usdt, premium_ccy, created_at, closed_at, signal_note, status,
|
||||
trading_usdt_before, pnl_settled, initial_premium_usdt,
|
||||
open_fee, close_fee
|
||||
open_fee, close_fee, exchange_ord_id, close_ord_id
|
||||
FROM options_trades
|
||||
WHERE status = 'closed'
|
||||
ORDER BY id DESC
|
||||
@@ -445,6 +587,14 @@ def sync_options_from_local_trades(
|
||||
# 仅期权开/平手续费折 U(不含现货)
|
||||
ofee = abs(_safe_float(r["open_fee"]) or 0.0)
|
||||
cfee = abs(_safe_float(r["close_fee"]) or 0.0)
|
||||
# 模拟盘旧单曾按「权利金×费率」计费偏小:按 OKX 公式/订单回填
|
||||
ofee, cfee = _resolve_option_fees_coin(
|
||||
conn,
|
||||
r,
|
||||
open_fee=ofee,
|
||||
close_fee=cfee,
|
||||
premium_ccy=ccy,
|
||||
)
|
||||
fee_u = None
|
||||
if ccy in ("ETH", "BTC"):
|
||||
fee_parts = 0.0
|
||||
|
||||
Reference in New Issue
Block a user