Files
fxhnt/tests/unit/test_stablecoin_current_weights.py
jgrusewski 309bcc7475 perf(paper): memoize date-independent work in sleeve current_weights
paper-backfill calls each as_of-aware sleeve's current_weights(as_of) once per
date (~1650 dates). UnlockShortRunner + StableReversionRunner re-did
date-independent work on every call: rebuilt events_norm, re-ran eligibility,
and full-panel-scanned+sorted just to find the latest day <= as_of (O(panel)
per call -> O(N*panel) over the backfill).

- UnlockShortRunner: memoize events_norm (now a property), _eligible() result,
  and the sorted all-days axis; current_weights finds the latest day via
  bisect_right over the memoized axis. run() reuses the same caches.
- StableReversionRunner: memoize the sorted all-days axis; current_weights uses
  bisect_right; run() reuses it.

Bit-identical output (drives the live paper track + replay; live==replay):
golden sweep tests recompute expected weights via the naive pre-optimization
logic across ~20 as_of dates (before-data, mid-stream, in/out of unlock window,
after last day) and assert exact dict equality. Verified the references also
match the old src (git-stash check). Per-call complexity O(panel) -> O(log days
+ active names). Full suite: 693 passed.

TsTrendForward.current_weights left alone: it does no thrown-away
date-independent work per call (load_panel is an O(1) ref in backfill; the
per-symbol sort is date-dependent on the closes feeding the signal).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 20:22:31 +02:00

57 lines
2.4 KiB
Python

from fxhnt.application.stablecoin_runner import StableReversionRunner
def test_current_weights_shorts_rich_names():
# panel = {symbol: {epoch_day: close}}; day 20000 has USDT rich (>1+thresh), DAI at peg
panel = {"USDTUSD": {20000: 1.01}, "DAIUSD": {20000: 1.0001}}
r = StableReversionRunner(panel, thresh_bp=50.0)
w = r.current_weights("epoch:20000")
assert w["USDTUSD"] < 0 # rich -> short
assert w.get("DAIUSD", 0.0) == 0.0
def test_current_weights_uses_latest_day_on_or_before_as_of():
panel = {"USDTUSD": {19990: 1.0001, 20000: 1.02}}
r = StableReversionRunner(panel, thresh_bp=50.0)
# day 19990 not rich -> {}; day 20000 rich -> short
assert r.current_weights("epoch:19995") == {}
assert r.current_weights("epoch:20005")["USDTUSD"] < 0
def test_current_weights_empty_when_no_data():
r = StableReversionRunner({"USDTUSD": {20000: 1.01}}, thresh_bp=50.0)
assert r.current_weights("epoch:19000") == {}
def _reference_current_weights(panel, thresh_bp, as_of):
"""Recompute current_weights via the NAIVE pre-optimization logic (full-panel scan/sort for the
latest day every call) so the golden sweep pins the memoized+bisect impl to a from-scratch baseline."""
from fxhnt.application._date_axis import as_of_day
from fxhnt.domain.stablecoin_reversion import short_rich_weights
th = thresh_bp / 1e4
day_lim = as_of_day(as_of)
days = sorted({d for s in panel.values() for d in s if d <= day_lim})
if not days:
return {}
d = days[-1]
dev = {s: series[d] - 1.0 for s, series in panel.items()
if d in series and series[d] > 0}
return short_rich_weights(dev, th)
def test_golden_sweep_bit_identical():
# multi-symbol panel over many days, mixed rich/cheap/at-peg; sweep ~20 as_of dates incl.
# before-data, mid-stream (incl. a day where no name is rich -> {}), and after the last day.
panel = {
"USDTUSD": {d: 1.0 + 0.0001 * ((d % 7) - 3) for d in range(19990, 20010)},
"DAIUSD": {d: 1.0 + 0.0003 * ((d % 5) - 2) for d in range(19990, 20010)},
"TUSDUSD": {d: 1.0 + 0.01 if d % 3 == 0 else 1.0 for d in range(19990, 20010)},
}
thresh_bp = 50.0
r = StableReversionRunner(panel, thresh_bp=thresh_bp)
as_ofs = [f"epoch:{x}" for x in range(19985, 20012)] # before-data .. after-last-day
for ao in as_ofs:
expected = _reference_current_weights(panel, thresh_bp, ao)
assert r.current_weights(ao) == expected, ao