Deduct round-trip taker fees from estimated perp PnL.
Unify hub/instance TP profit, calc_pnl, and push/accounting to net of 0.05% per side; leave exchange floating PnL unchanged. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -88,7 +88,8 @@ class HubCalculatorLibTests(unittest.TestCase):
|
||||
self.assertEqual(data["first_contracts"], 10.0)
|
||||
self.assertEqual(len(data["rows"]), 1)
|
||||
self.assertEqual(data["rows"][0]["loss_at_sl_u"], 50.0)
|
||||
self.assertEqual(data["rows"][0]["profit_at_tp_u"], 200.0)
|
||||
# 毛利 200 − 双边费 (1000+1200)*0.0005=1.1 → 198.9
|
||||
self.assertEqual(data["rows"][0]["profit_at_tp_u"], 198.9)
|
||||
|
||||
@patch("lib.hub.hub_calculator_lib._resolve_market", return_value=_mock_resolve())
|
||||
def test_roll_calculator_chain_two_legs(self, _mock):
|
||||
|
||||
@@ -136,7 +136,8 @@ def test_apply_order_price_display_fields_gate_contract_size():
|
||||
avg_entry_price=62063.4,
|
||||
)
|
||||
assert payload["reward_at_tp_usdt"] is not None
|
||||
assert abs(payload["reward_at_tp_usdt"] - 6.73) < 0.1
|
||||
# 毛利约 6.73, 扣双边 0.05% 后约 6.25
|
||||
assert abs(payload["reward_at_tp_usdt"] - 6.25) < 0.1
|
||||
|
||||
|
||||
def test_calc_latest_risk_amount_long():
|
||||
|
||||
@@ -43,4 +43,5 @@ def test_infer_initial_position_from_live():
|
||||
|
||||
|
||||
def test_reward_at_tp_long():
|
||||
assert roll_ui.reward_at_tp_usdt("long", 100.0, 110.0, 2.0) == 20.0
|
||||
# 毛利 20, 双边费 (200+220)*0.0005=0.21 → 净 19.79
|
||||
assert abs(roll_ui.reward_at_tp_usdt("long", 100.0, 110.0, 2.0) - 19.79) < 1e-6
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
"""永续固定费率净盈亏."""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
sys.path.insert(0, str(ROOT))
|
||||
|
||||
from lib.trade.trade_fee_lib import ( # noqa: E402
|
||||
estimate_roundtrip_fee_usdt,
|
||||
net_pnl_after_fee,
|
||||
notional_usdt,
|
||||
taker_fee_rate,
|
||||
)
|
||||
|
||||
|
||||
class TestTradeFeeLib(unittest.TestCase):
|
||||
def test_default_rate(self):
|
||||
os.environ.pop("PERP_TAKER_FEE_RATE", None)
|
||||
self.assertAlmostEqual(taker_fee_rate(), 0.0005)
|
||||
|
||||
def test_notional(self):
|
||||
self.assertAlmostEqual(notional_usdt(100, 2, 1.0), 200.0)
|
||||
self.assertAlmostEqual(notional_usdt(62000, 78, 0.0001), 483.6, places=2)
|
||||
|
||||
def test_roundtrip_fee_qty(self):
|
||||
# 开 100*2=200, 平 110*2=220, 费=(200+220)*0.0005=0.21
|
||||
fee = estimate_roundtrip_fee_usdt(100, 110, 2.0, 1.0, rate=0.0005)
|
||||
self.assertAlmostEqual(fee, 0.21, places=6)
|
||||
|
||||
def test_net_long_matches_checklist(self):
|
||||
# 毛利 20, 费 0.21 → 净 19.79
|
||||
net = net_pnl_after_fee(20.0, 100, 110, 2.0, 1.0, rate=0.0005)
|
||||
self.assertAlmostEqual(net, 19.79, places=4)
|
||||
|
||||
def test_open_notional_fallback(self):
|
||||
# 无张数:开名义 1000, 出场 110/100 → 平 1100, 费=1.05
|
||||
fee = estimate_roundtrip_fee_usdt(100, 110, open_notional=1000, rate=0.0005)
|
||||
self.assertAlmostEqual(fee, 1.05, places=6)
|
||||
net = net_pnl_after_fee(50.0, 100, 110, open_notional=1000, rate=0.0005)
|
||||
self.assertAlmostEqual(net, 48.95, places=4)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user