Skip to content

1,300+ strategies entered the lab. Fewer than 50 survived.

Five classic technical strategies and every possible combination of them, evaluated across 48 assets — crypto, ETFs, US stocks, Latin American ADRs and currencies — with fees, slippage and no look-ahead. Every variant trains on 70% of history and is judged on the 30% it never saw. This is not a trading course: it is an honest measurement of how much technical analysis survives contact with reality.

data: own pipeline (API → PostgreSQL → dbt → backtester) · automatic daily refresh · open source

backtest explorer

loading pipeline data…

The rules that make these numbers credible

A backtest without these rules is marketing. Each one exists because its absence inflates results — and several were learned by finding real bugs, documented in the repository.

no look-ahead

A signal computed at day t's close executes at day t+1's open. No trade ever uses information that did not yet exist — the classic error that inflates backtests.

real costs

10 bps commission per side + 5 bps adverse slippage on every fill. The #1 reason strategies that look "perfect" on paper lose real money.

70/30 validation

Every variant trains on 70% of history and is judged on the remaining 30%, which never influenced its selection. With 1,300+ variants, skipping the blind window would be data dredging.

symmetric warm-up

Indicators need history before they can speak. The 70/30 split is taken after that warm-up, so both windows compare equivalent regimes.

winning requires trading

A combination that never enters the market returns 0% and would "beat" a falling market. It does not count: beating buy & hold requires having traded.

auditable data

More than 58,000 candles from Tiingo, Tiingo FX, Coinbase and Kraken in a PostgreSQL medallion warehouse, 89 dbt data-quality tests, 171 Python unit tests and cross-source reconciliation. Everything reproducible from the repo.

The 89 tests, one by one

What gets checked before a single figure is published

This is the complete list, counted against dbt's compiled manifest. When one fails the pipeline stops, and the page keeps yesterday's data instead of publishing something broken.

47
not_null
No column that feeds a calculation may arrive empty. This is the test that caught the Kraken defect, when 100% of one source was landing as NULL.
21
accepted_values
A category field only accepts values from the catalogue. A misspelled asset class stops being new data and becomes an error.
7
unique_combination
The same candle cannot exist twice for one asset on one date. That is what makes re-ingestion harmless.
6
custom SQL
Rules no generic test covers: that excess return reconciles with its components, or that a combination which never traded cannot count as a winner.
4
relationships
Every symbol in a result must exist in the asset catalogue. An orphaned asset fails instead of vanishing.
3
unique
Primary keys are unique in fact, not by convention.
1
ohlc_consistency
A day's high cannot sit below its low, nor the open outside the range. It catches a corrupt feed before any metric does.

On top of these, 171 Python unit tests cover the backtesting engine, the strategies and each API client.