fc0d76d174
Co-authored-by: Cursor <cursoragent@cursor.com>
154 lines
5.9 KiB
Python
154 lines
5.9 KiB
Python
"""多笔买/卖回 VWAP 与真盈亏."""
|
|
from __future__ import annotations
|
|
|
|
import sqlite3
|
|
import unittest
|
|
|
|
|
|
class SpotVwapBridgeTests(unittest.TestCase):
|
|
def test_buy_and_close_sell_vwap_multi_fill(self):
|
|
from lib.options.options_spot_bridge_lib import (
|
|
BRIDGE_CLOSED,
|
|
add_bridge_buy_fill,
|
|
add_bridge_close_sell_fill,
|
|
bridge_buy_vwap,
|
|
bridge_sell_vwap,
|
|
ensure_bridge_table,
|
|
insert_bridge,
|
|
update_bridge,
|
|
)
|
|
|
|
conn = sqlite3.connect(":memory:")
|
|
conn.row_factory = sqlite3.Row
|
|
ensure_bridge_table(conn)
|
|
bid = insert_bridge(conn, underlying="BTC", status="holding", budget_usdt=2200)
|
|
add_bridge_buy_fill(conn, bid, usdt_spent=1000.0, coin_bought=0.5)
|
|
add_bridge_buy_fill(conn, bid, usdt_spent=1200.0, coin_bought=0.6)
|
|
self.assertAlmostEqual(float(bridge_buy_vwap(conn, bid)), 2000.0, places=4)
|
|
|
|
add_bridge_close_sell_fill(conn, bid, usdt_recovered=800.0, coin_sold=0.4)
|
|
add_bridge_close_sell_fill(conn, bid, usdt_recovered=1200.0, coin_sold=0.6)
|
|
self.assertAlmostEqual(float(bridge_sell_vwap(conn, bid)), 2000.0, places=4)
|
|
update_bridge(conn, bid, status=BRIDGE_CLOSED, close=True)
|
|
self.assertAlmostEqual(float(bridge_sell_vwap(conn, bid)), 2000.0, places=4)
|
|
conn.close()
|
|
|
|
def test_true_pnl_uses_bridge_vwap_not_index(self):
|
|
from lib.options.options_db import init_options_tables
|
|
from lib.options.options_pnl_settle_lib import resolve_true_pnl_usdt_from_trade
|
|
from lib.options.options_spot_bridge_lib import (
|
|
BRIDGE_CLOSED,
|
|
add_bridge_buy_fill,
|
|
add_bridge_close_sell_fill,
|
|
ensure_bridge_table,
|
|
insert_bridge,
|
|
update_bridge,
|
|
)
|
|
|
|
conn = sqlite3.connect(":memory:")
|
|
conn.row_factory = sqlite3.Row
|
|
init_options_tables(conn)
|
|
ensure_bridge_table(conn)
|
|
bid = insert_bridge(conn, underlying="BTC", status="holding", budget_usdt=2200)
|
|
add_bridge_buy_fill(conn, bid, usdt_spent=2200.0, coin_bought=1.1)
|
|
add_bridge_close_sell_fill(conn, bid, usdt_recovered=1600.0, coin_sold=0.8)
|
|
add_bridge_close_sell_fill(conn, bid, usdt_recovered=400.0, coin_sold=0.2)
|
|
update_bridge(conn, bid, status=BRIDGE_CLOSED, close=True)
|
|
# sell_vwap=2000; U=0.01*2000=20; 不用指数 80000
|
|
pnl, src = resolve_true_pnl_usdt_from_trade(
|
|
premium_paid=0.01,
|
|
premium_received=0.02,
|
|
realized_pnl=0.01,
|
|
open_index_px=90000.0,
|
|
close_index_px=80000.0,
|
|
premium_ccy="BTC",
|
|
conn=conn,
|
|
bridge_id=bid,
|
|
)
|
|
self.assertEqual(src, "premium_move")
|
|
self.assertAlmostEqual(float(pnl), 20.0, places=2)
|
|
conn.close()
|
|
|
|
def test_pending_sell_still_allows_option_pnl(self):
|
|
"""现货待卖回不阻断期权盈亏折U(用冻结平仓价)."""
|
|
from lib.options.options_pnl_settle_lib import resolve_true_pnl_usdt_from_trade
|
|
from lib.options.options_spot_bridge_lib import (
|
|
BRIDGE_PENDING_SELL,
|
|
add_bridge_buy_fill,
|
|
ensure_bridge_table,
|
|
insert_bridge,
|
|
update_bridge,
|
|
)
|
|
|
|
conn = sqlite3.connect(":memory:")
|
|
conn.row_factory = sqlite3.Row
|
|
ensure_bridge_table(conn)
|
|
bid = insert_bridge(conn, underlying="ETH", status="holding", budget_usdt=3000)
|
|
add_bridge_buy_fill(conn, bid, usdt_spent=3000.0, coin_bought=1.0)
|
|
update_bridge(conn, bid, status=BRIDGE_PENDING_SELL)
|
|
pnl, src = resolve_true_pnl_usdt_from_trade(
|
|
premium_paid=0.01,
|
|
premium_received=0.02,
|
|
realized_pnl=0.01,
|
|
open_index_px=3000.0,
|
|
close_index_px=3000.0,
|
|
premium_ccy="ETH",
|
|
conn=conn,
|
|
bridge_id=bid,
|
|
)
|
|
self.assertEqual(src, "premium_move")
|
|
self.assertAlmostEqual(float(pnl), 30.0, places=2)
|
|
conn.close()
|
|
|
|
def test_closed_bridge_without_sell_falls_back_close_index(self):
|
|
"""已关桥无卖回 VWAP 时回退冻结平仓价."""
|
|
from lib.options.options_pnl_settle_lib import resolve_true_pnl_usdt_from_trade
|
|
from lib.options.options_spot_bridge_lib import (
|
|
BRIDGE_CLOSED,
|
|
add_bridge_buy_fill,
|
|
ensure_bridge_table,
|
|
insert_bridge,
|
|
update_bridge,
|
|
)
|
|
|
|
conn = sqlite3.connect(":memory:")
|
|
conn.row_factory = sqlite3.Row
|
|
ensure_bridge_table(conn)
|
|
bid = insert_bridge(conn, underlying="BTC", status="holding", budget_usdt=1000)
|
|
add_bridge_buy_fill(conn, bid, usdt_spent=1000.0, coin_bought=0.01)
|
|
update_bridge(conn, bid, status=BRIDGE_CLOSED, close=True)
|
|
pnl, src = resolve_true_pnl_usdt_from_trade(
|
|
premium_paid=0.01,
|
|
realized_pnl=0.01,
|
|
open_index_px=100000.0,
|
|
close_index_px=90000.0,
|
|
premium_ccy="BTC",
|
|
conn=conn,
|
|
bridge_id=bid,
|
|
)
|
|
self.assertEqual(src, "premium_move")
|
|
self.assertAlmostEqual(float(pnl), 900.0, places=2)
|
|
conn.close()
|
|
|
|
def test_buy_vwap_ignores_shrunk_coin_bought(self):
|
|
from lib.options.options_spot_bridge_lib import (
|
|
add_bridge_buy_fill,
|
|
bridge_buy_vwap,
|
|
ensure_bridge_table,
|
|
insert_bridge,
|
|
update_bridge,
|
|
)
|
|
|
|
conn = sqlite3.connect(":memory:")
|
|
conn.row_factory = sqlite3.Row
|
|
ensure_bridge_table(conn)
|
|
bid = insert_bridge(conn, underlying="BTC", status="holding", budget_usdt=2200)
|
|
add_bridge_buy_fill(conn, bid, usdt_spent=2200.0, coin_bought=1.1)
|
|
update_bridge(conn, bid, coin_bought=0.01)
|
|
self.assertAlmostEqual(float(bridge_buy_vwap(conn, bid)), 2000.0, places=4)
|
|
conn.close()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|