修复币本位统计:开仓成本按预算/开仓指数计,不再用平仓价重估。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -148,6 +148,32 @@ def freeze_pnl_to_usdt(
|
||||
}
|
||||
|
||||
|
||||
def fee_to_usdt(
|
||||
fee_amt: Any,
|
||||
fee_ccy: Any,
|
||||
*,
|
||||
index_px: float | None,
|
||||
) -> float:
|
||||
"""手续费折 USDT."""
|
||||
amt = fee_amount_abs(fee_amt)
|
||||
if amt <= 0:
|
||||
return 0.0
|
||||
fc = str(fee_ccy or "").strip().upper()
|
||||
if fc in ("USDT", "USDC", "USD", ""):
|
||||
# 空币种时按稳定币近似,避免把小数额 ETH 费当成整 U
|
||||
if fc == "" and amt < 0.05:
|
||||
idx = _safe_float(index_px)
|
||||
if idx is not None and idx > 100:
|
||||
return round(amt * float(idx), 4)
|
||||
return round(amt, 4)
|
||||
if fc in ("ETH", "BTC"):
|
||||
idx = _safe_float(index_px)
|
||||
if idx is None or idx <= 0:
|
||||
return 0.0
|
||||
return round(amt * float(idx), 4)
|
||||
return round(amt, 4)
|
||||
|
||||
|
||||
def settle_closed_pnl(
|
||||
*,
|
||||
premium_paid: Any,
|
||||
@@ -156,11 +182,18 @@ def settle_closed_pnl(
|
||||
close_fee: Any = 0,
|
||||
premium_ccy: str,
|
||||
index_px: float | None,
|
||||
open_index_px: float | None = None,
|
||||
budget_usdt: float | None = None,
|
||||
fee_ccy: str | None = None,
|
||||
) -> dict[str, float | None]:
|
||||
"""
|
||||
由「毛权利金」结算:净盈亏 = 收回 − 已付 − 开/平手续费(权利金单位).
|
||||
仅用于本地开平仓权利金口径;不要对 OKX realizedPnl 再调此函数扣费
|
||||
(交易所 realizedPnl = pnl + fee + ..., 已含手续费).
|
||||
由「毛权利金」结算.
|
||||
币数量净盈亏 = 收回 − 已付 − 开/平手续费.
|
||||
冻结 U(币本位):
|
||||
平仓收回×平仓指数 − 开仓成本U − 手续费U
|
||||
开仓成本优先 budget_usdt,否则 已付×开仓指数(缺省才用平仓指数).
|
||||
这样不会把开仓成本也按平仓价重估,避免和余额对不上.
|
||||
不要对 OKX realizedPnl 再调此函数扣费.
|
||||
"""
|
||||
paid = float(_safe_float(premium_paid) or 0.0)
|
||||
recv = float(_safe_float(premium_received) or 0.0)
|
||||
@@ -171,12 +204,59 @@ def settle_closed_pnl(
|
||||
if cfee < 0:
|
||||
cfee = abs(cfee)
|
||||
net = round(recv - paid - ofee - cfee, 8)
|
||||
return freeze_pnl_to_usdt(
|
||||
net,
|
||||
premium_ccy=premium_ccy,
|
||||
index_px=index_px,
|
||||
total_fee=ofee + cfee,
|
||||
pc = str(premium_ccy or "").strip().upper()
|
||||
close_idx = _safe_float(index_px)
|
||||
open_idx = _safe_float(open_index_px)
|
||||
budget = _safe_float(budget_usdt)
|
||||
fc = str(fee_ccy or pc or "").strip().upper()
|
||||
|
||||
if pc not in ("ETH", "BTC"):
|
||||
return freeze_pnl_to_usdt(
|
||||
net,
|
||||
premium_ccy=premium_ccy,
|
||||
index_px=close_idx,
|
||||
total_fee=ofee + cfee,
|
||||
)
|
||||
|
||||
if close_idx is None or close_idx <= 0:
|
||||
return {
|
||||
"realized_pnl": net,
|
||||
"close_index_px": None,
|
||||
"open_index_px": float(open_idx) if open_idx and open_idx > 0 else None,
|
||||
"realized_pnl_usdt": None,
|
||||
"total_fee": round(ofee + cfee, 8),
|
||||
}
|
||||
|
||||
# 开仓成本 U:预算(真实花出去的 USDT) > 已付×开仓指数 > 已付×平仓指数
|
||||
if budget is not None and budget > 0:
|
||||
entry_u = float(budget)
|
||||
if open_idx is None or open_idx <= 0:
|
||||
open_idx = (entry_u / paid) if paid > 1e-12 else close_idx
|
||||
elif open_idx is not None and open_idx > 0:
|
||||
entry_u = paid * float(open_idx)
|
||||
else:
|
||||
entry_u = paid * float(close_idx)
|
||||
open_idx = close_idx
|
||||
|
||||
exit_u = recv * float(close_idx)
|
||||
# 开仓费按开仓指数、平仓费按平仓指数折 U
|
||||
fee_u = fee_to_usdt(ofee, fc or pc, index_px=open_idx) + fee_to_usdt(
|
||||
cfee, fc or pc, index_px=close_idx
|
||||
)
|
||||
# 若开仓成本已是 budget(含买币),ETH 开仓费已体现在币变少/卖回变少,不再重复扣 ETH 开仓费
|
||||
if budget is not None and budget > 0 and (fc or pc) in ("ETH", "BTC"):
|
||||
fee_u = fee_to_usdt(cfee, fc or pc, index_px=close_idx)
|
||||
if str(fee_ccy or "").strip().upper() in ("USDT", "USDC", "USD"):
|
||||
fee_u += fee_to_usdt(ofee, fee_ccy, index_px=open_idx)
|
||||
|
||||
usdt = round(exit_u - entry_u - fee_u, 4)
|
||||
return {
|
||||
"realized_pnl": net,
|
||||
"close_index_px": float(close_idx),
|
||||
"open_index_px": float(open_idx) if open_idx and open_idx > 0 else None,
|
||||
"realized_pnl_usdt": usdt,
|
||||
"total_fee": round(ofee + cfee, 8),
|
||||
}
|
||||
|
||||
|
||||
def settle_exchange_realized_pnl(
|
||||
|
||||
Reference in New Issue
Block a user