Lk / tests /test_arima_model.py
Kashaf1's picture
Upload moirai_forecast_app contents
ef20ebe
Raw History Blame Contribute Delete
3.7 kB
"""
Unlike test_moirai_model.py / test_chronos_model.py, these tests
exercise AutoArimaForecaster's predict() for REAL -- statsforecast has
no torch/network dependency, so there's no reason to stub it out.
"""
import numpy as np
import pandas as pd
from arima_model import AutoArimaForecaster
from fixtures import make_synthetic_ohlcv
from forecast_types import ModelInputError, QuantileForecast
def test_predict_returns_a_real_quantile_forecast():
df = make_synthetic_ohlcv(n=150, seed=60, freq="1h")
model = AutoArimaForecaster()
forecast = model.predict(context_df=df, target_col="close", past_covariate_cols=[],
prediction_length=5, freq="1h")
assert isinstance(forecast, QuantileForecast)
assert forecast.quantiles.shape == (5, 5)
assert forecast.quantile_levels == [0.1, 0.25, 0.5, 0.75, 0.9]
assert forecast.context_length_used == 150
def test_quantiles_are_monotonically_non_decreasing_per_step():
"""P10 <= P25 <= P50 <= P75 <= P90 must hold at every horizon step --
a real property of valid prediction intervals, not just "some
numbers came back"."""
df = make_synthetic_ohlcv(n=150, seed=61, freq="1h")
model = AutoArimaForecaster()
forecast = model.predict(context_df=df, target_col="close", past_covariate_cols=[],
prediction_length=5, freq="1h")
for step in range(5):
row = forecast.quantiles[step]
assert np.all(np.diff(row) >= -1e-9), f"step {step} quantiles not monotonic: {row}"
def test_rejects_too_short_context():
df = make_synthetic_ohlcv(n=5, seed=62, freq="1h")
model = AutoArimaForecaster(min_context=10)
try:
model.predict(context_df=df, target_col="close", past_covariate_cols=[],
prediction_length=5, freq="1h")
raise AssertionError("expected ModelInputError")
except ModelInputError as e:
assert "too short" in str(e)
def test_rejects_nan_in_context():
df = make_synthetic_ohlcv(n=150, seed=63, freq="1h")
df = df.copy()
df.iloc[10, df.columns.get_loc("close")] = np.nan
model = AutoArimaForecaster()
try:
model.predict(context_df=df, target_col="close", past_covariate_cols=[],
prediction_length=5, freq="1h")
raise AssertionError("expected ModelInputError")
except ModelInputError as e:
assert "NaN" in str(e)
def test_predict_is_deterministic_for_identical_input():
"""ARIMA fitting is deterministic (no sampling) -- two calls on the
exact same context must return the exact same forecast, unlike
Moirai-MoE before its seeding fix."""
df = make_synthetic_ohlcv(n=150, seed=64, freq="1h")
model = AutoArimaForecaster()
f1 = model.predict(context_df=df, target_col="close", past_covariate_cols=[], prediction_length=5, freq="1h")
f2 = model.predict(context_df=df, target_col="close", past_covariate_cols=[], prediction_length=5, freq="1h")
assert np.allclose(f1.quantiles, f2.quantiles)
def test_works_through_the_real_backtest_engine():
"""End-to-end: AutoArimaForecaster must be usable as a drop-in
WalkForwardBacktester forecaster with no special-casing, proving
the shared interface actually holds."""
from backtest_engine import WalkForwardBacktester
df = make_synthetic_ohlcv(n=150, seed=65, freq="1h")
from features import compute_indicators
feat = compute_indicators(df)
bt = WalkForwardBacktester(AutoArimaForecaster(min_context=10), timeframe="1h",
horizon=5, context_length=32)
result = bt.run(feat)
assert result["num_origins"] > 0
assert len(result["errors"]) == 0