D09-F02-A03 / Complete engineering topic

ARIMA

A production-minded guide to ARIMA.

D09 · STATISTICAL TIME SERIES
D09-F02-A03Canonical / Tested / Open
D09 / D09-F02

The useful outcome

Many financial levels are not plausibly stationary. ARIMA makes the transformation explicit: forecast changes or changes-of-changes, then restore the original scale one horizon at a time. The practical goal is a path that another person can reproduce from a declared cutoff—not a line whose origin, state, or future assumptions are hidden.

The question this tutorial answers is: How does ARIMA forecast a differenced process and reconstruct a level-scale path without confusing drift, intercept, or integration?

What you will build

You will calculate the model by hand, implement it in Python and TypeScript, inspect eight long synthetic scenarios, and learn where correct recursion ends and empirical forecast validation begins.

ARMA supplies the stationary-scale recursion. Diagnostics and stationarity tests inform d but remain separate decisions.

Freeze the variant before fitting anything

Fixed-coefficient non-seasonal ARIMA(p,d,q), d in {0,1,2}, conditional ARMA residuals, and recursive reintegration from recorded anchors.

VariantDefinitionBest useMain limitation
Selected conditional ARIMAfixed coefficients and explicit anchorsmechanical auditno automatic order selection
State-space ARIMAexact/approximate diffuse initializationlikelihood and missing datarepresentation choices matter
ARIMA with drift/trenddeterministic term mapped through differencingtrending seriesconstant semantics vary by API
Fractional integrationnon-integer differencinglong memorydifferent model family

This matters because forecast libraries often share a model-family name while differing in constants, trend representations, signs, initialization, missing data, or optimizer behavior.

Intuition before notation

Differencing changes the modeled object. A forecast of a change is not yet a price or level; integration must restore each lower-order state in the correct sequence. The hardest part is the difference between forecast scale and publication scale. The forecast origin is therefore a visible data boundary, not just the point where a chart changes color.

Forecast origin and recursive path

Formula and symbols

ϕ(B)(1B)dyt=c+θ(B)εt;Δdy^T+hT is recursively integrated from the last d anchors\phi(B)(1-B)^d y_t=c+\theta(B)\varepsilon_t;\qquad \widehat{\Delta^d y}_{T+h|T}\text{ is recursively integrated from the last }d\text{ anchors}

SymbolMeaningUnit or range
Bbackshift operatorB y_t = y_{t-1}
dnon-seasonal difference order0, 1, or 2 here
phi(B)AR lag polynomialdimensionless
theta(B)MA lag polynomialdimensionless
cintercept on differenced scaledifferenced units

The formula is a conditional point forecast. Future random innovations use zero because zero is their conditional expectation—not because the future is known to contain no shocks.

Data that the formula is allowed to see

A finalized equally spaced level series, d, AR and MA coefficients on the d-times-differenced scale, an intercept on that scale, and a horizon. Observations must be equally spaced, finite, ordered, and on one consistent scale. The model version and cutoff are frozen before the holdout. Revisions require a new forecast version rather than silent history replacement.

Algorithm

  1. Validate the level series and record the final value of every integration layer.
  2. Apply ordinary differencing d times without dropping or filling internal gaps silently.
  3. Run the selected conditional ARMA recursion on the highest-order difference.
  4. For each horizon, update the highest lower-order difference and then the level.
  5. Publish both differenced-scale and restored forecasts with the integration anchors.

Recursion anatomy for the selected forecast model

Hand calculation

The following is author-derived arithmetic over synthetic values:

JSON
{
  "values": [
    100,
    102,
    105,
    109,
    114,
    120
  ],
  "config": {
    "ar": [
      0.5
    ],
    "ma": [],
    "intercept": 1,
    "difference_order": 1,
    "horizon": 2
  }
}
  • First differences are [2,3,4,5,6].
  • h=1 difference: 1+0.5(6)=4; level: 120+4=124.
  • h=2 difference: 1+0.5(4)=3; level: 124+3=127.

The expected path is [124, 127]. Independent tests pin these values before the larger fixtures are generated.

Calculation flow

Rendering system map…

The order matters. Revealed actuals may score the path, but they may not alter the version that was issued at the cutoff.

Guided experiment

The standalone lab contains eight scenarios and 1,440 calendar-month-end observations. It trains on 144 values and forecasts a 36-value holdout. Start at horizon one, predict what state should persist, then Step through twelve model-specific checkpoints. Change the principal parameter and watch the complete path recompute from the frozen training data.

The scenarios isolate persistence, mean reversion, linear trend, seasonal structure, a late level shift, one gross outlier, a variance-regime change, and seasonal phase/amplitude drift. They are not selected trades or provider histories.

The state an expert audits

For this model, keep the differenced-scale conditional mean, the current integration anchor, and the restored level forecast visible.

Use ARIMA when a declared integer difference produces a defensible modeled scale and residual diagnostics no longer show obvious structure. Compare d=0, d=1, and d=2 through rolling origins; do not select d from a visually smooth forecast.

Audit errors on both scales. A small differenced error can accumulate into a large level miss, while a level path can look plausible even when the differenced dynamics are misspecified.

When implementations disagree, use this order: Compare difference direction, deterministic-term semantics, anchor timestamps, MA sign, initialization, and the exact order used to reintegrate multiple differences.

Model-specific state and benchmark workbench

The workbench is deliberately quantitative. It connects the model's unique state to the declared benchmark rather than asking the learner to judge whether the purple line “looks right.”

Failure diagnosis

  • Over-differencing can create unnecessary moving-average structure.
  • Under-differencing can leave unstable persistence in the modeled series.
  • A constant on the differenced equation is not always the same as a level intercept.
  • Reintegration must be recursive; adding every forecast to the same origin is wrong.
  • Structural breaks are not repaired merely by differencing.

Boundary and failure comparison

Reporting differenced-scale output as a level or claiming d was validated because a forecast looks plausible. Correct arithmetic answers “did we implement the selected model?” It does not answer “is this a good model for this series?”

Implementation contract

The Python reference favors readable state transitions. TypeScript implements the same contract independently. Shared fixtures and focused tests require matching numeric paths within 1e-9 and exact agreement on lengths, nulls, states, and invalid-input behavior.

Estimation is intentionally outside the public function. In a real workflow, fit or select parameters using only training data, record the method and version, pass the frozen result into this recursion engine, and evaluate using rolling origins against simple benchmarks.

Practical evaluation

Use a loss function that matches the decision, report by horizon, and include baseline forecasts. Preserve the refit schedule and origin timestamps. If prediction intervals are needed, choose and validate an uncertainty model; do not manufacture intervals from point forecasts alone.

The lab's declared baseline is nonseasonal naïve last-value forecast. At active horizon k, it calculates errors only for the first k revealed holdout values:

  • MAE = mean(abs(actual - forecast));
  • RMSE = sqrt(mean((actual - forecast)^2));
  • bias = mean(actual - forecast);
  • MAE skill = 1 - model_MAE / benchmark_MAE.

Positive skill means the model's revealed-prefix MAE is lower than the frozen benchmark's. Negative skill is useful evidence: the sophisticated recursion is losing to a simple rule on this synthetic path. When benchmark MAE is zero, skill is undefined rather than infinite. One origin still cannot establish general performance; repeat the complete procedure over rolling origins before making an empirical claim.

Related methods

Forecast Models family handoff

AutoReg introduces lag memory. ARMA adds innovation memory. ARIMA changes the modeled scale through differencing. SARIMA/SARIMAX adds seasonal polynomials and future driver scenarios. Holt-Winters maintains level, trend, and seasonal states directly. Theta combines a smoothed level with constrained drift.

Next: SARIMA/SARIMAX.

Historical and evidence boundary

A historical example is not useful for this mechanism lesson. A defensible case requires licensed point-in-time observations, identity, frequency, adjustment and revision basis, cutoff, parameters frozen before inspection, benchmark, holdout, and publication rights.

This tutorial establishes definition fidelity. It does not establish stationarity, model adequacy, forecast calibration, historical association, causation, profitability, or investment suitability.

Primary references

ARIMA Calculation Flow

Purpose: separate validated historical state, fixed model parameters, recursive forecast state, and holdout evaluation.

Rendering system map…

Takeaway: evaluation data follows publication; it never repairs the already issued forecast.

ReferencesPrimary sources and evidence notes

Expand the source trail, evidence role, and limitations behind the engineering choices.

FPP_ARIMA — Forecasting: Principles and Practice — ARIMA models

  • Organization or authors: Rob J. Hyndman and George Athanasopoulos
  • Source type: Authoritative open forecasting textbook
  • Publication or effective date: 2021 third edition; online version updated 2026-03-09
  • Version: 3rd edition
  • URL or DOI: https://otexts.com/fpp3/non-seasonal-arima.html
  • Accessed: 2026-07-27
  • Jurisdiction: Technical method; no legal jurisdiction.
  • Supports: ARIMA notation, differencing, AR and MA orders, stationarity/invertibility, and recursive point forecasting with future errors set to zero.
  • Limitations: Examples use the fable ecosystem; package-specific initialization remains an implementation choice.
  • Evidence role: Definition/variant comparison only; not provider data or an empirical result for the synthetic fixtures.
  • Publication boundary: Link and paraphrase are public; no source dataset or copyrighted table is reproduced.

STATSMODELS_ARIMA — statsmodels.tsa.arima.model.ARIMA

  • Organization or authors: statsmodels developers
  • Source type: Maintained official library documentation
  • Publication or effective date: 2025-12-05 documentation build
  • Version: statsmodels 0.14.6
  • URL or DOI: https://www.statsmodels.org/stable/generated/statsmodels.tsa.arima.model.ARIMA.html
  • Accessed: 2026-07-27
  • Jurisdiction: Technical method; no legal jurisdiction.
  • Supports: AR, MA, ARMA, ARIMA, seasonal, trend, and exogenous special cases plus stationarity and invertibility options.
  • Limitations: Its state-space likelihood, initialization, and optimizer are outside this deterministic teaching engine.
  • Evidence role: Definition/variant comparison only; not provider data or an empirical result for the synthetic fixtures.
  • Publication boundary: Link and paraphrase are public; no source dataset or copyrighted table is reproduced.

FPP_ACCURACY — Forecasting: Principles and Practice — Evaluating point forecast accuracy

  • Organization or authors: Rob J. Hyndman and George Athanasopoulos
  • Source type: Authoritative open forecasting textbook
  • Publication or effective date: 2021 third edition; online version updated 2026-03-09
  • Version: 3rd edition
  • URL or DOI: https://otexts.com/fpp3/accuracy.html
  • Accessed: 2026-07-27
  • Jurisdiction: Technical method; no legal jurisdiction.
  • Supports: Forecast accuracy must be measured on genuine forecasts outside the training sample; MAE, RMSE, scaled errors, and benchmarks answer different evaluation questions.
  • Limitations: A single synthetic holdout is a teaching comparison, not an empirical model-selection study.
  • Evidence role: Definition/variant comparison only; not provider data or an empirical result for the synthetic fixtures.
  • Publication boundary: Link and paraphrase are public; no source dataset or copyrighted table is reproduced.

FPP_TSCV — Forecasting: Principles and Practice — Time series cross-validation

  • Organization or authors: Rob J. Hyndman and George Athanasopoulos
  • Source type: Authoritative open forecasting textbook
  • Publication or effective date: 2021 third edition; online version updated 2026-03-09
  • Version: 3rd edition
  • URL or DOI: https://otexts.com/fpp3/tscv.html
  • Accessed: 2026-07-27
  • Jurisdiction: Technical method; no legal jurisdiction.
  • Supports: Rolling forecasting origins preserve temporal order and can evaluate horizon-specific errors without using future observations.
  • Limitations: This family demonstrates one frozen origin; production claims require many origins and a declared refit schedule.
  • Evidence role: Definition/variant comparison only; not provider data or an empirical result for the synthetic fixtures.
  • Publication boundary: Link and paraphrase are public; no source dataset or copyrighted table is reproduced.

FPP_RESIDUALS — Forecasting: Principles and Practice — Evaluating regression and residual behavior

  • Organization or authors: Rob J. Hyndman and George Athanasopoulos
  • Source type: Authoritative open forecasting textbook
  • Publication or effective date: 2021 third edition; online version updated 2026-03-09
  • Version: 3rd edition
  • URL or DOI: https://otexts.com/fpp3/regression-evaluation.html
  • Accessed: 2026-07-27
  • Jurisdiction: Technical method; no legal jurisdiction.
  • Supports: Residual plots and residual autocorrelation diagnose information left in the fitted model, but residual size is not a substitute for genuine forecast error.
  • Limitations: Residual diagnostics do not prove unbiasedness, calibrated intervals, or out-of-sample usefulness for these fixed teaching configurations.
  • Evidence role: Definition/variant comparison only; not provider data or an empirical result for the synthetic fixtures.
  • Publication boundary: Link and paraphrase are public; no source dataset or copyrighted table is reproduced.
arima.ts

type ForecastResult = {
  forecast:number[];
  fitted:(number|null)[];
  residuals?:number[];
  state:Record<string,unknown>;
  [key:string]:unknown;
};
const finite=(value:number,name:string)=>{
  if(typeof value!=="number"||!Number.isFinite(value))throw new Error(`${name} must be finite`);
  return value;
};
const positiveInt=(value:number,name:string,min=1)=>{
  if(!Number.isInteger(value)||value<min)throw new Error(`${name} must be an integer >= ${min}`);
  return value;
};
const series=(values:number[],minimum=2)=>{
  if(!Array.isArray(values)||values.length<minimum)throw new Error(`values must contain at least ${minimum} observations`);
  return values.map((value,index)=>finite(value,`values[${index}]`));
};
const coefficients=(values:number[],name:string,allowEmpty=true)=>{
  if(!Array.isArray(values)||(!allowEmpty&&values.length===0))throw new Error(`${name} must be a coefficient list`);
  return values.map((value,index)=>finite(value,`${name}[${index}]`));
};

function armaCore(values:number[],ar:number[],ma:number[],intercept:number,horizon:number):ForecastResult{
  const a=coefficients(ar,"ar"),m=coefficients(ma,"ma");
  if(a.length===0&&m.length===0)throw new Error("at least one AR or MA coefficient is required");
  const p=a.length,q=m.length,y=series(values,Math.max(p+2,q+2,3)),c=finite(intercept,"intercept"),H=positiveInt(horizon,"horizon");
  const fitted:(number|null)[]=Array(y.length).fill(null),residuals:number[]=Array(y.length).fill(0);
  for(let t=p;t<y.length;t++){
    let prediction=c;
    for(let lag=1;lag<=p;lag++)prediction+=a[lag-1]*y[t-lag];
    for(let lag=1;lag<=q;lag++)if(t-lag>=0)prediction+=m[lag-1]*residuals[t-lag];
    fitted[t]=prediction;residuals[t]=y[t]-prediction;
  }
  const extended=[...y],errors=[...residuals],forecast:number[]=[];
  for(let step=0;step<H;step++){
    const t=extended.length;let prediction=c;
    for(let lag=1;lag<=p;lag++)prediction+=a[lag-1]*extended[t-lag];
    for(let lag=1;lag<=q;lag++)if(t-lag>=0)prediction+=m[lag-1]*errors[t-lag];
    extended.push(prediction);errors.push(0);forecast.push(prediction);
  }
  return {forecast,fitted,residuals,state:{order:[p,q],last_values:y.slice(-Math.max(1,p)),last_residuals:residuals.slice(-Math.max(1,q)),presample_innovations:"zero",future_innovations:"zero conditional mean"}};
}

function differ(values:number[],order:number){
  if(!Number.isInteger(order)||order<0||order>2)throw new Error("difference order must be 0, 1, or 2");
  let current=[...values];const levels:number[][]=[current];
  for(let k=0;k<order;k++){current=current.slice(1).map((v,i)=>v-current[i]);levels.push(current);}
  return levels;
}
export function forecastARIMA(values:number[],ar:number[],ma:number[],intercept:number,differenceOrder:number,horizon:number):ForecastResult{
  const y=series(values,6),levels=differ(y,differenceOrder),base=armaCore(levels[levels.length-1],ar,ma,intercept,horizon);
  if(differenceOrder===0)return {...base,differenced_forecast:base.forecast,state:{...base.state,difference_order:0,integration_anchors:[]}};
  const last=levels.slice(0,differenceOrder).map(level=>level[level.length-1]),restored:number[]=[];
  for(const high of base.forecast){
    let increment=high;
    for(let k=differenceOrder-1;k>=0;k--){last[k]+=increment;increment=last[k];}
    restored.push(last[0]);
  }
  return {...base,forecast:restored,differenced_forecast:base.forecast,state:{...base.state,difference_order:differenceOrder,integration_anchors:levels.slice(0,differenceOrder).map(level=>level[level.length-1])}};
}
Full-height labarima labOpen full screen