feat(exec): bybit paper-envelope helper (testnet-only) + venue in book-state
This commit is contained in:
@@ -15,11 +15,22 @@ def crypto_envelope(repo: Any, equity: float) -> float:
|
||||
return min(float(repo.current_allocation().get("bybit_4edge", 0.0)), float(equity))
|
||||
|
||||
|
||||
def paper_or_b2a_crypto_envelope(repo: Any, equity: float, paper_envelope: float, is_paper: bool) -> float:
|
||||
"""PAPER-validation envelope (min(paper, equity)) when `paper_envelope > 0`, bypassing B2a — refused on a
|
||||
non-testnet account (never widen real-capital exposure). Otherwise the B2a/B3-gated `crypto_envelope`."""
|
||||
if paper_envelope > 0.0:
|
||||
if not is_paper:
|
||||
raise ValueError("paper-envelope refused: bybit account is not testnet/paper")
|
||||
return min(float(paper_envelope), float(equity))
|
||||
return crypto_envelope(repo, equity)
|
||||
|
||||
|
||||
def build_crypto_pos_state(positions: dict[str, float], marks: dict[str, float], envelope: float,
|
||||
funding_cursor_ts: int) -> dict[str, Any]:
|
||||
funding_cursor_ts: int, venue: str = "") -> dict[str, Any]:
|
||||
return {"positions": {s: float(q) for s, q in positions.items()},
|
||||
"marks": {s: float(m) for s, m in marks.items()},
|
||||
"envelope": float(envelope), "funding_cursor_ts": int(funding_cursor_ts)}
|
||||
"envelope": float(envelope), "funding_cursor_ts": int(funding_cursor_ts),
|
||||
"venue": str(venue)}
|
||||
|
||||
|
||||
def compute_crypto_exec_return(pos_prior: dict[str, Any], today_marks: dict[str, float],
|
||||
@@ -76,11 +87,13 @@ class _CryptoExecBookingStrategy:
|
||||
|
||||
def record_bybit_exec_track(repo: Any, exec_return: float | None, new_positions: dict[str, float],
|
||||
today_marks: dict[str, float], envelope: float, funding_cursor_ts: int,
|
||||
today: str, at: dt.datetime) -> None:
|
||||
today: str, at: dt.datetime, venue: str = "") -> None:
|
||||
"""Book `exec_return` as an observed forward_record for `bybit_4edge_exec` via A's run_track (anchor +
|
||||
record + nav/summary), then carry the next run's basis (positions/marks/envelope/funding cursor) under the
|
||||
book-state key `bybit_4edge_exec_pos` (SEPARATE from run_track's own book_state)."""
|
||||
book-state key `bybit_4edge_exec_pos` (SEPARATE from run_track's own book_state). `venue` is recorded on
|
||||
the exec book-state."""
|
||||
from fxhnt.application.forward_engine import run_track
|
||||
run_track(repo, "bybit_4edge_exec", _CryptoExecBookingStrategy(exec_return), today=today, at=at)
|
||||
repo.set_book_state("bybit_4edge_exec_pos",
|
||||
build_crypto_pos_state(new_positions, today_marks, envelope, funding_cursor_ts), at=at)
|
||||
build_crypto_pos_state(new_positions, today_marks, envelope, funding_cursor_ts, venue),
|
||||
at=at)
|
||||
|
||||
@@ -97,3 +97,32 @@ def test_apply_fills_rejects_unknown_side():
|
||||
fills = [{"symbol": "SOLUSDT", "side": "HOLD", "qty": 2.0}]
|
||||
with pytest.raises(ValueError, match="apply_fills: unexpected fill side"):
|
||||
apply_fills(current, fills)
|
||||
|
||||
|
||||
def test_build_crypto_pos_state_persists_venue():
|
||||
from fxhnt.application.bybit_exec_record import build_crypto_pos_state
|
||||
st = build_crypto_pos_state({"BTCUSDT": 1.0}, {"BTCUSDT": 60000.0}, 5000.0, 123, venue="bybit-testnet")
|
||||
assert st["venue"] == "bybit-testnet" and st["funding_cursor_ts"] == 123
|
||||
|
||||
|
||||
def test_paper_or_b2a_crypto_envelope_paper_mode():
|
||||
from fxhnt.application.bybit_exec_record import paper_or_b2a_crypto_envelope
|
||||
class _Repo:
|
||||
def current_allocation(self):
|
||||
raise AssertionError("B2a must not be read in paper mode")
|
||||
assert paper_or_b2a_crypto_envelope(_Repo(), equity=8000.0, paper_envelope=10000.0, is_paper=True) == 8000.0
|
||||
|
||||
|
||||
def test_paper_or_b2a_crypto_envelope_refuses_non_testnet():
|
||||
import pytest
|
||||
from fxhnt.application.bybit_exec_record import paper_or_b2a_crypto_envelope
|
||||
with pytest.raises(ValueError, match="paper-envelope refused"):
|
||||
paper_or_b2a_crypto_envelope(object(), equity=8000.0, paper_envelope=10000.0, is_paper=False)
|
||||
|
||||
|
||||
def test_paper_or_b2a_crypto_envelope_default_reads_b2a():
|
||||
from fxhnt.application.bybit_exec_record import paper_or_b2a_crypto_envelope
|
||||
class _Repo:
|
||||
def current_allocation(self):
|
||||
return {"bybit_4edge": 3000.0}
|
||||
assert paper_or_b2a_crypto_envelope(_Repo(), equity=8000.0, paper_envelope=0.0, is_paper=True) == 3000.0
|
||||
|
||||
Reference in New Issue
Block a user