Skip to content
Backtesting

Replay the bars you ship.

History and real time come back from one endpoint, so nothing about your test path is retrofitted.

The run

Run a rule on the bars.

Fills, realized and open — off one response, at whatever speed you read it.

Return

Unavailable

no response, so nothing to describe

Realized

Unavailable

no response, so nothing to describe

Unrealized

Unavailable

no response, so nothing to describe

Position

Unavailable

no response, so nothing to describe

The read did not land. Nothing is drawn from a response that did not arrive.

GET /v1/prices/ohlcv?asset=EUR&interval=1d&from=2026-09-09T00:00:00.000Z&to=2026-11-08T00:00:00.000Z&limit=60

One response. The cursor is an index into it, not a second call.

Rule
breakout · 4-bucket channel · one unit · long only · filled at the close · no fees or slippage
The build

Page the window, then replay.

BUILD · THE REPLAY
let from = windowStart
while (from < windowEnd) {
  const { data } = await ohlcv('EUR', { interval: '1d', from })
  if (data.length === 0) break
  for (const bar of data) strategy.onBar(bar)
  // to is exclusive, so the next page opens on the next bucket
  from = nextBucket(data[data.length - 1].timestamp)
}

One request per page, ordered by construction, and the same four prices the live screens draw.

  • A gap is an absence.

    A bucket nothing was published for is missing from the response, not carried forward and not zeroed.

  • Null is not zero.

    volume is null when no size was published — and on a coarse bucket rather than a partial sum of the minutes that did.

  • The universe stays yours.

    Survivorship, corporate actions and which instruments you were allowed to hold that day are your harness’s — this contract ends at the bar.