The order-economics guide sets each SKU’s buy on its own: price the two ways to be wrong, take the critical-ratio quantile of the forecast. In practice, the sum of those buys rarely matches the money available. There is an open-to-buy budget, a cash ceiling, a warehouse that holds so much, a container that carries so much. So the real question is not only how much of each SKU, but which SKUs get the money first.
Most organizations answer it with a rule:
- One service level for everyone. Lower the target until the plan fits: “this season we buy to 90% instead of 95%.”
- An equal cut. Compute every buy, then trim each by the same percentage. Both decide by rule how scarce money is shared. None of them asks what each dollar would earn. This piece shows how to ask that question directly, what the answer looks like, and when it matters.
Every unit has its own expected return
Think of a buy not as a quantity per SKU but as a long list of individual units: the 1st trail runner, the 2nd, and so on up to the 136th; the 1st pair of socks up to the 786th. Each unit has an expected profit of its own. The -th unit sells if demand reaches , earning the price; otherwise it is cleared at the salvage value. With unit cost , price and clearance value ,
is the unit’s expected profit and its expected return per dollar spent. The first unit of an item almost always sells, so it returns the full markup, . Each additional unit is a little less likely to sell, so returns fall steadily until they reach zero at the critical-ratio quantile, which is exactly where the unconstrained newsvendor stops.
Rank every unit, then buy from the top
If the returns of all units of all SKUs are put in one list and sorted, the best use of a budget is to buy from the top of the list until the money runs out. Because each SKU’s returns only fall as you buy more of it, nothing further down the list can beat anything above it. This is the whole method. It needs nothing beyond the forecast and the unit economics you already have.
The exhibit applies it to a seasonal buy for an outdoor store with eight SKUs. Drag the budget down from the unconstrained optimum and watch where the money goes.
Exhibit 1 · Interactive
Rank every unit by what it earns per dollar, then buy from the top until the money runs out
Expected return per dollar of each successive unit, best first. The shaded area is the expected profit the budget buys.
What each SKU gets: units bought out of its unconstrained optimum, and the chance of not selling out
What the list does that rules cannot
At half of the unconstrained budget, the ranked list allocates as follows. The “one service level” rule, for comparison, has to drop to a 17% in-stock probability for every SKU to fit the same budget.
| SKU | Markup | Unconstrained buy | Ranked list buys | Ranked list in-stock | One service level buys | Equal cut buys |
|---|---|---|---|---|---|---|
| Wool socks | 300% | 786 | 628 | 62% | 434 | 393 |
| Water bottle | 150% | 475 | 324 | 33% | 273 | 237 |
| Rain shell | 144% | 89 | 50 | 28% | 40 | 44 |
| Headlamp | 122% | 240 | 125 | 22% | 114 | 120 |
| Trail runners | 117% | 136 | 80 | 19% | 77 | 68 |
| Trekking poles | 100% | 80 | 26 | 11% | 31 | 40 |
| Down parka | 86% | 35 | 6 | 1% | 15 | 17 |
| Novelty mug | 75% | 104 | 0 | 0% | 53 | 52 |
Four things stand out.
- Some SKUs get nothing. The last unit the budget buys earns 84 cents per dollar. The first novelty mug earns 75 cents, less than that, so no mug makes the cut, even though the mug sells 150 a season. The rule is general: when the last dollar earns a return , every SKU whose markup is below gets nothing, whatever its volume. The down parka, at an 86% markup, barely clears the bar and gets 6 units.
- Service levels are an output, and they differ widely. In-stock probabilities run from 62% for socks to zero for mugs. The “one service level” rule forces them all to 17%, which overbuys the parka and the mug and underbuys the socks and bottles that earn the most per dollar.
- Size is not value. The parka has the highest price and the second-highest revenue in the assortment, and it is nearly cut out. A unit’s claim on the budget comes from what it earns per dollar, not from how big or how visible the item is. This is precisely where ABC classification goes wrong. Ranking by revenue would make the parka an A item and protect it first, sending scarce budget to the units that earn the least per dollar. ABC sorts items by size and then pretends the sort is an economic decision; it is not, and no choice of class boundaries fixes that.
- The budget has a price. The return on the last dollar, , is what one more dollar of budget would earn. At half budget, another $1,000 adds about $821 of expected profit. That is the number to bring to a budget discussion: if money costs less than that, the budget is too small.
The budget acts as a markup on every unit’s cost
The same result can be written in a form that connects back to the critical ratio. Spending the budget optimally is equivalent to solving each SKU on its own, but as if every unit cost instead of :
This is the newsvendor critical ratio with an inflated cost, where is the Lagrange multiplier of the budget constraint. A tight budget raises the effective cost of every unit by the same percentage, which hurts low-markup items most and drives them to zero first. In the example, every SKU’s in-stock probability at half budget matches this formula to within two percentage points.
How much does it matter?
Less than you might think when money is loose, and a great deal when it is tight.
Exhibit 2
Rules of thumb are nearly harmless when money is loose and expensive when it is tight
| Budget | Ranked list | One service level | Equal cut | Ranked list advantage |
|---|---|---|---|---|
| 100% ($31,011) | $27,681 | $27,343 | $27,681 | +1.2% over one service level |
| 75% ($23,258) | $26,243 | $25,792 | $25,900 | +1.3% to +1.8% |
| 50% ($15,506) | $21,372 | $20,414 | $19,883 | +4.7% to +7.5% |
| 30% ($9,303) | $15,153 | $13,374 | $12,262 | +13.3% to +23.6% |
Two conclusions follow. First, when the budget nearly covers the unconstrained buy, the rules of thumb cost about one to two percent, and the real gain comes from getting each SKU’s economics right in the first place. Even at full budget, one service level for all loses money, because it ignores that the optimal service level differs by SKU. Second, the tighter the budget, the more the allocation matters. At 30% of the unconstrained buy, the ranked list earns 13% to 24% more expected profit than the rules, from the same money and the same forecast. Tight budgets are exactly when organizations reach for blunt rules, and exactly when blunt rules cost the most.
Check it in a simulator
Everything above is computed from expected values. A season is not an expected value: demand comes in once, high for some SKUs and low for others, and the buy either fits it or does not. So the claims deserve a test that does not rely on the same formulas. A simulator provides it. Draw thousands of demand scenarios from the same forecasts, play the season out under each policy, and record what each one would actually have earned. Every policy faces exactly the same scenarios, so any difference comes from the quantities alone.
Exhibit 3 · Interactive
Play the season out 2,000 times: the ranked list wins most seasons and earns its edge in the good ones
In a run of 5,000 simulated seasons:
| Budget | Average profit: ranked list / one service level / equal cut | Seasons the ranked list wins, against each rule | Bad season (10th percentile): ranked list / one service level / equal cut |
|---|---|---|---|
| 75% | $26,232 / $25,765 / $25,889 | 62% / 61% | $21,938 / $21,866 / $21,991 |
| 50% | $21,384 / $20,419 / $19,899 | 73% / 81% | $18,915 / $18,948 / $18,427 |
| 30% | $15,156 / $13,372 / $12,261 | 89% / 98% | $13,312 / $13,302 / $12,036 |
Three things come out of it.
- The averages match the formulas to within sampling error. The expected-profit figures in the exhibits above are not artifacts of the approximation; they are what the season delivers on average.
- The ranked list wins most seasons, not all of them. It maximizes expected profit, which is a statement about the average. In roughly a third of seasons at a 75% budget, demand happens to favor what the rules bought. The tighter the budget, the more consistently the ranked list comes out ahead.
- It concentrates the budget, so outcomes spread more. The rules spread a small budget thinly across everything, which makes every unit very likely to sell and every season look alike. At half budget, one service level sells out of every SKU in nearly a quarter of seasons, so a strong season cannot earn it anything more. The ranked list puts the money where the return is highest, so good seasons are much better and bad seasons are about as bad as under the rules: the 10th-percentile seasons are within a few dollars of each other at every budget. The very worst seasons can be somewhat worse.
That third point is where a simulator earns its keep. If the business genuinely cares about bad seasons beyond their effect on the average, for example because a weak season breaches a covenant, that is a cost, and it can be priced: a penalty on profit below a threshold, or on cash tied up at season end. The simulator then scores each policy on that richer economic objective, scenario by scenario. What it should not do is replace the economics with a gut preference for “safer” allocations that nobody has priced.
The same tool covers what the closed-form math cannot: case packs and minimum orders, substitution between SKUs when one sells out, a shared truck, a markdown schedule. Write the rules of the season, feed it forecast scenarios, and let it score candidate decisions. The formulas find good candidates quickly; the simulator is how you check them against the world they will meet.
Beyond a cash budget
The same idea extends with small changes.
- Other scarce resources. If the binding limit is shelf space, warehouse volume or container capacity rather than cash, rank units by expected profit per unit of that resource: per cubic meter, per pallet position, per kilogram.
- Several limits at once. With a cash budget and a space limit together, one ranking no longer suffices. Each limit gets its own price, and the problem becomes a small linear or mixed-integer program. The prices still have the same meaning: what one more unit of each resource is worth.
- Lots and minimum orders. If a SKU can only be bought in cases of 12 or in a minimum order of 200, rank lots instead of units. The list is then a heuristic rather than exactly optimal, because lots are lumpy, which makes it a knapsack problem. In practice the greedy list is usually very close.
- Repeated replenishment. For stock that carries over, replace the clearance loss with the holding and ageing cost over the protection interval from How long does inventory need to last?. The ranking logic is the same: the next unit of each SKU earns its margin times the chance it is needed, minus the cost of carrying it if it is not.
In Python
Working from forecast samples keeps it general: any probabilistic forecast that produces demand scenarios can drive the list.
import numpy as np
rng = np.random.default_rng(0)
# name: (unit cost, price, clearance value, forecast mean, coefficient of variation)
skus = {
"Trail runners": (60, 130, 30, 120, 0.40),
"Rain shell": (45, 110, 15, 80, 0.60),
"Wool socks": ( 4, 16, 2, 600, 0.30),
"Headlamp": (18, 40, 10, 200, 0.50),
"Down parka": (140, 260, 50, 40, 0.80),
"Water bottle": ( 6, 15, 3, 400, 0.35),
"Trekking poles": (35, 70, 20, 70, 0.70),
"Novelty mug": ( 8, 14, 1, 150, 0.90),
}
def forecast_samples(mean, cv, n=50_000):
"""Stand-in for a probabilistic forecast: demand scenarios for the season."""
s2 = np.log(1 + cv**2)
return rng.lognormal(np.log(mean) - s2 / 2, np.sqrt(s2), n)
# Every unit worth buying, with its expected profit and return per dollar.
units = []
for name, (c, p, v, mean, cv) in skus.items():
d = np.sort(forecast_samples(mean, cv))
k = np.arange(1, int(d[-1]) + 1)
p_sold = 1 - np.searchsorted(d, k - 0.5) / len(d) # chance the k-th unit sells
value = (p - v) * p_sold - (c - v) # expected profit of the k-th unit
for kk, val in zip(k, value):
if val <= 0:
break
units.append((val / c, int(kk), name, val, c))
units.sort(key=lambda u: (-u[0], u[1])) # best return first
def allocate(budget):
qty, spend, profit, last = {n: 0 for n in skus}, 0.0, 0.0, None
for ret, k, name, val, c in units:
if k == qty[name] + 1 and spend + c <= budget:
qty[name], spend, profit, last = k, spend + c, profit + val, ret
return qty, spend, profit, last
qty, spend, profit, last = allocate(15_506)
print(qty)
print(f"spend ${spend:,.0f}, expected profit ${profit:,.0f}, last dollar earns {last:.0%}")
# {'Trail runners': 80, 'Rain shell': 51, 'Wool socks': 629, 'Headlamp': 127,
# 'Down parka': 5, 'Water bottle': 327, 'Trekking poles': 27, 'Novelty mug': 0}
# spend $15,504, expected profit $21,369, last dollar earns 83%
The sample-based version reproduces the exact calculation used in the exhibits to within a few dollars. Sorting tens of thousands of candidate units is instant; for very large catalogs, a priority queue that only expands each SKU’s next unit does the same work without materializing the full list.
Common mistakes
- Cutting every SKU by the same percentage. It keeps low-return units and drops high-return ones in equal measure.
- Lowering one service level until the plan fits. It ignores that each SKU’s right service level was different to begin with, and the gap widens as the budget shrinks.
- Ranking by revenue or volume, including ABC classes. What matters is expected profit per dollar of the scarce resource. High-revenue, low-markup items are often the first that should lose budget, which is the opposite of what an ABC policy does.
- Treating zero as a failure. A SKU that gets nothing under a tight budget is not being neglected; its first unit earns less than the last unit of something else.
- Judging a policy by one season. At half budget, the ranked list loses about one season in four to one service level and still earns more over time. Score policies across many simulated seasons, not on last year’s outcome.
- Arguing about the budget without its price. The return on the last dollar tells you what more budget would earn. Without it, budget negotiations are about opinions.
Where to go next
- How much to order sets each SKU’s unconstrained buy from its economics.
- How long does inventory need to last? covers the protection interval and the cadence for repeating orders.
- The newsvendor guide derives the single-SKU result this piece builds on, including the Lagrange multiplier for a shared budget.