53 lines
2.4 KiB
Python
53 lines
2.4 KiB
Python
import math
|
|
from fxhnt.application.paper_book import isv_adaptive_weights
|
|
|
|
def _series(vals, start=1): # {epoch_day: ret}
|
|
return {start + i: v for i, v in enumerate(vals)}
|
|
|
|
def test_empty_active_returns_empty():
|
|
assert isv_adaptive_weights({}, []) == {}
|
|
|
|
def test_no_history_is_equal_weight():
|
|
w = isv_adaptive_weights({"a": {}, "b": {}}, ["a", "b"])
|
|
assert w == {"a": 0.5, "b": 0.5}
|
|
|
|
def test_low_vol_sleeve_gets_higher_weight():
|
|
lo = _series([0.001, -0.001] * 30) # ~60 obs low vol
|
|
hi = _series([0.05, -0.05] * 30) # ~60 obs high vol
|
|
w = isv_adaptive_weights({"lo": lo, "hi": hi}, ["lo", "hi"])
|
|
assert math.isclose(sum(w.values()), 1.0, abs_tol=1e-9)
|
|
assert w["lo"] > w["hi"]
|
|
|
|
def test_rising_vol_regime_shrinks_lookback():
|
|
# calm must extend through the PRIOR block (indices 40-49); only the last 10 (indices 50-59) are hot,
|
|
# so std(recent L_min=10) > std(prior L_min=10). Expose L_t via the debug return for determinism.
|
|
calm = [0.01, -0.01] * 25 # 50 obs low vol (covers the prior block)
|
|
hot = [0.06, -0.06] * 5 # last 10 obs high vol (the recent block)
|
|
s = _series(calm + hot)
|
|
_, dbg = isv_adaptive_weights({"x": s, "y": _series([0.01, -0.01] * 30)},
|
|
["x", "y"], _debug=True)
|
|
assert dbg["L_t"] < 60
|
|
flat = _series([0.01, -0.01] * 40)
|
|
_, dbg2 = isv_adaptive_weights({"x": flat, "y": flat}, ["x", "y"], _debug=True)
|
|
assert dbg2["L_t"] == 60
|
|
|
|
def test_cap_never_below_one_over_n():
|
|
s = _series([0.02, -0.02] * 30)
|
|
_, dbg = isv_adaptive_weights({"a": s, "b": s, "c": s}, ["a", "b", "c"], _debug=True)
|
|
assert dbg["cap_t"] >= 1.0 / 3 - 1e-9
|
|
|
|
def test_floor_holds_after_waterfill():
|
|
# one very-low-vol sleeve would dominate; floor keeps the other above phi/N.
|
|
dom = _series([0.0001, -0.0001] * 40)
|
|
weak = _series([0.2, -0.2] * 40)
|
|
w = isv_adaptive_weights({"dom": dom, "weak": weak}, ["dom", "weak"])
|
|
assert math.isclose(sum(w.values()), 1.0, abs_tol=1e-9)
|
|
assert w["weak"] >= 0.5 / 2 - 1e-9 # w_floor = phi/N = 0.25
|
|
assert w["dom"] <= 1.0 + 1e-9
|
|
|
|
def test_mixed_history_cold_sleeve_gets_floor():
|
|
has = _series([0.02, -0.02] * 30)
|
|
w = isv_adaptive_weights({"has": has, "cold": {1: 0.01}}, ["has", "cold"]) # cold has <2 obs
|
|
assert math.isclose(w["cold"], 0.5 / 2, abs_tol=1e-9) # exactly w_floor
|
|
assert math.isclose(sum(w.values()), 1.0, abs_tol=1e-9)
|