Retailers rarely know their demand curve — they only observe how many units sell at whatever price was charged. This simulation hides a constant-elasticity demand curve, demand = k·price^(−ε), behind a noisy, inventory-censored sales signal and lets a pricing engine discover it live. Each simulated day the engine either exploits its current best price estimate or explores a nearby price to keep learning, exactly like a multi-armed bandit balancing exploitation against information gain.
Underneath, a rolling log-log linear regression on the last 30 (price, units-sold) observations recovers an estimate of ε and the demand scale k. A grid search over the allowed price range then scores every candidate price by expected revenue minus a penalty for drifting away from the pace needed to sell the remaining inventory by the end of the horizon — a simplified version of the terminal-inventory revenue-management problem airlines and retailers solve every day.
What is demand elasticity, and how does the engine estimate it without ever seeing it?
Price elasticity of demand ε measures how sharply quantity demanded reacts to price: a 1% price rise shrinks demand by roughly ε%. This simulation generates true daily demand from a constant-elasticity curve, demand = k·price^(−ε), but the engine is never told k or ε — it only observes the noisy, inventory-capped units actually sold at whatever price it charged that day. By taking logs, ln(demand) = ln(k) − ε·ln(price) becomes a straight line, so an ordinary least-squares regression on the last 30 (price, sold) pairs recovers estimates of both k and ε directly from the slope and intercept.
Why does the engine "probe" nearby prices instead of jumping straight to the optimum?
A regression fit on a narrow cluster of prices is unreliable — if every observation sits near $38–$42, the slope estimate barely constrains ε outside that range, and the estimated revenue curve can be badly wrong once extrapolated. The engine therefore behaves like a multi-armed bandit: most days it exploits the price its current model believes is best, but with probability ε-bandit (the exploration-rate slider) it instead nudges the price to a random nearby level purely to collect a more informative data point. This exploration/exploitation trade-off is the same one used in real online pricing and ad-auction systems.
Why is there sometimes no interior price that maximizes revenue?
Revenue under constant elasticity is R(p) = p·k·p^(−ε) = k·p^(1−ε). If ε > 1 (elastic demand), the exponent 1−ε is negative, so R(p) is strictly decreasing in p — revenue is maximized by charging the lowest price the engine is allowed to charge, and volume more than compensates for the lower margin. If ε < 1 (inelastic demand), 1−ε is positive and revenue keeps rising with price, so the best price is the highest one allowed. Only the case ε = 1 makes revenue flat. That is why this simulator always imposes explicit price floor and ceiling sliders — real "optimal price" problems are usually optimizations against a boundary, not a smooth interior peak.
Maximizing today's estimated revenue in isolation can sell out far too fast (leaving money on the table from customers who would have paid more) or far too slow (ending the season with unsold, discounted-to-zero stock). The engine computes a target pace — remaining inventory divided by remaining days — and scores each candidate price as estimated revenue minus λ·(estimated demand at that price − target pace)², where λ is the pacing-weight slider. A higher λ pulls the chosen price toward whatever keeps sell-through on schedule; a lower λ lets the engine chase pure revenue and risk finishing with excess stock or a stockout.
Exploitation means charging the price that the engine's current best model says maximizes the pacing-adjusted revenue score — it uses what has already been learned. Exploration means deliberately trying a different, nearby price even though the model does not currently believe it is optimal, purely to observe how demand responds there and refine the elasticity estimate. Too little exploration and the engine can get stuck near a locally decent price while missing a much better one elsewhere on the curve; too much exploration and it wastes days on poor prices. The exploration-rate slider directly controls how often a random probe price is used instead of the model's recommendation.
The simulator's true demand curve can call for, say, 220 units on a given day, but if only 40 units remain in stock, only 40 units are actually sold and observed. The engine's regression only ever sees sold units, not true unconstrained demand, so as inventory nears zero the observed demand systematically understates the real curve — a well-known bias in retail data called demand censoring. This is one reason real revenue-management systems try to stop discounting before inventory gets critically low, rather than reading zero sales as "no demand."
The overall shape — a hidden constant-elasticity curve, price experiments generating noisy sales data, an online regression recovering the curve, and a pacing constraint against a fixed horizon — mirrors airline and hotel revenue management, retail markdown optimization, and the "contextual pricing bandits" used by some e-commerce platforms. Real systems add far more (competitor prices, cross-item cannibalization, customer segments, richer exploration policies such as Thompson sampling), but the core loop of probe → estimate → optimize → pace is the same one used here.