The problem

Stocksholm helped clients pick stocks for their personal portfolios. Their strategy was based on momentum trading: each month it selected the 10 best stocks to invest in, and clients rebalanced accordingly. They asked for help evaluating that algorithm by backtesting it: replaying it against historical prices to see how it would have performed.

Why backtest at all?

A momentum strategy is a claim about the future: stocks that did well recently will keep doing well. You can’t test the future directly. Waiting years to find out with real money is slow and expensive, and you only get one try.

So the past is the only laboratory available. A backtest replays history and asks what would have happened if you had followed the strategy back then. That is far better than guessing, but it has a trap built in: the past already contains the answer. It is very easy, usually by accident, to let the test use information that would not have existed at the time. The result looks wonderful and means nothing. It is the same problem as data leakage in machine learning.

A good backtest is therefore not one that finds a great strategy. It is one that can’t fool you.

See it in action

Below is a small simulated market of 50 stocks over five years. By construction, no stock is better than any other, so no strategy can have a real edge. Each month the strategy buys the stocks with the best recent return, which is the same idea as momentum trading.

The two sliders set how many stocks the strategy holds and how many months of history it ranks them on. Start with Naive, then switch to Honest. The market, the strategy and the settings stay the same; the only difference is whether the test is allowed to peek.

The table shows the metrics the tool reports for a real portfolio. They are explained below.

What I built

A backtesting tool written in Python with FastAPI, containerized with Docker and deployed on Kubernetes. It takes the closing prices of a portfolio’s assets over time and returns the performance and risk metrics that matter when judging a strategy. It follows the rule the demo illustrates: a decision made on a given date may only use data from before that date.

Reading the results

Investors care about returns more than prices, so everything starts there. The daily return is

$$ r = \frac{V_n}{V_{n-1}} - 1 \approx \log\frac{V_n}{V_{n-1}} $$

where $V_n$ is the price on day $n$. Log returns are used for computational reasons, and they add up cleanly over time. From the returns the tool computes:

  • Mean return and volatility: the average return, and the time-normalized standard deviation $\sigma_T = \sqrt{T\sigma^2}$, which measures risk.
  • Maximum drawdown: the largest drop from a peak to a later valley, $MD = \dfrac{\text{valley} - \text{peak}}{\text{peak}}$, which shows downside risk.
  • Sharpe ratio: return per unit of volatility, $SR = \dfrac{R - r_f}{\sigma_T}$, where $r_f$ is the risk-free rate. Higher is better. It depends on the period and the risk-free rate, and it treats upside and downside volatility alike.
  • Calmar ratio: the same idea with maximum drawdown in the denominator, $CR = \dfrac{R - r_f}{MD}$. It reacts to sudden drops, so Sharpe and Calmar are best read together.
  • Positive and negative months and the win/loss ratio: how often the strategy is up versus down.