This project asks a simple question: where should a retailer keep its backup stock? The network here has one overseas factory, three regional warehouses (North America, Europe, Asia-Pacific), and ten stores. Every number on this page comes from a simulation that was given only past data to plan with, then tested against a later period it had never seen - the same way a real policy would have to work.
Every technical term used anywhere on this page is defined below. Nothing further down assumes you have read a supply-chain textbook.
Two levels hold stock: three regional warehouses, and the ten stores they supply. Everything starts at a single overseas factory. The shape matters because the two legs of the journey are wildly different lengths: a month or more by sea to reach a warehouse, then a couple of days by road to reach a shop. That mismatch is what the rest of this page is about.
Network structure in text: a single overseas factory feeds three regional warehouses. DC-1 · R1, the Los Angeles DC in North America, sits 35 days from the factory and serves 4 stores: S01, S02, S03 and S04. DC-2 · R2, the Rotterdam DC in Europe, sits 45 days from the factory and serves 3 stores: S05, S06 and S07. DC-3 · R3, the Singapore DC in Asia-Pacific, sits 30 days from the factory and serves 3 stores: S08, S09 and S10. Factory to warehouse lead times run 30 to 45 days by sea including customs. Warehouse to store deliveries take 2 to 5 days by road. Every store is held to a 95% service target.
Note that this is a simple tree: every store is supplied by exactly one warehouse, so there is a single path from the factory to any shop. That is what makes the pooling question tractable here, and it is a different shape from a hierarchy where product and geography cross one another.
Where a network branches is where the money and the risk sit. A warehouse that serves four stores is carrying risk for all four at once, so getting its stock level wrong has four times the blast radius of getting one shop wrong. That is the argument for planning the levels together rather than one at a time.
The long sea leg is the other half of the picture. An order placed today for a warehouse arrives more than a month from now, against a forecast made today. The shops, by contrast, can be corrected within days. Most of the difficulty in this project comes from that asymmetry.
When a regional warehouse runs empty, the damage is not limited to one shop. Every store that depends on that warehouse is stranded at once - they place their restock orders as normal and simply do not receive the goods, however well their own shelves were planned. A single warehouse shortage in this network therefore turns into simultaneous empty shelves across three or four stores, during the busiest trading weeks of the year, which is precisely when lost sales are most expensive and most visible to customers.
This is also the failure that is hardest to see coming. The textbook method reports healthy numbers for three quarters out of four. Anyone reviewing it in a calm period would reasonably conclude it was working fine.
Why it happens. The textbook method sizes each warehouse’s backup stock with a standard formula that assumes each day’s demand is unrelated to the last. Real demand is not like that: it has a weekly rhythm, a Christmas season, and a growth trend, so busy days arrive in clusters. Across a 30to45 day sea crossing those clusters pile up, and the true swing in demand turns out to be between 2.8× and 10.6× larger than the formula assumes. The formula therefore buys a backup stock sized for a calm world. The new method sizes the same backup stock from what demand actually did over that same 30to45 day window, so the clustering is already accounted for.
This is a warning about how inventory plans are usually reviewed. The textbook formula is not broken in an obvious way, it is the standard approach taught everywhere, and it performs perfectly well for most of the year. Its weakness only appears under demand pressure, which is the one condition where being wrong is expensive.
The practical implication is that a policy should never be judged on an average or a quiet period. It should be judged on its worst quarter, because that is where the lost sales, the emergency freight bills, and the disappointed customers actually occur. Any review process that looks at annual averages will systematically miss this.
A business case built on “this saves 2.7%” would be on shaky ground: in a quiet quarter the real figure is nearer 1.5%, and anyone checking the books three months later would find the promised saving missing. A business case built on “this saves between 1.5% and 8.3%, averaging under 4%, and it holds our warehouses at full reliability even at Christmas” is both more honest and more persuasive, because the reliability part is the finding that actually replicated every time.
It is also worth being clear that this is a modest saving on its own. The reason to adopt the approach is that shelves stay stocked in peak season; the cost reduction is a bonus, not the headline.
The shared-warehouse method assumes a regional warehouse can rush an emergency delivery to a nearby store quickly. The faster that is, the less backup stock each store has to hold itself. This was the single softest assumption in the whole model, so it was tested directly. Move the slider to see what the simulation actually produced at each speed.
Models usually rest on a handful of assumptions nobody can verify, and the honest question is always “how much would it matter if this were wrong?” Here that question has an answer, and the answer is reassuring: even if the assumed emergency delivery speed is off by a factor of three, the recommendation does not change.
That is worth knowing before committing money to a change. It means the case does not depend on negotiating a fast internal courier arrangement, and it removes an obvious line of objection from anyone reviewing the proposal.
This is the most common way an inventory review goes wrong. Cost is easy to measure and lands straight on a financial report; stockouts are diffuse, show up as lost sales nobody logged, and rarely get attributed back to an inventory decision. So the policy that quietly runs out of stock can look like the responsible, frugal choice on paper.
Putting the service figure directly on the cost bar is a deliberate guard against that. Any time someone presents an inventory saving, the first question should be what happened to availability over the same period.
These bars start at zero, so the differences look modest, and they genuinely are modest in ordinary quarters. The gap opens up in Q4. The larger operational difference between the two methods is in the warehouses, shown at the top of this page.
One row per location per method per test period.
The test. Four separate tests were run. Each one builds the stocking plan using only the history up to a cut-off date, then simulates the following three months day by day, stores selling, ordering from their warehouse, warehouses ordering from the factory, deliveries arriving after realistic delays. Demand the shops could not supply is treated as a lost sale, not a delayed one, which is how retail actually works. The simulation runs for two months before measurement starts, so it is not being judged on its opening conditions.
Why the standard formula was replaced. The textbook approach understates how much demand really swings over a 30to45 day sea crossing, by between 2.8× and 10.6× at the warehouses, because it assumes each day is unrelated to the one before. Every backup stock figure here is instead taken from what demand actually did over windows of that same length in the real history.
Where the saving comes from. The stores do not all get busy at the same time, Sydney peaks mid-year while Tokyo and Jakarta peak in December. That means one shared pile of backup stock at the warehouse only needs 65to75% of what ten separate piles would. This was measured by adding up genuine simultaneous shortfalls in the history, not assumed.
What this cannot tell you.
Source: rolling-window backtest of 4 test periods × 3 methods ×
13 locations. Generated by src/rolling_validation.py, with the
emergency-delivery comparison from src/validate_policy.py.
This page is a static build of the Streamlit dashboard
(dashboard.py), same data, no server required.
·
Source
code on GitHub