Files
crypto_monitor/tests/test_hub_agent_mark_price.py
T
dekun 7352d10254 Fix hub total floating PnL by excluding OKX options from swap agent.
Option legs were scored with linear swap math and then added again from the options snapshot, inflating 总浮盈亏 and 持有仓位.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-05 22:13:22 +08:00

110 lines
3.6 KiB
Python

"""子代理持仓:三所标记价字段统一解析."""
from __future__ import annotations
import sys
import unittest
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "manual_trading_hub"))
from agent import _position_mark_price, _ticker_mark_price # noqa: E402
sys.path.insert(0, str(ROOT))
from lib.hub.hub_position_metrics import ( # noqa: E402
enrich_ccxt_position_metrics_out,
estimate_linear_swap_upnl_usdt,
is_option_like_position,
parse_position_unrealized_pnl,
resolve_position_display_upnl,
)
class TestHubAgentMarkPrice(unittest.TestCase):
def test_binance_mark_price(self):
px = _position_mark_price({"markPrice": 65880.1, "info": {}})
self.assertAlmostEqual(px, 65880.1)
def test_okx_mark_px(self):
px = _position_mark_price({"info": {"markPx": "72.85"}})
self.assertAlmostEqual(px, 72.85)
def test_gate_info_mark(self):
px = _position_mark_price({"info": {"mark_price": "0.2241"}})
self.assertAlmostEqual(px, 0.2241)
def test_missing_returns_none(self):
self.assertIsNone(_position_mark_price({"info": {}}))
def test_infer_from_notional_and_contracts(self):
p = {"notional": 1000, "contracts": 10, "info": {}}
px = _position_mark_price(p)
self.assertAlmostEqual(px, 100.0)
def test_ticker_fallback(self):
class _Ex:
def fetch_ticker(self, sym):
return {"mark": 99.5, "info": {}}
self.assertAlmostEqual(_ticker_mark_price(_Ex(), "BTC/USDT:USDT"), 99.5)
def test_gate_unrealised_pnl_in_info(self):
pnl = parse_position_unrealized_pnl(
{"info": {"unrealised_pnl": "6.81"}, "unrealizedPnl": None}
)
self.assertAlmostEqual(pnl, 6.81)
def test_okx_upl_signed(self):
pnl = parse_position_unrealized_pnl(
{"info": {"upl": "-2.15"}, "unrealizedPnl": None}
)
self.assertAlmostEqual(pnl, -2.15)
def test_enrich_aligns_short_gate_metrics(self):
pos = {
"side": "short",
"contracts": 11,
"entryPrice": 73.187,
"markPrice": 66.038,
"info": {"unrealised_pnl": "7.86"},
}
out = {"unrealized_pnl": 7.86, "mark_price": 66.038}
enrich_ccxt_position_metrics_out(pos, out, contract_size=1.0, funds_decimals=2)
self.assertGreater(out["unrealized_pnl"], 70.0)
def test_estimate_short_hype_contract_size(self):
upnl = estimate_linear_swap_upnl_usdt(
"short", 73.187, 66.038, 11, 0.1
)
self.assertAlmostEqual(upnl, 7.86, places=1)
def test_resolve_prefers_computed_when_exchange_off(self):
shown = resolve_position_display_upnl(
"short", 73.187, 66.038, 11, 1.0, 7.86
)
self.assertAlmostEqual(shown, 78.64, places=1)
def test_resolve_keeps_exchange_when_aligned(self):
shown = resolve_position_display_upnl(
"short", 73.187, 66.038, 11, 0.1, 7.86
)
self.assertAlmostEqual(shown, 7.86, places=2)
def test_is_option_like_position(self):
self.assertTrue(
is_option_like_position({"symbol": "ETH/USD:USD-260806-1875-C", "contracts": 1})
)
self.assertTrue(
is_option_like_position(
{"symbol": "x", "info": {"instType": "OPTION", "instId": "ETH-USD-260806-1875-P"}}
)
)
self.assertFalse(
is_option_like_position({"symbol": "BTC/USDT:USDT", "contracts": 10})
)
self.assertFalse(is_option_like_position({"symbol": "ETH/USDT:USDT"}))
if __name__ == "__main__":
unittest.main()