dbc86a1ce6
OKX/Binance LIVE share half_open and option_closed_perp_pending repair paths; private REST throttles default to 1s and are tunable in settings. Co-authored-by: Cursor <cursoragent@cursor.com>
70 lines
2.1 KiB
Python
70 lines
2.1 KiB
Python
"""实盘防卡状态:half_open / option_closed_perp_pending。"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from app.sim.ledger import Ledger
|
|
from app.sim.matcher import BLOCKING_STATUSES, Matcher
|
|
|
|
|
|
def test_blocking_statuses_include_repair_states() -> None:
|
|
assert "half_open" in BLOCKING_STATUSES
|
|
assert "option_closed_perp_pending" in BLOCKING_STATUSES
|
|
assert "open" in BLOCKING_STATUSES
|
|
|
|
|
|
def test_has_open_position_blocks_half_open(tmp_path, monkeypatch) -> None:
|
|
monkeypatch.setenv("MODE", "SIM")
|
|
from app.models.db import Database
|
|
|
|
db = Database(tmp_path / "t.db")
|
|
m = Matcher(db)
|
|
assert m.has_open_position() is False
|
|
|
|
with db._lock:
|
|
db._conn.execute(
|
|
"""UPDATE positions SET
|
|
group_id=?, option_inst_id=?, option_side=?, option_qty_eth=?,
|
|
option_qty_contracts=?, option_entry_px=?, status=?
|
|
WHERE id=1""",
|
|
("G-test", "ETH-OPT", "call", 2.0, 200.0, 10.0, "half_open"),
|
|
)
|
|
db._conn.commit()
|
|
|
|
assert m.has_open_position() is True
|
|
assert m.position_status() == "half_open"
|
|
|
|
with db._lock:
|
|
db._conn.execute(
|
|
"UPDATE positions SET status='option_closed_perp_pending' WHERE id=1"
|
|
)
|
|
db._conn.commit()
|
|
assert m.has_open_position() is True
|
|
|
|
with db._lock:
|
|
db._conn.execute(
|
|
"""UPDATE positions SET
|
|
group_id=NULL, option_inst_id=NULL, status='flat' WHERE id=1"""
|
|
)
|
|
db._conn.commit()
|
|
assert m.has_open_position() is False
|
|
db.close()
|
|
|
|
|
|
def test_ledger_allow_negative(tmp_path) -> None:
|
|
from app.models.db import Database
|
|
|
|
db = Database(tmp_path / "l.db")
|
|
ledger = Ledger(db)
|
|
# 掏空
|
|
snap = ledger.snapshot()
|
|
ledger.apply_cash(-snap["available"], kind="drain", note="drain")
|
|
try:
|
|
ledger.apply_cash(-1.0, kind="fail", note="should fail")
|
|
assert False, "expected RuntimeError"
|
|
except RuntimeError:
|
|
pass
|
|
# LIVE 镜像允许透支
|
|
bal = ledger.apply_cash(-1.0, kind="live", note="ok", allow_negative=True)
|
|
assert bal < 0
|
|
db.close()
|