Skip to content

Stockcast logo

Stockcast

Turn forecasts into inventory decisions you can simulate, inspect, and evaluate.

Get started Guide Examples

Stockcast is a Python library for the step that comes after forecasting. You bring a forecast from any model you like. Stockcast maps it into orders, simulates their execution against historical or simulated demand, and evaluates the resulting impact against business metrics such as cost, service, and waste. Happy with a policy? Put it into production with the same objects.

Inspired by PyTorch-style libraries, it is built from Lego-like parts that snap onto one engine. Each part is a class you can subclass and adjust. Swap the policy, the demand, the supplier, or the shelf-life rule, and everything else stays the same.

Read our philosophy: why Stockcast is built this way, and the research behind it.

How it works

How Stockcast works: your forecast feeds your policy; with your optional rules, demand and starting stock, Stockcast plays out each period and reports service, stock and cost. YOUR DATA YOUR CHOICES STOCKCAST YOU GET Forecastfrom any library Demandand starting stock Policywhen and how much to order Rules (optional)suppliers · packs · shelf life Plays outeach period1 deliveries arrive2 orders go out3 demand is met Service, stock, costand the event table

Two pipelines

Research: backtest and compare. For researchers and analysts who measure forecasts by the decisions they lead to. Compare policies, forecasting models, lead times, suppliers, and shelf-life rules on identical demand.

Comparing candidates: two candidates run on the same demand and starting stock; the results differ only because of the candidate. YOUR CANDIDATES STOCKCAST YOU COMPARE Candidate Aa forecast, policy or rule Candidate Banother forecast, policy or rule + as many as you like Same demand,same starting stockeach candidate, period by period A: 98% servedavg. 14 packs on the shelf B: 93% servedavg. 8 packs on the shelf

Compare scenarios

Production: run the chosen policy every period. For engineers who put the chosen policy behind a periodic job: load stock, refresh the forecast, compute orders with the supplier's rules, and save the state.

The production loop: the latest sales and deliveries update the stock; a fresh forecast and your policy give the orders to send; the next period it starts again. YOUR DATA Latest salesand deliveries STOCKCAST Update the stockon hand, on order YOUR DATA Fresh forecastfrom any library YOUR CHOICE Your policyand supplier rules YOU GET Orders to sendto your suppliers next period

From backtest to production

Example

import numpy as np
import pandas as pd

from stockcast.core import InventoryStateDataFrame, SimulationEngine
from stockcast.evaluation import InventoryEvaluator, avg_on_hand, fill_rate
from stockcast.policies import OrderUpToPolicy

sku, today = "tea_250g", pd.Timestamp("2026-02-01")

# Twelve weeks of daily tea sales, about six packs a day.
days = pd.date_range("2026-01-05", periods=84, freq="D")
sales = pd.DataFrame({
    "unique_id": sku,
    "date": days,
    "y": np.random.default_rng(3).poisson(6, len(days)),
})
past, future = sales[sales["date"] <= today], sales[sales["date"] > today]

# Forecast tomorrow from the last four weeks. Any model works; here, two
# common ways to state the uncertainty.
last_4_weeks = past["y"].tail(28)
forecast = pd.DataFrame({
    "unique_id": [sku],
    "date": [today + pd.Timedelta(days=1)],   # the day it forecasts
    "fh": [1],                                # one step ahead
    "mean": [last_4_weeks.mean()],            # a moving average ...
    "std": [last_4_weeks.std()],              # ... and its spread
    "q95": [last_4_weeks.quantile(0.95)],     # or a 95% quantile forecast
})

# Today's stock and the ordering policy.
shelf = InventoryStateDataFrame.from_observed(pd.DataFrame({
    "unique_id": [sku],
    "date": [today],     # the day the shelf was counted
    "on_hand": [30],     # packs on the shelf
}))
policy = OrderUpToPolicy(
    lead_time=0,             # delivered before the shop opens
    review_period=1,         # order every morning
    freq="D",                # one period is one day
    service_level=0.95,      # cover tomorrow's demand on 95% of days
    allow_backorders=False,  # a missed sale is lost
)

engine = SimulationEngine()

# From a mean and a spread, the policy computes the quantile...
policy.fit(forecast, mean_column="mean", std_column="std")
from_mean_std = engine.run(policy=policy, demand_source=future, inventory=shelf)

# ...or it takes a quantile forecast as it is.
policy.fit(forecast, target_column="q95")
from_quantile = engine.run(policy=policy, demand_source=future, inventory=shelf)

# Score the next eight weeks of each.
metrics = [fill_rate, avg_on_hand]
pd.concat({
    "mean + std": InventoryEvaluator().fit(from_mean_std).evaluate(metrics),
    "quantile": InventoryEvaluator().fit(from_quantile).evaluate(metrics),
}).droplevel(1).round(2)
            fill_rate  avg_on_hand
mean + std       0.99         5.30
quantile         0.99         5.69

The Quickstart walks through each of these lines.

Key features

  • Any forecasting model. Stockcast does not fit models; it takes quantiles, a mean and standard deviation, or sample paths from statsforecast, skforecast, smooth, Prophet, deep learning, or your own code. Connect any forecasting model.
  • Forecasts become decisions. Judge a forecast by the stock, missed sales, and cost it leads to, not only by its accuracy.
  • Small parts you combine. Policies, schedules, constraints, suppliers, callbacks, and shelf-life processes each do one job. Use the built-in ones or subclass a base class.
  • Every unit is accounted for. Each SKU and period is one row of the event table, and the engine checks that stock, backorders, and pipeline balance on every row.
  • Timing you can read. Receive, decide, then meet demand, in that order. Other conventions map onto it: work with any timing convention.

About

Stockcast is maintained by our team at the Predictive AI and Digital Shift (PADS) research group, VIVES University of Applied Sciences.

Read more

Citation

If you use Stockcast in your work, please cite the version you used. The repository's CITATION.cff has the details, and GitHub's Cite this repository button formats them:

Theodosiou, F. Stockcast: forecast-driven inventory decisions, simulation, and
evaluation in Python. Version 0.2.0. https://github.com/FilTheo/stockcast

Contributing

Contributions are welcome, from typo fixes to new building blocks. See the contributing guide and the release notes.

Getting help

Open an issue on GitHub for questions, ideas, and bugs. For a bug, include a small example and the run manifest (result.run_manifest), which records the versions and settings behind a result.

Stockcast is released under the Apache License 2.0.