Unit Testing Quant Research Code
Writing small, automated tests that check individual pieces of research code against known correct answers — catching silent bugs in a backtest engine or signal calculation before they quietly produce a wrong, but plausible-looking, result.
Research code has a dangerous property that most other software doesn't: a bug in it usually doesn't crash. A backtest engine with an off-by-one error in how it aligns signals to returns doesn't throw an exception — it just quietly uses tomorrow's return where it should have used today's, produces a Sharpe ratio, and moves on, looking exactly like a working backtest that happens to have found a good strategy. The bug is invisible unless someone independently verifies the calculation, which is exactly the kind of check that's easy to skip when the output already looks plausible and the deadline is real.
What a unit test actually does
A unit test checks a single, small piece of code — one function, one calculation — against an input where the correct output is known in advance, usually because it was worked out by hand or comes from a trusted reference source. If a function computes a Sharpe ratio, a unit test feeds it a small, hand-calculated series of returns and checks that the function returns the exact number that hand calculation produces. If a function is supposed to shift a signal forward by one day to avoid look-ahead bias, a test feeds it a tiny synthetic series and checks the shift landed on the correct date, including at the edges of the series where off-by-one errors love to hide. These tests run automatically, in seconds, every time the code changes, so a bug introduced by an edit gets caught immediately rather than surfacing weeks later as an unexplained shift in backtest results.
A concrete case
A quant refactors a backtest engine's execution-cost model to make it faster, and all the existing strategy backtests still run without errors and produce numbers in a broadly similar range — nothing looks obviously broken. But a unit test that checks the cost model against a hand-computed example — a single trade of a known size at a known spread should cost exactly this many basis points — starts failing, revealing that the refactor introduced a subtle sign error that was silently halving transaction costs across every strategy. Without the test, this would likely have gone unnoticed until live trading costs came in roughly double what the backtests had predicted.
What this means in practice
The parts of a research pipeline most worth unit testing are exactly the parts where a silent error is both easy to make and hard to notice by eye: date alignment, return calculations, position sizing arithmetic, and anything involving off-by-one indexing. Unit tests won't catch a strategy that's a bad idea, but they reliably catch the much more common failure mode of a good idea implemented with a small, invisible bug.
Unit tests check individual pieces of research code against known correct answers, catching silent calculation bugs — like off-by-one signal misalignment — that produce plausible-looking but wrong results, which are otherwise very hard to detect by inspection alone.
Related concepts
Practice in interviews
Further reading
- Beck, Test-Driven Development: By Example