RESEARCH

Loading a day of tick data: 73.8s to 0.9s

Study details

Measured
2026-07-28 recording
Instruments
222 US equity symbols, 1.59 GB SQLite recording
Method
load the same recorded session through the SQLite reader and through a columnar binary format, then compare wall-clock time and verify every cell is bit-identical
Result
loading fell from 73.8s to 0.9s with every compared cell bit-identical and the same trade list
Contents
A backtest that takes over a minute to load a single day is not a backtest you will run twice. You end up testing fewer ideas, which is the opposite of the point. We profiled where the time went and found it was not the strategy engine.

1. Where the time actually went

Loading one recorded session took 73.8s. The engine itself ran in a couple of seconds. Almost all of the wall clock was spent pulling rows out of SQLite and turning each stored value into a number, one value at a time, across hundreds of millions of values. That is a storage format problem, not an algorithm problem. Row-oriented storage with per-value parsing is a poor fit for something that reads whole columns.

2. What we changed

We write each recorded session a second time in a columnar binary layout: fixed-width float64 values, one block per column, with a checksum and a header describing the schema. Loading becomes a read into memory rather than a parse.
PathTime
SQLite load73.8s
Binary load0.9s
That is 81x faster on the same data.

3. Proving it did not change anything

Speed is only useful if the numbers are identical. Two checks had to pass before we would use it: - Every cell compared bit for bit: 641,261,891 values, all identical. - The same strategy run over both formats produced the same 11,494 trades — same times, prices, quantities and P&L. Not "close enough". Bit-identical, because a float that differs in the last place can move a value across a decision boundary and change a trade.

4. What it costs

The binary file is larger than the compressed SQLite original, because raw float64 does not pack as tightly as SQLite's integer encoding. We accepted that: disk is cheaper than the time you lose waiting. For transfer we compress it, which recovers most of the difference. Conclusion Before optimising a backtest engine, measure where the time goes. Ours was almost entirely in reading data, and the fix was a storage format rather than faster code. Whatever you change, verify bit-identity before you trust the faster path.

Limitations

  • This is one recorded session of 222 US equity symbols. Load times scale with the number of symbols, columns and rows, so the ratio on your data will differ.
  • Measured on a local NVMe disk. On slower storage the gap narrows, because the binary path becomes disk-bound rather than parse-bound.
  • The comparison is our SQLite reader against our binary reader. A different SQLite access pattern could be faster than ours was.
  • Bit-identity was verified for this session and this schema. It is a property we test on every build, not a proof for all inputs.
  • Server-side benchmarks are not included here; those numbers have not been measured yet.

Related reading

← All research

Originally published by TraderWe on August 11, 2026. You may quote and link to this page. Republishing the full text without a link back to the original is not permitted.

4 replies

I
IndicatorSkeptic· Aug 2026 ago
The unglamorous truth that most "my backtest is slow" problems are parsing, not math. Though now that you can run it 80x more, my only worry is you'll find 80x more curve-fit edges.
D
DrawdownDave· Aug 2026 ago
Honestly my bottleneck was never the loader, it was me re-running the same broken idea until it looked good once. Faster iteration would have just let me overfit at speed, so I'd say pair this with a rule about how many runs you're allowed before you stop and think.
N
NightOwl_Yuki· Aug 2026 ago
nice, though writing every session out twice must eat disk pretty fast - do old recordings get pruned or is that on us?
GrandpaGrizzly· Aug 2026 ago· edited Aug 2026 ago
Back in the day we'd kick off a run before dinner and read the output in the morning, and let me tell you, waiting overnight made you awfully choosy about which idea was worth the wait. Nothing wrong with fast, just don't let cheap runs turn into careless ones — the machine will happily hand you a hundred pretty equity curves before lunch. Bit-identical check is the part I'd brag about, not the seconds.
Sign in to reply →