Skip to main content

Inventory Forecasting Algorithm (Technical)

Written by Kostis Mamassis

The Inventory Forecasting module estimates future replenishment needs by projecting inventory forward for each product and forecast period based on a seasonally adjusted exponentially weighted moving-average demand forecast model.

This article explains the algorithm using formulas only.

Forecast period setup

Let:

• P = selected number of forecast periods

• L = selected forecast period length

• H = selected history range in months

• D = selected demand decay factor (monthly)

• ADM = average days per month (30.4375)

For each future period Pₙ, the algorithm defines:

• PeriodStartₙ

• PeriodEndₙ (exclusive)

• PeriodDaysₙ = Days(PeriodStartₙ, PeriodEndₙ)

• ForecastPeriodMonthsₙ = PeriodDaysₙ / ADM (display only)

Historical daily demand

The history window covers:

• HistoryStartDate = EndDateExclusive − H months

• HistoryDayCount = Days(HistoryStartDate, EndDateExclusive)

For each product and warehouse, historical demand is grouped by calendar day:

• DailyQtyd = total historical demand on day d

The monthly decay factor D is converted to a daily equivalent:

• DailyDecayFactor = D^(1 / ADM)

Each historical day is weighted by recency:

• Weightd = DailyDecayFactor^(DaysAgod − 1)

where DaysAgod = Days(d, EndDateExclusive).

Weighted daily quantity:

• WeightedDailyQty = Σ(DailyQtyd × Weightd)

Weight total across the full history window:

• WeightTotal = (1 − DailyDecayFactor^HistoryDayCount) / (1 − DailyDecayFactor)

• (= HistoryDayCount when DailyDecayFactor = 1)

Weighted daily demand rate:

• WeightedDailyDemand = WeightedDailyQty / WeightTotal (units / day)

Overall average monthly demand (used only as the seasonality baseline):

• OverallAverageMonthlyDemand = (Σ DailyQtyd / HistoryDayCount) × ADM

Seasonality

For each future period, the algorithm slices the period into calendar-month segments and computes a demand-weighted seasonal average.

For each calendar month M overlapped by period Pₙ:

• SeasonalAverageForMonthM = average of HistoricalSalesByCalendarMonth for month M, starting from the item's first sale date

• DaysInSlice = days that period Pₙ falls within month M

Period-level seasonal average monthly demand:

• SeasonalAverageMonthlyDemandₙ = Σ(SeasonalAverageForMonthM × DaysInSlice) / Σ(DaysInSlice)

Seasonality factor:

• SeasonalityFactorₙ = SeasonalAverageMonthlyDemandₙ / OverallAverageMonthlyDemand

• (= 1 when OverallAverageMonthlyDemand ≤ 0)

Forecast demand

Base forecast before seasonality (daily rate × period days):

• ForecastDemandBeforeSeasonalityₙ = WeightedDailyDemand × PeriodDaysₙ

Forecast after seasonality before rounding:

• ForecastDemandAfterSeasonalityBeforeRoundingₙ = WeightedDailyDemand × SeasonalityFactorₙ × PeriodDaysₙ

Final forecast demand:

• ForecastDemandₙ = ROUND(ForecastDemandAfterSeasonalityBeforeRoundingₙ, 0)

Known future demand and supply

For each period:

• NonShippedSOQtyₙ = approved sales order demand expected in period n

• NonAllocatedWOQtyₙ = production-related demand expected in period n

• NonReceivedPOQtyₙ = approved purchase order supply expected in period n

• NonReceivedWOQtyₙ = approved production supply expected in period n

The expected date is set in the respective Purchase/Sales Orders in the Latest Expected Date field. For the Production Orders, this is stored under the Due Date field.

Demand to cover

For each period:

• DemandToCoverₙ = ForecastDemandₙ + NonShippedSOQtyₙ + NonAllocatedWOQtyₙ

Product-level aggregation

For each product and period, the algorithm aggregates across all selected inventory locations:

• CurrentStockLevelₙ = Σ(current stock across selected locations)

• StockAlertQtyₙ = Σ(stock alert level across selected locations)

• ForecastDemandₙ = Σ(forecast demand per location)

• DemandToCoverₙ = Σ(demand to cover per location)

• NonReceivedPOQtyₙ = Σ(incoming PO quantity)

• NonReceivedWOQtyₙ = Σ(incoming WO quantity)

Rolling inventory projection

First period

• StartingQty₁ = CurrentStockLevel₁

Projected quantity before planned purchase:

• ProjectedBeforePurchase₁ = StartingQty₁ + NonReceivedPOQty₁ + NonReceivedWOQty₁ − DemandToCover₁

Planned purchase quantity:

• PlannedPurchaseQty₁ = MAX(0, StockAlertQty₁ − ProjectedBeforePurchase₁)

Projected quantity after planned purchase:

• ProjectedAfterPurchase₁ = ProjectedBeforePurchase₁ + PlannedPurchaseQty₁

Subsequent periods

For each period n > 1:

• StartingQtyₙ = ProjectedAfterPurchaseₙ₋₁

Projected quantity before planned purchase:

• ProjectedBeforePurchaseₙ = StartingQtyₙ + NonReceivedPOQtyₙ + NonReceivedWOQtyₙ − DemandToCoverₙ

Planned purchase quantity:

• PlannedPurchaseQtyₙ = MAX(0, StockAlertQtyₙ − ProjectedBeforePurchaseₙ)

Projected quantity after planned purchase:

• ProjectedAfterPurchaseₙ = ProjectedBeforePurchaseₙ + PlannedPurchaseQtyₙ

Final displayed metrics per period

For each product and period, the module displays:

• Forecast Demand = ForecastDemandₙ

• Demand to Cover = DemandToCoverₙ

• Starting Quantity = StartingQtyₙ

• Projected Quantity = ProjectedBeforePurchaseₙ

• Total Stock Alert Level = StockAlertQtyₙ

• Planned Purchase Quantity Needed = PlannedPurchaseQtyₙ

Summary formula chain

For each period n:

• ForecastDemandₙ = ROUND(WeightedDailyDemand × SeasonalityFactorₙ × PeriodDaysₙ, 0)

• DemandToCoverₙ = ForecastDemandₙ + NonShippedSOQtyₙ + NonAllocatedWOQtyₙ

• ProjectedBeforePurchaseₙ = StartingQtyₙ + NonReceivedPOQtyₙ + NonReceivedWOQtyₙ − DemandToCoverₙ

• PlannedPurchaseQtyₙ = MAX(0, StockAlertQtyₙ − ProjectedBeforePurchaseₙ)

• ProjectedAfterPurchaseₙ = ProjectedBeforePurchaseₙ + PlannedPurchaseQtyₙ

And for n > 1:

• StartingQtyₙ = ProjectedAfterPurchaseₙ₋₁

Did this answer your question?