Inspiration

A small shop has to pay for stock before it sells it. Order too little and the shelves are empty. Order too much and there is no cash left for rent and wages. The usual tools do not check the bank balance: a reorder-point rule buys whenever stock is low, and an open-to-buy budget caps spending but does not say which items deserve the money. We wanted a tool that answers one question: how much can I safely spend this week, and on what?

What it does

SafeToBuy gives a shop owner a weekly buying plan.

  1. It forecasts sales for every item as a range, not a single number.
  2. It plays out thousands of possible futures for the bank balance.
  3. It finds the largest budget \(B\) that keeps cash above a safety buffer in at least 9 out of 10 futures:

$$\max B \quad \text{such that} \quad P\left(\min_t \text{cash}_t \ge \text{buffer}\right) \ge 1 - \alpha, \quad \alpha = 0.10$$

  1. It spends that budget on the items that earn the most per dollar, and marks each item as buy in full, buy part, or wait.
  2. It explains the plan in plain English, and every number in the explanation is checked against the real calculation.

In our demo week the shop has $24,708 in the bank. Everything worth buying costs $33,463. SafeToBuy says $16,383 is safe to spend. The reorder-point rule would spend $20,796 with a 45% chance of running short.

How we built it

  • Data: real weekly sales and prices from the public M5 Walmart dataset (store CA_1, FOODS_3 department). Costs, bills and the bank balance are our assumptions, and all of them are written down in the repo.
  • Forecast: LightGBM quantile models with conformal calibration.
  • Cash model: a Monte Carlo simulation of the bank balance.
  • Decision: a cash gate that picks the budget, then a marginal-value allocator that spends it.
  • Explanations: Claude Haiku, with a guardrail that rejects any number not found in the plan.
  • App: Streamlit. Python, 146 automated tests.

The machine learning does the predicting. Simulation and optimization make the decision.

Challenges we ran into

  • The death spiral. Our first rule was "if no budget is safe, buy nothing". The shop then had nothing to sell, so the next week was even less safe. We changed it to "get as close to safe as possible".
  • Testing honestly. We tuned settings on two time windows and locked them before touching the two held-out windows.
  • A subtle ordering bug. Tiny rounding differences changed which items got bought first. We fixed the tie-breaking.

Accomplishments that we're proud of

On 156 held-out weeks per rule:

  • 27.9% fewer weeks short of cash than the reorder-point rule (62 vs 86).
  • 1.0% more profit than the open-to-buy rule.
  • A forecast error of 0.200 (weighted quantile loss) against 0.239 for a naive baseline.

It is not a clean sweep, and we say so. Open-to-buy had slightly fewer short weeks (58 vs 62), and our profit was 2.9% lower than the reorder-point rule. Every number in our README is generated from a saved run, not typed by hand.

What we learned

  • A good forecast is not a decision. Most of the value came from the cash check and the spending order.
  • Forecast ranges matter more than the single best guess when the question is about risk.
  • Reporting where you lose makes the wins more believable.

What's next for SafeToBuy

  • Connect to real shop data: point-of-sale exports and bank feeds.
  • Support supplier credit terms and bulk discounts.
  • Test on more stores and product types.
  • Autonomous purchasing of stock according to data

Built With

Share this project:

Updates

Submission history