Guide · Small backtest
No consistent winner
Safety stock vs DDMRP-style buffers on retail sales: lower inventory, immediate fill and fewer order lines do not move together. These are simulated outcomes, not observed results at the retailer.
By Dan K., CPIM, DDMRP certified · Updated October 22, 2026
Drafted with AI assistance; every worked example is recomputed in code before publishing.
This small backtest uses Online Retail II, a UK gift retailer selling largely to wholesale customers. It compares a classic safety-stock policy with a simplified DDMRP-style buffer. There is no consistent winner: a lower inventory result can accompany lower immediate fill, and the comparison depends on the baseline and starting stock. These figures do not show that either method is better or that anyone will save money.
Data, cleaning and cohort
Source: Chen, D. (2012), Online Retail II, UCI Machine Learning Repository, DOI 10.24432/C5CG6D, licensed CC BY 4.0. Accessed October 20–21, 2026. Demand is aggregated weekly per SKU after these exclusions:
- Drop duplicate rows and cancellation invoices with a C prefix.
- Drop quantity ≤ 0 and price ≤ 0.
- Trim and uppercase item codes; keep only five digits followed by optional letters (
^\d{5}[A-Z]*$). - Drop partial first and last weeks.
The cohort contains 1,932 SKUs: at least 52 weeks of training span, at least 52 units and 13 positive weeks in the last 52 weeks of training, and sales in the final 13 weeks of training. The out-of-sample test is the final 26 weeks, June 6, 2011–December 4, 2011: 1,873,681 test units, or 59.2% of cleaned test-period units.
ABC cohort counts: A 515, B 608, C 809. XYZ counts: X 5, Y 344, Z 1,583. The 5-item X class is weak evidence; it cannot support a broad claim about stable-demand items.
Simulation method
Weekly review follows this sequence: receive, serve backorders, order, then demand, with a 26 weeks warm-up. The main results use lost sales: unmet demand is not carried forward. A backorder variant was also run, in which unmet units wait and receipts serve those backorders before new demand. All policies start from the same rolling classic target.
Classic safety stock
SS = z × sigma_weekly × sqrt(LT), with z for 95% cycle service.
Order up to (LT + 1) × mean + SS, where LT is in weeks and the extra 1 week covers weekly review. Parameters are fixed from training history starting at each SKU's first sale. The cycle-service setting is not the achieved immediate unit fill rate.
Simplified DDMRP-style buffer
ADU uses trailing 13 weeks: total units in that window divided by (13 × 7 days). DLT is LT × 7 days. LTF is 0.5. VF depends on CV: below 0.5, use 0.25; from 0.5 through 1, use 0.5; above 1, use 0.75.
red = ADU × DLT × LTF × (1 + VF)yellow = ADU × DLTgreen = max(ADU × DLT × LTF, ADU × 7 days)- Order to top of green when net flow ≤ top of yellow, in whole units.
This is simplified DDMRP, with no spike qualification or planned adjustments. Lead times are assumed. There is no MOQ, capacity or cost model. The policies were not tuned to equal service.
Lost-sales results: inventory and service together
Average week-end units are the time average of the cohort's total stock, not a per-item average or a money value. Immediate unit fill is the share of demand served without waiting. Stockout SKU-weeks are out of 50,232 possible SKU-weeks (1,932 × 26); they are not a count of distinct items.
Lost-sales simulation: fixed classic and DDMRP-style buffer · Swipe sideways to see all columns.
| Lead time | Policy | Average week-end units | Immediate unit fill | Stockout SKU-weeks | Order lines |
|---|---|---|---|---|---|
| 2 weeks | Classic (fixed) | 373,078.5 | 83.87% | 3,455 | 31,010 |
| 2 weeks | DDMRP-style | 244,150.4 | 77.68% | 6,480 | 12,948 |
| 4 weeks | Classic (fixed) | 558,900.1 | 84.86% | 3,173 | 30,403 |
| 4 weeks | DDMRP-style | 531,546.9 | 85.08% | 3,766 | 7,910 |
Buffer differences from fixed classic, calculated from the reported figures · Swipe sideways to see all columns.
| Lead time | Average inventory | Immediate fill change | Order lines | Stockout SKU-week rate: classic → buffer |
|---|---|---|---|---|
| 2 weeks | 34.6% less | −6.19 pp | 58.2% fewer | 6.9% → 12.9% |
| 4 weeks | 4.9% less | +0.22 pp | 74.0% fewer | 6.3% → 7.5% |
“pp” means percentage points: a difference between fill percentages. Inventory and order-line changes use the classic result as their denominator. Displayed comparisons are calculated from the reported, rounded figures.
A rolling classic baseline changes the comparison
Updating classic parameters over the same rolling 13 weeks gives another baseline. A comparison with fixed training parameters alone does not isolate the effect of the buffer rules from adapting to recent demand.
Rolling classic baseline and buffer differences · Swipe sideways to see all columns.
| Lead time | Rolling classic average units | Rolling classic immediate fill | Buffer inventory vs rolling classic | Buffer fill change vs rolling classic |
|---|---|---|---|---|
| 2 weeks | 326,570.4 | 83.46% | 25.2% less | −5.78 pp |
| 4 weeks | 518,659.8 | 83.96% | 2.5% more | +1.12 pp |
Aggregate fill hides different outcomes by class
Immediate unit fill by ABC class: fixed classic → buffer · Swipe sideways to see all columns.
| Lead time | Class | Classic fill | Buffer fill | Change |
|---|---|---|---|---|
| 2 weeks | A (515 SKUs) | 89.56% | 81.80% | −7.76 pp |
| 2 weeks | C (809 SKUs) | 61.90% | 63.82% | +1.92 pp |
| 4 weeks | A (515 SKUs) | 90.57% | 88.86% | −1.71 pp |
| 4 weeks | C (809 SKUs) | 63.09% | 72.29% | +9.20 pp |
If A-item availability is important in your setting, check it separately: the buffer lost A-item fill at both lead times in this simulation, even where the aggregate fill was slightly higher. C-item gains here would not establish a gain for another business.
Backorder variant
Backorder simulation: immediate unit fill
| Lead time | Classic | DDMRP-style buffer |
|---|---|---|
| 2 weeks | 77.34% | 69.59% |
| 4 weeks | 76.88% | 79.26% |
These are immediate-fill results, not eventual fulfillment. If your business carries shortages forward, test that behavior rather than treating the lost-sales result as interchangeable.
How we checked
An independent implementation reproduced every figure within 0.5% after matching two conventions: history starts at each SKU's first sale, and all policies share the same starting stock. Agreement checks the simulation's implementation; it does not validate the retailer's unobserved stock availability or make these policies equally calibrated.
This page publishes the reported study summary. Site tests lock those figures and recompute the displayed percentage comparisons; those page tests do not rerun the original backtest.
What this cannot establish
- These are simulated outcomes, not observed inventory or service results at the retailer.
- Recorded sales hide past stockouts; observed sales need not equal unconstrained demand.
- Lead times are assumed; there is no MOQ, capacity or cost model.
- The buffer is simplified DDMRP, without spike qualification or planned adjustments.
- The policies were not tuned to equal service; a lower stock result can mean less immediate fulfillment.
- One retailer is not a general result. The 5-item X class is weak evidence.
- The starting-stock sensitivity reverses the inventory ranking; neither policy is shown to be better or to save money.
Conditional takeaways for a policy comparison
- If fewer order lines matter operationally, the buffer's sharp reduction here is a reason to test that metric alongside fill, not a cost-saving estimate.
- If service on A items matters, check that class explicitly before acting on cohort averages.
- If comparing policies on your own data, include a rolling baseline, vary the common starting stock and check service at matched targets before making a decision.
Attribution: Chen, D. (2012). Online Retail II. UCI Machine Learning Repository. DOI: 10.24432/C5CG6D. CC BY 4.0. Accessed October 20–21, 2026. Data were cleaned, aggregated to weekly SKU demand and used for the simulations described above.
FAQ
Does this study show that DDMRP or safety stock is better?
No. These are simulated outcomes from one retailer's recorded sales, not observed inventory or service results at that retailer. The policies were not tuned to equal service, and the inventory ranking changes with the baseline and starting-stock assumption. Neither method is a consistent winner.
Why does the starting stock matter?
All policies start from the same rolling classic target in the main run. With a different common start, the fixed classic target, the 4 weeks buffer inventory ranking reverses: 4.4% more instead of 4.9% less. A common start does not make the result insensitive to the choice of start.
Is the buffer policy a full DDMRP implementation?
No. It is a simplified DDMRP-style policy using trailing usage, lead-time and variability factors, buffer zones and a net-flow trigger. It has no spike qualification or planned adjustments, and the simulation includes no MOQ, capacity or costs.
Is the classic service setting the achieved fill rate?
No. The classic formula uses z for 95% cycle service. Immediate unit fill is measured separately in the simulation. The setting does not guarantee that percentage of units will be served immediately.
Can these results predict savings for my business?
No. Recorded sales hide past stockouts, lead times are assumed, costs are absent and only one retailer is studied. If you compare policies on your own data, check service by item class, multiple baselines and sensitivity to starting stock before drawing a conclusion.
Related tools
- Inventory buffer zone calculator →
- DDMRP planning workspace →
- Safety stock calculator →
- Reorder point calculator →
- EOQ calculator →
- ABC/XYZ analysis →
- BOM explosion calculator →
- Forecast accuracy calculator →
- Days of supply calculator →
- Kanban calculator →
- Inventory turnover calculator →
- Min max inventory calculator →