case studies

Market Data Case Study: Four Million Trades Turned Into Candles, Checked After a Pulled Plug

A stock chart is made of candles: for each minute, the first price, the highest, the lowest and the last, with the volume traded. A candle is a window summary, the same kind of summary Precomputing keeps for API latency, only in a field every investor knows. In the Engine demo a trading day of stock trades goes through the Engine, which keeps 1-second, 1-minute and 1-hour candles and a quote board ready in its SQLite file, and writes the file five times a second.

The run covers one simulated trading day, 28 September 2026 from 09:30 to 16:00 New York time, for eight invented symbols. News lifts SIM4 by 8% at 11:02:17, SIM8 is halted at noon and reopens 3.5% lower, and SIM6 drops 6% at 14:31:05. At 13:15 the demo throws the Engine away in the middle of writing its file.

The trading day for SIM4 in 1-minute candles, from 09:30 to 16:00 New York time, with volume below. The price trades near 23.1 until 11:02:17, jumps 8% in one trade, and trades between 24.8 and 26 for the rest of the day. The jump was caught as an unusual step and kept whole. A line at 13:15 marks the pulled plug; the candles on both sides were checked against a recount.

SIM4’s day as the Engine’s file holds it: 390 one-minute candles, read with SQL.

The Set-Up

Market data
Market Eight invented symbols, SIM1 to SIM8, busy at the open and the close and calm at lunch; 4,048,210 trades in the day
Kept Every trade whole for five minutes; candles at 1 second for an hour, 1 minute for 90 days and 1 hour for good
Ready answers A quote board of eight precomputes: last price, the day’s open, high, low, volume, turnover and trades per symbol, and a total
Unusual trades Each trade judged by its step from the previous trade of the same symbol; far outside the usual steps, it is kept whole
Runtime The Engine, compiled to WebAssembly, writing into SQLite 3.53.4’s WebAssembly build five times a second

Every candle comes from the same summary columns. Open is price_first, high price_max, low price_min, close price_last, volume size_sum, and VWAP is notional_sum / size_sum, where the policy derives notional = price * size for each trade.

What Happened

  • 09:30. The open, the busiest stretch of the day. The Engine takes in each trade, updates its candles in memory and writes what changed to the file five times a second.
  • 11:02:17. SIM4 jumps 8% in one trade, from about 23.15 to 25.02. The Engine keeps that trade whole with a z-score of 239, and judges the trades after it from the new price, so none of them is flagged.
  • 12:00 to 12:10. SIM8 is halted. It reopens 3.5% lower, and the first trade after the halt is caught the same way.
  • 13:15. The plug. The Engine is thrown away in the middle of a checkpoint, with every trade since the last one in memory. SQLite rolls the half-written checkpoint back. A fresh Engine opens the file in well under a second, reads where the feed stands, and the feed resends every trade after that. The candles are checked right away and match the recount.
  • 14:31:05. SIM6 drops 6%. Caught, kept whole, z-score −610.
  • 16:00. The close. The day ends with every closed candle and the whole quote board equal to a recount of every trade.

How many trades the plug throws away depends on the moment: a pull at 13:15 typically catches tens of thousands in memory and a checkpoint of about ten thousand rows half written. None of them is lost, because none had been acknowledged, and the feed still had them.

What the File Can Answer

The quote board at the close, read from the precompute views:

symbol  last    open    high    low     volume     trades
SIM1    185.69  187.40  188.57  183.59  296729493  914944
SIM2    64.32   64.26   64.78   63.27   251147498  777593
SIM3    408.44  412.77  414.92  403.06  200335637  617625
SIM4    25.61   23.11   25.96   22.88   174335302  537394
SIM5    99.69   98.61   99.80   97.02   140549448  434536
SIM6    138.08  145.29  146.32  135.77  114578542  353743
SIM7    31.32   31.76   32.04   31.03    81017889  252087
SIM8    52.10   52.90   53.84   50.60    51858071  160288

SIM4 around its jump, in 1-minute candles with their VWAP:

sqlite> SELECT time(w - 14400, 'unixepoch') AS minute,
   ...>   printf('%.2f', price_first) AS open, printf('%.2f', price_max) AS high,
   ...>   printf('%.2f', price_min) AS low, printf('%.2f', price_last) AS close,
   ...>   CAST(size_sum AS INTEGER) AS volume, printf('%.2f', notional_sum / size_sum) AS vwap
   ...> FROM trades_win WHERE res = 60 AND symbol = 'SIM4' AND w BETWEEN 1790607660 AND 1790607780;
minute    open   high   low    close  volume   vwap
11:01:00  23.12  23.17  23.12  23.15   350961  23.15
11:02:00  23.15  25.04  23.14  24.99   788771  24.82
11:03:00  25.00  25.01  24.91  24.94  1056240  24.96

And the three price jumps of the day, kept whole with their z-scores:

time      symbol  price   z
11:02:17  SIM4     25.02   239
12:10:00  SIM8     51.03  -231
14:31:05  SIM6    136.48  -610

The Numbers

Over one trading day Result
Trades 4,048,210
Candles checked against a recount in the browser 27,150 at 1 second, 1 minute and 1 hour: 0 differences
The quote board Identical to the recount
The Engine’s file at the close About 10 MB, against an estimated 115 MB for a plain table of every trade, measured on the first 100,000 trades and scaled to the day
The Engine in the browser 170,000 to 220,000 trades a second in Chromium, writing the file five times a second
The Engine against the compiled triggers, first 200,332 trades, both in WebAssembly 12 to 15 times faster; the two files identical
The native Engine, whole day, full sync every 10,000 trades 12 to 16 seconds in our runs, 258,000 to 337,000 trades a second, every closed candle identical
The crash lab: native Engine killed 100 times while it takes in the day 0 acknowledged trades lost; final file identical to an uninterrupted run

Browser figures from a headless run of the demo’s own code and from Chromium, on a two-core cloud server (Intel Xeon at 2.8 GHz); native figures from the command-line Engine and the crash lab on the same server.

What the Demo Revealed

A price jump is a hard case for an anomaly rule. Judged by level, every trade after the jump sits far from the old baseline, so a rule would flag hundreds of ordinary trades until the baseline caught up. The policy language gained change for this: the baseline learns the usual steps between trades, and only the step itself is unusual. In the demo each of the three jumps is flagged exactly once.

The plug also showed why sequence numbers belong in the file. The Engine records the last trade the file holds in the same transaction as the candles, so a crash can never leave the two out of step. Without that, a resend after a crash would count some trades twice.

Next: On Real Traffic

The Engine reads events from standard input, from files or over HTTP, so a pilot can feed it from an existing market data handler or any event stream that needs answers faster than SQL triggers give them. The open questions are memory over long runs with many keys, and speeds on named hardware other than one cloud server.

Try It Yourself

Open the Engine demo, press Play and pull the plug around the open, when the Engine holds the most trades in memory. Then pause and run the race against the compiled SQL. At the end, every closed candle is checked against a recount, and the file is yours to query or download.