Forecast
A seasonal model, a forecast band built from its own residual spread, and the baselines it has to beat. Pick a series and a horizon; every number is recomputed.
Backtest
Walk-forward re-fits the model at every origin and scores only points it had not seen. One split can be lucky; dozens of origins are harder to fool.
Methods
The equations, the fixed parameters and the parts this kit does not do. Every number on the other two screens comes from these functions.
level: L(t) = α·(y(t) − S(t−m)) + (1−α)·(L(t−1) + T(t−1))
trend: T(t) = β·(L(t) − L(t−1)) + (1−β)·T(t−1)
seasonal: S(t) = γ·(y(t) − L(t)) + (1−γ)·S(t−m)
forecast: ŷ(t+h) = L(t) + h·T(t) + S(t+h−m) (additive)
ŷ(t+h) = (L(t) + h·T(t)) · S(t+h−m) (multiplicative)
Multiplicative seasonality is only valid on strictly positive series, and the fit rejects the rest with an error rather than returning nonsense.
walk-forward:
for each origin t in [minTrain, n − h]:
fit on y[0..t]
predict y[t+1 .. t+h]
score all folds together
MAE = mean(|y − ŷ|)
RMSE = sqrt(mean((y − ŷ)²))
MAPE = mean(|(y − ŷ) / y|) (zero actuals skipped)
bias = mean(ŷ − y) (positive = too high)
The newest points are the ones being forecast, so a fold's training window never contains its target. This is why the backtest is slower than a single train/test split, and why it is worth it.
- Fixed smoothing parameters. No α/β/γ optimisation, so a well-tuned library will beat these defaults.
- One seasonality per series. No holiday effects, no multiple season cycles.
- Gaussian residual band. It widens as √h, which is a useful approximation, not a guarantee of coverage.
- Anomalies are detected against the model's own residuals. A structural break is reported as a run of anomalies, not as one event.
- Three generated datasets. They are deterministic and documented, not a benchmark.