Repository navigation
Methods Auto
High-level composition layer. Source:
forecast.py.auto_forecast(x, y, horizon, ...). API: ../api/auto.md.
These are not new fitting math -- they are the decision logic distilled from the domain validation studies, whose organizing result was that the single biggest lever is picking the structurally-correct model / estimator variant, not the solver. Each function composes only the validated, stable levers behind one call, and keeps the studies' honest ceilings (near-random-walk series fall back to persistence; clean bulk shapes match but do not beat a well-initialized NLLS).
Recovering parameters needs no shape rules. fit(model, data, basis="auto")
fits the candidate bases and returns whichever leaves the smallest residual
over the samples, which is a measurement rather than a guess; the shape
statistics that a router would need do not separate the cases anyway (the
detrended spectral peak share of a logistic is 0.44 to 0.48, of a damped
oscillation 0.52, of a noisy ten-cycle sine 0.45 to 0.56). Measured over the
whole validation corpus at 20 noise draws, the route recovers parameters
within 1.054 of scipy.optimize.curve_fit on every family, against 1.212 for
the shape router it replaces.
dtfit forecasts by fitting an extrapolable parametric structure and continuing
it -- the opposite of a black-box learner. auto_forecast routes the model class
from the data's shape, fits it, and extrapolates horizon steps on the uniform
grid, behind two safety guards.
Under model="auto" the router (_auto_model) picks one of three model classes
from the data's shape:
| condition | model class (model= value) |
|---|---|
| saturating positive growth (monotone, large ratio, all positive) |
logistic ("logistic") |
a detected seasonal cycle (strength above season_strength) |
linear + seasonal ("linear_seasonal") |
| otherwise |
poly ("poly", a quadratic level) |
Each class is fit with the matching stable lever -- the logistic and seasonal fits
use fit(basis="legendre") with data-driven seeds and bounds (the growth rate is
bracketed by the time span; the seasonal frequency is seeded from
fft_frequency_seed), so the global search
is well-posed.
Forcing a class. model= also accepts an explicit class, bypassing the router.
The full set is "auto" (route by structure), "logistic", "linear" (a plain
"poly" (the quadratic level), "linear_seasonal", and
"random_walk". Note the router only ever chooses among logistic /
linear_seasonal / poly; linear and random_walk are reachable only by
naming them explicitly (linear is also the internal fallback for a failed or
diverging fit).
Persistence-fallback guard. Whichever class is chosen, auto_forecast first
checks the no-structure guard (below); if it fires -- or model="random_walk"
is requested outright -- the forecast is just naive persistence of the last value,
with no fitting.
The studies were emphatic that a parametric forecaster must know when not to extrapolate. Two guards enforce that:
- No-structure guard. Before trusting the structured model, it is fit on the first 80 % of the training data and scored against naive persistence on the held-out training tail. If the structured fit cannot get near persistence there (RMSE more than a factor worse), the series is treated as near-random-walk and the forecast falls back to persisting the last value. This is what keeps dtfit honest on FX-like series, where no parametric model beats "tomorrow = today" one step out.
- Divergence guard. A quadratic level can extrapolate to absurd values. If the forecast leaves a generous band around the observed range, the runaway quadratic is dropped to a linear fit (and, failing that, to persistence). This prevents the classic unstructured-extrapolation blow-up.
The return is the length-horizon forecast on the extrapolated grid.
fit(..., basis="auto") and auto_forecast are where the per-method math is operationalized
into a usable default. They compose only stable pieces (fit(basis="legendre"),
fit(basis="block") (the block image),
fft_frequency_seed) -- the conservative
merges the domain studies validated -- and they preserve the honest negatives those
studies reported:
- the basis route matches, but does not beat, a well-initialized NLLS on clean bulk shapes; its edge is robustness and interpretable parameters.
-
auto_forecastpersists on near-random-walk series by design -- the guards are features, not workarounds.
Left: on a trend-plus-cycle series auto_forecast routes to the
linear+seasonal model and extrapolates the cycle onto the held-out tail,
where a random walk can only persist a flat line. Right: on a structureless
(near-white-noise) series the no-structure guard fires and the forecast falls
back to persistence rather than chasing the noise with a polynomial.

Use fit(..., basis="auto") when you have a known model form and want the
right basis without choosing it yourself; use auto_forecast
for a structured, guarded forecast of a series with real extrapolable structure
(growth, saturation, a clean cycle). For deliberate control over the estimator,
call the individual methods (LSI, EAC); for model inference
(which family fits at all) use suggest_models. The honest
ceilings above are the reason both functions exist as conservative composers
rather than aggressive optimizers.
Published automatically from the repo's wiki/ directory by the wiki workflow. All pages are maintained directly in wiki/.
Start here
Guides
Examples
- Overview
- 01 Quickstart
- 02 Fitting methods
- 03 Models & auto
- 04 sklearn estimator
- 05 Streaming
- 06 Scaling
- 07 Diagnostics
- 08 Stochastic
API reference
Methods (math)
Experimental
Validation