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>
57 lines
2.4 KiB
Python
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
|