Team Ai
Apppublic

Sumitx369/Paper_Trading_Backtesting

sourceHugging Faceupdated 4mo agoView on Hugging Face
2likes
test_ml.py56 linesDownload Raw Back to tests
1"""Tests for Phase-2 ML terms (fusion weighting, GARCH, HMM, per-stock sizing)."""2from __future__ import annotations3 4import numpy as np5import pandas as pd6 7from app.services.engine import fusion, ml, portfolio8 9 10def test_active_weights_scale_with_present_terms():11    # Bayes only -> w1=112    assert fusion.active_weights(has_lgbm=False, has_hmm=False, has_garch=False) == (1.0, 0.0, 0.0, 0.0)13    # + HMM -> bayes shares with w3, sums to 1; garch off14    w = fusion.active_weights(has_lgbm=False, has_hmm=True, has_garch=False)15    assert abs(w[0] + w[1] + w[2] - 1.0) < 1e-9 and w[2] > 0 and w[3] == 0.016    # all on -> w4 (garch) active and capped17    w = fusion.active_weights(has_lgbm=True, has_hmm=True, has_garch=True)18    assert abs(w[0] + w[1] + w[2] - 1.0) < 1e-9 and w[1] > 0 and w[2] > 0 and 0 < w[3] <= 0.519 20 21def test_fuse_subtracts_garch_penalty():22    f = fusion.fuse("S1", p_bayes=0.9, p_hmm=0.6, garch_penalty=0.25, regime="TRENDING")23    # 0.65*0.9 + 0.35*0.6 - 0.30*0.25 = 0.585 + 0.21 - 0.07524    assert f.p_raw == round(0.585 + 0.21 - 0.075, 5)25    assert f.weights["w3"] > 0 and f.weights["w4"] > 026 27 28def test_garch_penalty_bounds():29    if not ml.garch_available():30        return31    # a noisy but finite return series -> a bounded [0,1] penalty or None32    rng = np.cumsum(np.sin(np.arange(300) / 3.0)) + 10033    pen = ml.garch_penalty(pd.Series(rng))34    assert pen is None or (0.0 <= pen <= 1.0)35    # too-short series -> None36    assert ml.garch_penalty(pd.Series([100, 101, 102])) is None37 38 39def test_hmm_winprob_in_range():40    if not ml.hmm_available():41        return42    for state in ("TRENDING", "RANGE", "HIGH_VOL"):43        p = ml.hmm_winprob("S1", state, 0.9)44        assert p is None or (0.0 <= p <= 1.0)45 46 47def test_per_stock_capital_cap_splits_account():48    # ₹10k capital, 5 positions -> ₹2k per stock; a ₹100 stock => 20 sh, not 10049    cap = 10_00050    sd = portfolio.size(cap, 1_000, entry=100.0, stop=98.0, size_band="FULL",51                        per_position_cap=cap / 5)52    assert sd.qty == 20 and sd.rupees <= cap / 5 + 1e-653    # without the cap it would deploy the whole account54    full = portfolio.size(cap, 1_000, 100.0, 98.0, "FULL")55    assert full.qty > sd.qty56