SPB Git forge
1commits 1branches 0releases
189.0 KBsize
maindefault branch
4 h agolast push
Python 54.7% TypeScript 42.5% SQL 1.9%
1.8 KB · 51 lines python
Raw Blame History
1import math23import numpy as np4import pandas as pd56from ktrade.backtest.metrics import block_bootstrap_ci, deflated_sharpe, drawdown_series7from ktrade.backtest.validation import param_grid, walk_forward8from ktrade.strategy.meanrev import ou_half_life9from ktrade.strategy.momentum import TimeSeriesMomentum10from tests.conftest import synthetic_candles111213def test_drawdown():14    dd = drawdown_series(pd.Series([100, 110, 99, 120, 60]))15    assert math.isclose(dd.min(), 0.5 - 1)161718def test_ou_half_life_detects_mean_reversion_and_random_walk():19    rng = np.random.default_rng(0)20    x = np.zeros(2000)21    for i in range(1, 2000):22        x[i] = 0.9 * x[i - 1] + rng.normal()23    hl = ou_half_life(pd.Series(x))24    assert 4 < hl < 10  # theory: -ln2/ln(0.9) ≈ 6.625    rw = pd.Series(np.cumsum(rng.normal(size=2000)))26    assert math.isnan(ou_half_life(rw)) or ou_half_life(rw) > 100272829def test_bootstrap_ci_contains_point_estimate():30    rng = np.random.default_rng(1)31    r = rng.normal(0.0005, 0.01, 2000)32    bpy = 365 * 2433    ci = block_bootstrap_ci(r, bpy, n_boot=200)34    s = r.mean() / r.std(ddof=1) * math.sqrt(bpy)35    assert ci["sharpe_ci"][0] <= s <= ci["sharpe_ci"][1]363738def test_deflated_sharpe_decreases_with_trials():39    a = deflated_sharpe(1.5, 2000, 365 * 24, 1, 0.0, 0.0)["dsr"]40    b = deflated_sharpe(1.5, 2000, 365 * 24, 100, 0.0, 0.0)["dsr"]41    assert a > b424344def test_walk_forward_produces_oos_folds():45    df = synthetic_candles(n=1500, seed=11, drift=0.0005)46    wf = walk_forward(TimeSeriesMomentum, df, interval_min=60, grid={"lookback": [24, 48], "ema_fast": [10], "ema_slow": [40]}, n_folds=3)47    assert len(wf["folds"]) == 3 and wf["n_trials"] == 248    for f in wf["folds"]:49        assert f["train"][1] < f["test"][0]  # OOS strictly after IS50    assert len(param_grid(TimeSeriesMomentum, {"lookback": [1, 24]})) == 1  # 1 < min → dropped51