← Back to dashboard
Forecast Model — Admin Panel

How the demand forecast is built

One pipeline, run per SKU, per month. Every stage below is a real rule in the code — nothing here is decorative. Follow the line top to bottom.

1

Demand — confirmed pieces per Single SKU

Bundles are split into their component Singles × quantity. If the History tab and Main both cover the same day, Main wins — nothing is double-counted. Same basis as DOH and Sellthrough, so numbers line up across the dashboard.

2

Source window — last 30 full days

Every feature is computed from the 30 days right before the target month, so nothing from the target month itself ever leaks in.

last 3/7/10/14/15/20/30 days first 7 days max day / max week StdDev / CV trend slope + R² momentum % zero days
3

Behavior classification

Every SKU is tagged with exactly one demand pattern from those 30-day features. Incompatible patterns are never trained or predicted together.

Shifting Up Shifting Down Steady Non-Linear / Volatile Spiky
4

Size segment — split by volume, not just behavior

Independently of behavior, every SKU also falls into a volume segment. The forecasting method is chosen per segment, because one method does not win everywhere.

SEGMENT A
100+ pcs / month
Method re-scored every run from real backtests + bias correction (±25% cap), then blended 70% with the average of all rules so one bad pick can't sink the month. Measured: 55.8% → 57.6%, worst month 33.9% → 46.1%.
SEGMENT B
30–99 pcs / month
Fixed method: TSB (intermittent-demand model). Measured out-of-sample: 11.9% → 15.6% accuracy, bias −14% → −9%.
SEGMENT C
under 30 pcs / month
Fixed method: TSB, tuned for even gappier series. Measured: 5.1% → 6.0% accuracy, bias −49% → −45%.
5

Method picking — tested on the past, not assumed

For Segment A, every candidate method below is scored against real past months, using models that never saw those months. Lowest real error wins — the forecast can't quietly end up worse than doing nothing.

last 7d × 30/7 (capped ±40% of naive) last 10d × 3 (capped ±40% of naive) last 14d × 30/14 last 15d × 30/15 (capped ±40% of naive) last 21d × 30/21 half last-14 + half last-30 the ML model half model + half last-14
6

Model — ridge regression, per behavior

Trained on log(1 + next-month demand), so an uninformative model lands on "same as last 30 days" instead of drifting to the catalogue average. Non-Linear / Volatile SKUs get a hurdle model instead: probability of selling at all × expected amount.

7

Baseline — the rule-based anchor

A non-ML estimate, one formula per behavior. This is what the ML forecast is blended against and capped around — a transparent number you can explain without touching the model.

BehaviorBaseline formula
Shifting Upmax(30d total, last10×3, last7×4)
Shifting Down0.6×(first7×4) + 0.4×(last14×30/14)
Steadymean day × 30
Non-Linear / Volatilemax(maxWeek, maxDay×7, 30d total)
Spiky30-day total
8

Blend

Final = w × ML  +  (1 − w) × Baseline

w rises when the model agrees with the behavior pattern and volatility (CV) is moderate. It drops when the model and the pattern disagree — the forecast leans back on the transparent baseline instead.

9

Guardrails — the forecast can't run away

BehaviorCap
Shifting Upfloor ≥ 0.85 × (last7×4)
Shifting Downceiling ≤ 1.10 × baseline
Steadywithin ±15% of its level
Non-Linear / Volatilecap ≤ 2.75 × 30d total
Spikycap ≤ 1.5 × 30d total
10

V2 outlier dampening

SKUs that missed by 100%+ last month, or that are thin and erratic (≤5 selling days, CV > 2), get flagged. Their deviation from the baseline is halved before the guardrail is applied — a second, targeted brake on the SKUs most likely to overshoot. Toggle with V2 On/Off.

11

Stock ceiling — segment A, known-stock months only

For a month whose real opening stock is known (every backtest, plus the current month), a segment-A forecast is capped at 2.5 × what could actually be supplied = beginning inventory + inbound. It's an accuracy correction — you can't confirm more than you can supply — that removes wild over-forecasts on SKUs that never had the stock.

Segment A accuracy
44.9% → 54.2% (measured, 7 real months)
Next month is NOT capped
the purchase-plan number needs true demand — capping it to current stock would make you under-buy
12

Output — forecast + confidence range

Point forecast
scaled to the target month's day count
50 / 80 / 90% range
built from how far past forecasts actually missed, per size segment

No leakage, anywhere in this pipeline

Every "past months" reference above — the method scoring in step 5, the model training in step 6, the confidence range in step 11 — uses only month-pairs that ended before the month being predicted. A backtest for March is trained as if April never happened. The Naive column in the Accuracy Trend table shows what simply repeating last month would have scored, so Lift = what this whole pipeline actually adds over doing nothing.