fix复盘真盈亏改为期权币盈亏×平仓价,不再绑卖回与初始权利金差。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-10-13 12:39:15 +08:00
parent 839baea375
commit fc0d76d174
11 changed files with 98 additions and 211 deletions
+11 -41
View File
@@ -26,37 +26,18 @@ class FeeConvertTests(unittest.TestCase):
class PremiumMoveFormulaTests(unittest.TestCase):
def test_user_formula_matches_coin_basis_minus_initial(self):
def test_option_pnl_times_close_px(self):
coin = 0.01
paid = 0.01
open_px = 90000.0
close_px = 80000.0
initial = paid * open_px
a = true_pnl_usdt_premium_move(
coin_pnl=coin,
premium_paid=paid,
sell_back_px=close_px,
initial_premium_usdt=initial,
)
# (权利金+盈亏)×卖回 − 初始权利金U
expect = (paid + coin) * close_px - initial
self.assertAlmostEqual(float(a), expect, places=4)
# 无费时 ≡ 收回×平 − 已付×开
recv = paid + coin
self.assertAlmostEqual(float(a), recv * close_px - paid * open_px, places=4)
# 缺初始时用开仓价补算,结果相同
b = true_pnl_usdt_premium_move(
coin_pnl=coin,
premium_paid=paid,
sell_back_px=close_px,
open_index_px=open_px,
)
self.assertAlmostEqual(float(b), float(a), places=4)
self.assertAlmostEqual(float(a), coin * close_px, places=4)
class SettleClosedPnlTests(unittest.TestCase):
def test_sim_net_times_close_index(self):
# 无开仓指数时回退净币×平仓价
s = settle_closed_pnl(
premium_paid=0.01,
premium_received=0.02,
@@ -68,23 +49,23 @@ class SettleClosedPnlTests(unittest.TestCase):
self.assertAlmostEqual(float(s["realized_pnl"]), 0.009, places=8)
self.assertAlmostEqual(float(s["realized_pnl_usdt"]), 27.0, places=4)
def test_sim_proceeds_minus_open_premium_usdt(self):
"""盈利=(收回币)×卖回价 − 已付币×开仓指数 − 手续费U."""
def test_sim_coin_pnl_times_close(self):
"""真盈亏=净币盈亏×平仓价."""
s = settle_closed_pnl(
premium_paid=0.011005,
premium_received=0.02270864,
open_fee=0,
close_fee=0,
premium_ccy="BTC",
index_px=81000, # 卖回价
open_index_px=86000, # 初始 U 权利金用开仓指数
index_px=81000,
open_index_px=86000,
)
# 0.02270864*81000 - 0.011005*86000
expect = 0.02270864 * 81000 - 0.011005 * 86000
net = 0.02270864 - 0.011005
expect = net * 81000
self.assertAlmostEqual(float(s["realized_pnl_usdt"]), expect, places=2)
def test_sim_loss_remaining_minus_fees(self):
"""亏损:费先扣进币盈亏,再按用户式折 U(不另扣手续费U)."""
"""亏损:费先扣进币盈亏,再×平仓价."""
s = settle_closed_pnl(
premium_paid=0.01,
premium_received=0.004,
@@ -94,34 +75,26 @@ class SettleClosedPnlTests(unittest.TestCase):
index_px=2500,
open_index_px=3000,
)
# net_coin=-0.0062; U=-0.0062*2500 - 0.01*(3000-2500)=-20.5
self.assertAlmostEqual(float(s["realized_pnl"]), -0.0062, places=8)
self.assertAlmostEqual(float(s["realized_pnl_usdt"]), -20.5, places=2)
self.assertAlmostEqual(float(s["realized_pnl_usdt"]), -15.5, places=2)
def test_resolve_loss_does_not_deduct_fee_again(self):
"""历史币盈亏已含费;resolve 只跑用户式,不再用 open_fee/close_fee 扣第二遍."""
from lib.options.options_pnl_settle_lib import resolve_true_pnl_usdt_from_trade
# coin 已是 recv-paid-fees=-0.0062
pnl, src = resolve_true_pnl_usdt_from_trade(
premium_paid=0.01,
premium_received=0.004,
realized_pnl=-0.0062,
open_index_px=3000,
close_index_px=2500,
initial_premium_usdt=30.0,
open_fee=0.0001,
close_fee=0.0001,
premium_ccy="ETH",
)
self.assertEqual(src, "premium_move")
# (0.01-0.0062)*2500 - 30 = 9.5 - 30 = -20.5
self.assertAlmostEqual(float(pnl), -20.5, places=2)
# 若再扣一遍费会更亏于 -20.5
self.assertGreater(float(pnl), -20.55)
self.assertAlmostEqual(float(pnl), -15.5, places=2)
def test_budget_ignored_for_usdt(self):
# budget 不得抬高开仓成本
s = settle_closed_pnl(
premium_paid=0.01,
premium_received=0.02,
@@ -158,7 +131,6 @@ class SettleClosedPnlTests(unittest.TestCase):
class SimPremiumPnlStatsTests(unittest.TestCase):
def test_sync_sim_no_longer_overwrites_account_settled(self):
"""账户结算后 sync 兼容入口不得改写."""
import sqlite3
from lib.options.options_db import init_options_tables
@@ -235,13 +207,11 @@ class ExchangeFreezeStatsTests(unittest.TestCase):
]
frozen = apply_exchange_pnl_freeze(conn, history, _Ex())
converted = history_pnl_to_usdt(frozen, _Ex())
# 0.000138*100000=13.8; -0.00648*2500=-16.2; net=-2.4
self.assertAlmostEqual(float(converted[0]["realized_pnl"]), 13.8, places=4)
self.assertAlmostEqual(float(converted[1]["realized_pnl"]), -16.2, places=4)
stats = compute_options_stats_from_history(converted)
self.assertAlmostEqual(float(stats["net_realized_pnl"]), -2.4, places=4)
# 指数再变也不改冻结 U
class _Ex2:
def public_get_market_ticker(self, params):
return {"data": [{"last": "999999"}]}