Quant Memo
Core

Model Monitoring in Production

A model that scored well in backtest can still fail quietly once it is live, because the world it sees starts to differ from the world it was trained on. Monitoring is the discipline of catching that drift before the P&L does.

Prerequisites: Training Error vs Generalization Error, Cross-Validation for Time Series

A model that passed every backtest can still lose money the day after it goes live, and the scary part is that nothing about the model changed. What changed is the world feeding it data. A volatility regime shifts, a new exchange fee schedule alters order flow, a data vendor silently reformats a field. The model keeps making confident predictions on inputs it was never trained to see, and because there is no automatic alarm, the first sign of trouble is often a drawdown a risk manager notices weeks later. Monitoring exists to shrink that gap between "the model is wrong" and "someone finds out."

The analogy: gauges on a dashboard, not a single warning light

A pilot does not fly by watching one dial. Airspeed, altitude, fuel, engine temperature — each tells a different story, and a problem can show up in any one of them while the others still look fine. A single "everything is OK" light would be useless, because by the time it turns red the plane has usually already stalled.

Production monitoring is the same set of gauges applied to a model. You watch the inputs (are the features still shaped like the ones the model trained on?), the outputs (are the predictions still distributed the way they used to be?), and — once you finally have them — the labels (was the model actually right?). No single number is "the" health check. A model can have perfectly normal-looking inputs and still be wrong, and it can have drifting inputs and still be fine. You need several gauges because failure shows up in different places at different times.

Formalizing input drift: the Population Stability Index

The most common way to ask "does this feature still look like it did in training?" is the Population Stability Index, PSI. Split a feature's values into bins (say, deciles from the training set), record what fraction of training data fell in each bin — call that the expected proportion, EiE_i — and what fraction of live data currently falls in the same bins — the actual proportion, AiA_i. Then

PSI=i(AiEi)ln ⁣(AiEi)\text{PSI} = \sum_i (A_i - E_i)\, \ln\!\left(\frac{A_i}{E_i}\right)

In words: for every bin, take the difference between how much data is there now versus in training, multiply by the logarithm of their ratio, and add all the bins up. Each term is zero only when a bin's live share exactly matches its training share; it grows whenever a bin has either gained or lost a lot of traffic. The log makes the penalty symmetric — moving from 10% to 20% of the data is penalized about as much as moving from 20% to 10%. Common rule of thumb: PSI below 0.1 is negligible drift, 0.1–0.25 is worth watching, above 0.25 means the feature's population has meaningfully shifted and any model trained on the old population is now extrapolating.

Worked example 1: computing PSI by hand

A strategy uses "days since the stock last had an earnings surprise" as a feature, bucketed into three bins. In training, the split was 50% / 30% / 20% across bins A, B, C. This week's live data shows 35% / 40% / 25%.

Bin A: (0.350.50)ln(0.35/0.50)=(0.15)(0.357)=0.0535Bin B: (0.400.30)ln(0.40/0.30)=(0.10)(0.288)=0.0288Bin C: (0.250.20)ln(0.25/0.20)=(0.05)(0.223)=0.0112\begin{aligned} \text{Bin A: } &(0.35 - 0.50)\ln(0.35/0.50) = (-0.15)(-0.357) = 0.0535 \\ \text{Bin B: } &(0.40 - 0.30)\ln(0.40/0.30) = (0.10)(0.288) = 0.0288 \\ \text{Bin C: } &(0.25 - 0.20)\ln(0.25/0.20) = (0.05)(0.223) = 0.0112 \end{aligned} PSI=0.0535+0.0288+0.0112=0.093\text{PSI} = 0.0535 + 0.0288 + 0.0112 = 0.093

Under 0.1 — this is normal week-to-week wobble, not a regime change. If Bin A had instead dropped to 10% (a sudden pile-up of stale earnings dates), the first term alone would jump to (0.40)ln(0.10/0.50)=(0.40)(1.609)=0.644(-0.40)\ln(0.10/0.50) = (-0.40)(-1.609) = 0.644, blowing well past the 0.25 alarm threshold on its own.

Bin A Bin B Bin C 50% 35% 30% 40% 20% 25% training (expected) live (actual)
Dark bars are the training-set proportions per bin, accent bars are this week's live proportions. PSI sums up how far each accent bar has wandered from its dark neighbor.

Worked example 2: a control chart on performance

Feature drift only warns you that something changed upstream; a control chart on the loss itself watches the model's actual behavior. Suppose backtesting established a baseline daily log-loss of mean μ=0.42\mu = 0.42 with standard deviation σ=0.03\sigma = 0.03. Seven live days come in: 0.41, 0.44, 0.40, 0.47, 0.52, 0.55, 0.60.

Convert each to a z-score, z=(xμ)/σz = (x - \mu)/\sigma:

z5=0.520.420.03=3.33,z7=0.600.420.03=6.00z_5 = \frac{0.52 - 0.42}{0.03} = 3.33, \qquad z_7 = \frac{0.60 - 0.42}{0.03} = 6.00

Day 5 already crosses the conventional 3-sigma alarm line — under a stable model, a daily log-loss that far from the mean should happen by chance roughly one day in a thousand, so seeing it means the model's error distribution has actually moved, not just wobbled. By day 7 the loss is six standard deviations out, which is not statistical noise under any reasonable model of the baseline; something in the pipeline broke or the market regime genuinely shifted.

Convergence explorer
true meansamples →
after n = 200estimate -0.025error 0.025std error 0.071

Drag the sample size in the explorer above and notice how a running average that looks stable can still swing outside a tight band early on — the same reasoning applies to a rolling performance metric: a short window looks noisy even when nothing is wrong, so alarm thresholds must account for how many observations went into each point, exactly the way the 3-sigma line above assumed a known baseline standard deviation.

Monitoring has three layers — input drift, output drift, and (once available) label-based performance drift — because a model can fail through any one of them without the others moving. Watching only the metric you already report in a slide deck misses the earlier warnings.

What this means in practice

In finance, the hardest part of monitoring is that true labels often arrive late. A model predicting 20-day forward returns cannot be scored on today's prediction until 20 days from now, so a live performance chart is always looking at stale information. This is why input and output drift monitors matter so much: PSI on features and a distributional check on the prediction scores themselves (is the model suddenly predicting far more "buy" signals than usual?) are the only signals available in real time, while the label-based control chart above catches up later and confirms or denies what the earlier signals suggested.

A second practical point: monitoring must be segmented, not just aggregated. A model can look fine on average while quietly failing on one sector or one volatility regime, because a large stable segment can mathematically absorb a smaller broken one in a blended metric. Production monitoring dashboards should slice PSI and rolling loss by the subgroups a desk actually cares about, not just report one firm-wide number.

Practice

  1. A feature had training proportions 40% / 35% / 25% across three bins and live proportions 40% / 20% / 40%. Compute the PSI and say whether it clears the 0.25 alarm threshold.
  2. A model's baseline accuracy has mean 0.58 and standard deviation 0.02. A live week shows accuracy 0.55. Is that one observation, on its own, enough to declare drift? What additional information would you need before deciding?
  3. Explain in one sentence why a model can pass every input-drift check and still be losing money.

The classic mistake is treating a clean input-drift report as proof the model is fine. PSI only checks that the distribution of features hasn't moved — it says nothing about whether the relationship between features and outcome has changed. A model can see perfectly familiar inputs and still be dead wrong if the market's response to those inputs has shifted; that is concept drift, not input drift, and it is invisible to PSI. The second common mistake is reacting to a single noisy day on a control chart as if it were a confirmed regime break — always ask how many standard deviations of history the alarm threshold was calibrated on before trusting one point that crosses it.

Related concepts

Practice in interviews

Further reading

  • Breck et al., The ML Test Score: A Rubric for ML Production Readiness (2017)
  • Sculley et al., Hidden Technical Debt in Machine Learning Systems (2015)
ShareTwitterLinkedIn