Every few months someone sends me a backtest with an equity curve that goes up and to the right at an angle you only see in fiction, and when I ask where the candles came from, the answer is a CSV downloaded once, from somewhere, and never inspected again. The strategy logic got weeks of attention. The data got none. That ordering is backwards, because free crypto OHLCV data is genuinely usable, but every free source has its own specific defects, and if you do not know them you can end up optimizing a strategy against artifacts that never traded anywhere.
So here is the map I wish I had earlier: where the free candles actually live, what tends to be wrong with each source, and the five minutes of checking that catches most of it before it costs you anything.
Where the free candles actually live
Exchange REST endpoints are the natural starting point. Binance's klines endpoint is the workhorse of the entire hobbyist backtesting world: free, no API key needed for market data, every interval from one minute to one month, roughly a thousand candles per request. Paginate backwards and you can pull years of minute bars in an afternoon. Coinbase and Kraken expose similar endpoints, with one famous Kraken gotcha: its OHLC endpoint only serves roughly the most recent 720 candles per interval. Ask it for a year of hourly data and you get about a month, with no error and no warning, which has quietly truncated more datasets than I can count.
Then there are the public dumps. Binance publishes flat files of klines, trades, and aggregated trades for essentially every pair it lists, as daily and monthly archives anyone can download. Kraken posts downloadable CSVs of its full OHLCV history, refreshed every quarter or so. For anything bulky, dumps beat REST pagination. There are no rate limits to fight, no pagination logic to get subtly wrong, and the file either downloads completely or it does not.
Finally the aggregators, CoinGecko, CryptoCompare, and their cousins. One request, one symbol, and you get price history spanning the whole market, including coins that died years ago, which no single exchange can give you. The convenience is real. So are the defects, and they are different from the exchange-side ones, so they deserve their own section.
The three defects that actually bite
Missing candles come first. Most exchanges simply do not emit a bar for an interval in which nothing traded, and they emit nothing for the hours they were down for maintenance or the occasional outage. On BTC this almost never matters. On the four hundredth alt at one-minute resolution, gaps are everywhere. Your backtesting framework will respond in one of three ways: crash, silently forward-fill, or misalign. Misalignment is the dangerous one. Any indicator computed on bar position instead of timestamp shifts by however many bars are missing, and your signals start firing against the wrong candles without a single error being raised.
Zero-volume placeholder bars are the mirror image. Some aggregators, rather than leaving a gap, insert a synthetic bar with volume of zero and open, high, low, and close all pinned to the previous close. It plots beautifully. It also teaches your mean-reversion strategy that flat bars are reliably followed by a jump back to the real price, which is an artifact, and it quietly poisons anything that keys off volume, from VWAP to simple liquidity filters. Long runs of identical, volumeless bars are the signature to look for.
Silently changed tickers are the expensive one. Tokens rebrand, the MATIC to POL migration being the best-known example. Projects redenominate so that one old unit becomes a thousand new ones. Exchanges occasionally recycle a ticker for a completely different asset. An aggregator stitching feeds together across one of these events produces either a price series with a 10x cliff in the middle, which at least you can see, or a smooth series that switched which asset it describes partway through, which you cannot. Exchange data has its own version of this: a pair gets delisted and relisted months later, and the same symbol has different tick sizes and a completely different liquidity profile on either side of the gap.
There is also a layer of quieter quirks worth knowing about. Daily candles cut at different times on different sources, so a daily series from one feed will not match a daily series from another and neither is wrong. Volume arrives in base units from one source and quote units from another. And BTC-USDT is a different series from BTC-USD, which mostly does not matter, until a stablecoin wobbles and it suddenly matters a great deal.
The five-minute validation routine
Before any dataset touches a backtest I run the same short routine. It is a few lines of pandas, and I mean five minutes literally.
- Parse and sort the timestamps, then check for duplicates. Duplicated timestamps usually mean a bad join between two separate pulls.
- Compute how many bars the date range should contain at your interval and compare with what you have. If the count is short, list the gaps and look at where they cluster. A handful around known maintenance windows is normal. Thousands scattered randomly means the pull itself is broken.
- Count flat bars, meaning open, high, low, and close all identical, and count zero-volume bars. A few are legitimate on illiquid pairs. Long runs of them, priced exactly at the previous close, are synthetic fill.
- Sanity-check the geometry. High should be at least the larger of open and close, low at most the smaller, volume never negative. Violations are rare, and when they appear they usually mean mislabeled columns rather than exotic market conditions.
- Find the largest single-bar return in the series. A big candle on a volatile alt can be real. Anything that looks like a clean 10x or 1000x step is almost certainly a ticker switch or a redenomination rather than a market move.
- Cross-check one random week against a second source or the exchange's own chart. Two honest sources will differ a little in the wicks. Two sources that diverge for whole stretches mean one of them changed feeds somewhere, and you want to know which one you are holding.
If a dataset passes all six, it can still be wrong, but it is no longer wrong in any of the ways that are cheap to detect, and in practice that removes most of the disasters.
What I actually use
My shortlist is boring on purpose. For anything listed on a major exchange, I take the exchange's own data, dumps for the bulk history and the REST endpoint to top up the recent edge, and I store the raw files untouched next to the cleaned ones. Aggregators I use only for coins whose home exchange offers no usable history, and I tag those series as lower confidence in my own metadata, so that a suspicious backtest result gets checked against its data source before anything else. We run a version of these six checks automatically on everything that enters Blockcircle's backtesting engine, and the share of freely downloaded datasets that trip at least one of them genuinely surprised me when we first measured it.
Keep the raw files forever, by the way. The most painful failure mode I know is discovering a bug in your cleaning script and having no way to recover what the source originally said. Disk is cheap, and candles, once gone from an endpoint, are annoying to re-pull.
None of this is glamorous work, but the five minutes of checks costs less than one evening spent debugging a strategy whose only real edge was a data defect wearing a good equity curve. Run the checks before you run the backtest.