← back
04Cash Operations · Python + ML

CashCast

Every bank branch is guessing how much cash it needs next week. Most guess high — because running out is worse than wasting. CashCast stops the guessing.

Python 3.12FastAPIscikit-learnRidge RegressionIsolation ForestPlotly.jsSQLAlchemySQLitepytest

// the problem

“A branch manager orders cash based on last week and a gut feeling. She always adds 20% extra — because running dry is a customer service disaster. That extra 20% sits in a vault earning nothing.”

The US has 72,000 bank branches and 500,000 ATMs. Each one needs cash restocked regularly — and each one over-orders. The Fed estimates $4.2 billion in idle vault cash industry-wide. With interest rates elevated through 2025-2026, that cash has a real opportunity cost: money sitting in a vault at 5.5% annual rate is expensive to hold.

The reason banks over-order is simple: there's no system to predict demand accurately at the branch level. Cash demand isn't random — it spikes on paydays, falls on cold rainy days, surges before holidays, and follows a clear weekly pattern. All of that is in the transaction history. CashCast reads it.

problem → numbers

Idle vault cash (US industry)$4.2B/yr
Average branch over-order buffer15–20%
Fed funds rate (2025–2026)≥5.5%
CashCast target reduction15%

// how it works

1. Feature engineering

17 features extracted from date + rolling history: cyclic sine/cosine encoding for day-of-week, day-of-month, and month (so Monday-to-Sunday wraps correctly for the model). Lag features at 7 and 14 days. Rolling mean and volatility over 7 and 30 days. Binary flags for Fridays, paydays (1st and 15th), and pre-payday days.

2. Per-branch Ridge regression

Each branch gets its own model trained on 730 days of history (80/20 train/test split). Ridge regression handles the multicollinearity between lag features well and is fast to train — each branch model fits in under 200ms. MAPE is evaluated on the holdout set and surfaced in the dashboard confidence score.

3. Isolation Forest anomaly detection

After training, the model predicts on the full historical set and passes residuals (actual minus predicted) to Isolation Forest. Days where the model's prediction was far off — unusual spikes or drops — get flagged. These appear as anomaly markers on the dashboard and in the order recommendation table.

4. Forecast + order recommendation

14-day rolling forecast with confidence bands (±10-22% based on branch volatility). Recommended order = upper bound × 1.10, rounded to nearest $1,000. This replaces the flat 20% manual buffer with a data-driven one that changes every day.

// ML pipeline per branch

730 Daystransaction history17 Featurescyclic + lag + rollRidge (α=10)train 80%MAPEtest 20%Residualsactual - predictedIsolation Forestcontamination=4%Flag Anomalydates14-Day Forecast+ confidence bandOrder Rec.upper × 1.10 → $1kDashboardPlotly.js charts// narrative: "BRK-001: Next-week demand +18% above 90d median. Peak Mar 20 at $52,400."

forecast accuracy — BRK-001 (14d holdout)

MAPE

8.4%

Confidence

91.6%

Anomalies

4

Idle saved

$2.1K/wk

// what operators actually see

// ops dashboard

Branch Intelligence Dashboard

Plotly.js + FastAPI — branch health cards, 14-day forecast with confidence bands, per-branch order recommendations, anomaly flags, AI narrative

○ CashCastBranch Intelligence Dashboardlocalhost:8001

Branches

6

Avg MAPE

9.1%

Total Rec

$867K

Horizon

14d

Anomalies

2

High Risk

1

// 14-day demand forecast — BRK-01 Downtown (with confidence band)

$200K$150K$100K$50KMar 9Mar 15forecast

// per-branch order recs

BRK-01
$148K
BRK-02
$93K
BRK-03
$112K
BRK-04
$67K
BRK-05
$204K
BRK-06
$89K

// AI narrative — BRK-01

“14-day demand +18% above 90d median. Peak Thu Mar-19 at $52K. 1 anomaly flagged Mar-11.”

// branch health overview

BRK-01

$312K

healthy

BRK-02

$198K

healthy

BRK-03

$87K

low

BRK-04

$445K

healthy

BRK-05

$52K

risk

BRK-06

$231K

healthy