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¶
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.
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.
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)
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.
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.
