DataCraves logo DataCraves
← All use cases
E-commerce

Forecast inventory demand 30 days out — by SKU, by region

Stockouts kill conversion; over-ordering kills margin. Most demand forecasts are spreadsheets updated weekly by one analyst, blind to weather, promo cadence, and competitor pricing.

⚠️ Charts, numbers, and "client" examples on this page use illustrative mock data. Real client deployments are confidential.

The Problem

Inventory is the unsexy P&L lever that quietly destroys margin in fast-moving consumer businesses. Stockouts kill conversion at exactly the moment a customer is willing to spend. Over-ordering ties up working capital and forces end-of-season discounting that compresses margin for months.

The tooling most teams use looks something like this: one analyst, one Google Sheet of last year's sales by SKU, a column for "judgement adjustment", and a Friday meeting where the merchandising team argues. It works for the top 10% of SKUs that everyone has opinions about. It fails badly for the long tail of 4,000 SKUs where nobody has time to look.

Three structural problems make this worse:

⚠ Numbers below are illustrative. Real client data is confidential.

The DataCraves Approach

The Forecast Agent ingests sales history, the promo calendar, weather forecasts, and competitor pricing feeds. It produces a per-SKU × per-region 30-day demand forecast every night, with a 90% confidence band, and pushes PO suggestions to the ERP for any SKU heading for stockout inside its lead-time window.

We use a hybrid model — Prophet for the seasonal/trend baseline, an XGBoost residual model that captures non-linear lift from promos and weather. The two are blended per SKU class, weighted by which performed better on the trailing 60-day holdout.

Why hybrid, not pure ML

Pure XGBoost forecasts overfit on long-tail SKUs with sparse data. Pure Prophet misses the discontinuities caused by promos. Hybrid gives you the seasonality of one and the lift-modeling of the other, and lets you fall back to baseline when the residual model is uncertain.

The Architecture

Inventory pipeline architecture
Diagram 1 — Data pipeline. Internal sales + external signals are blended through a hybrid Prophet + XGBoost forecast.
Decision tree from forecast to PO suggestion
Diagram 2 — Decision flow. Forecast → stockout check → lead-time check → PO suggestion. Express ship is a fallback for tight windows.
Feedback loop with champion-challenger
Diagram 3 — Champion-challenger feedback loop. Models retrain only when MAPE drift exceeds threshold, then must beat the champion on holdout.

The Dashboard

SKUs forecasted
4,287
+ 142 LTM
Stockouts avoided
218
▼ 27% YoY
Working capital freed
₹3.2 Cr
▲ 14%
Forecast MAPE
11.4%
▼ 8 pp
30-day demand forecast — flagship SKU
Confidence band widens with horizon — typical for hybrid models.
Forecast accuracy by SKU class
Long-tail SKUs benefit the most from the residual model.
Inventory turns by category
Beauty turns 12× / yr; Home is the working-capital drag.
Stockout events — week by week
12-week pilot in mid-market apparel.
Promo lift — modeled vs actual
Roughly y=x — model captures lift faithfully.
Demand mix by region
North + South drive 62% of volume.

The Math / The Logic

For each SKU × region pair, we compute three forecasts and blend:

# forecast_blend.py
from prophet import Prophet
import xgboost as xgb

def forecast_sku(history_df, exog_df, horizon=30):
    # 1. Prophet baseline — seasonality + trend
    p = Prophet(yearly_seasonality=True, weekly_seasonality=True,
                changepoint_prior_scale=0.05)
    p.fit(history_df.rename(columns={"date":"ds", "qty":"y"}))
    base_fc = p.predict(p.make_future_dataframe(periods=horizon))

    # 2. XGBoost residual — captures promo + weather lift
    resid_train = history_df["qty"] - base_fc["yhat"][:len(history_df)]
    feats = exog_df[["is_promo", "discount_pct", "temp_c",
                    "is_weekend", "competitor_price_idx"]]
    bst = xgb.XGBRegressor(n_estimators=300, max_depth=5,
                           learning_rate=0.05, subsample=0.85)
    bst.fit(feats[:len(history_df)], resid_train)
    resid_fc = bst.predict(feats[len(history_df):])

    # 3. Blend; weight by trailing-60d hold-out MAPE
    w_base, w_resid = blend_weights(base_fc, resid_fc, history_df)
    final = w_base * base_fc["yhat"][-horizon:] + w_resid * resid_fc

    return final, confidence_band(final, sigma=residual_std(history_df))

Reorder rule. For each SKU we maintain a target service level (default 95%, configurable per category). Reorder point is computed as:

reorder_point = forecast_lead_time + Z(0.95) * sigma_lead_time
suggest_qty   = forecast_(lead+review) + safety_stock - on_hand - on_order

Where Z(0.95) = 1.645 and sigma_lead_time is computed from the last 90 days of demand variance scaled to the lead-time window.

Sample Output / Insight

📨 Slack #merch-daily — Forecast Agent · 07:00 IST

Today's PO suggestions (mock data):

  • SKU FA-2241 (Cotton tee, Navy, M) — North region: stockout in 9 days at current pace; lead time 14 days. Express ship 320 units recommended.
  • SKU EL-7733 (Wireless earbuds) — South region: forecast +38% next 14 days vs trailing 30 (festive promo loaded). PO 1,400 units; current on-hand only covers 6 days.
  • SKU HM-1102 (Throw blanket) — Forecast collapsing (-22%) due to weather warm-up in West. Pause inbound 800 units; reroute to North.

3 more in dashboard. ERP draft POs ready for one-click approval.

ROI Math

Assumptions to challenge: figures assume promo cadence and weather signal are actually available. If you don't pipe weather, expect MAPE 3–4 pp higher and ROI ~30% lower.

Common Pitfalls

⚠ Forecasting at the wrong grain.
SKU × week is too coarse for fast movers; SKU × day × region is too sparse for the long tail. Pick per-category grain.
⚠ Ignoring substitution.
If colour-Navy is out, customers buy colour-Black. Model substitution cross-elasticity or your stockout cost is overstated.
⚠ Static safety stock.
A flat 14-day safety stock destroys margin on slow movers. Tier it by demand variance.
⚠ Not back-testing on the last bad season.
Always back-test on the worst forecast period of last year. If the model can't survive that, it can't survive next year.
⚠ Trusting auto-PO end-to-end on day one.
Run as suggestions for 6 weeks before letting the agent write to the ERP unattended.
📊 Mock data, real patterns.
📈
Expected ROI
Stockouts down ~25%, working capital tied up in inventory down ~15%

Based on early access deployments in apparel and consumer electronics; assumes baseline forecast MAPE of 22%+.

Run this on your own data?

A 30-minute demo shows the agents working against your warehouse — not a pre-baked sandbox.

Book a demo →

Mock data, real patterns. Every visualization is synthetic to preserve client confidentiality.