Backtest a strategy on historical candles
Historical candles are the input to any backtest. Predictefy labels every candle with where it came from and how good it is, and a backtest that ignores those labels will produce confident numbers from data that cannot support them.
Request
Section titled “Request”Candles key on an outcome, not a market — a binary market has one series per side. Identifiers covers why.
curl -s "$PREDICTEFY_API_URL/api/polymarket/fetchOHLCV?outcomeId=OUTCOME_ID&resolution=1h&start=2026-01-01T00:00:00Z&end=2026-06-30T00:00:00Z&limit=5000" \ -H "Authorization: Bearer pk_live_YOUR_KEY"| Parameter | Detail |
|---|---|
outcomeId |
The series. id is a compatibility alias; marketId also accepted |
resolution |
1s 5s 10s 30s 1m 5m 15m 30m 1h 4h 6h 1d |
start / end |
ISO timestamp or epoch milliseconds |
limit |
1–5000 |
5m, 15m, 30m, 4h and 6h are aggregated at query time from stored history rather
than being stored natively. That is not a defect, but it does mean those buckets inherit the
quality of whatever they were built from — which the response tells you.
The candle record
Section titled “The candle record”{ "timestamp": 1767225600000, "open": 0.41, "high": 0.44, "low": 0.4, "close": 0.43, "volume": 128400, "source": "official", "sourceType": "true-candle", "quality": "ok", "isTrueCandle": true}timestamp, open, high, low and close are always present. Everything else is optional,
and the optional fields are the ones that decide whether a backtest is meaningful.
source — where the series came from: official, onchain, write-forward, derived.
sourceType — how the bucket was built:
| Value | Meaning |
|---|---|
true-candle |
The venue published this candle |
point-derived |
Built from point-in-time prices |
trade-derived |
Built from the trades tape |
rest-derived |
A coarse REST trade-tape candle |
book-derived |
Built from order-book state |
rollup |
Aggregated from finer buckets |
quality — ok, partial, suspect, or mixed. mixed means the bucket aggregates
inputs of differing quality, which is the expected value for a query-time aggregation.
isTrueCandle — the single boolean that separates published candles from reconstructed
ones.
Filter before you backtest
Section titled “Filter before you backtest”function usable(candle) { // A backtest that mixes published candles with book-derived reconstructions is // measuring two different things and reporting one number. if (candle.quality === 'suspect') return false; if (candle.sourceType === 'book-derived') return false; return true;}
const candles = body.data.filter(usable);const coverage = candles.length / body.data.length;if (coverage < 0.95) { throw new Error(`only ${(coverage * 100).toFixed(1)}% of buckets are usable — widen the window or drop the venue`);}Decide the rule up front and record it with the result. “Backtested on 1h candles, excluding
suspect and book-derived buckets, 98.2% coverage” is a claim someone can check. A bare Sharpe
ratio is not.
volume is nullable. A null is “not reported”, not zero — a volume filter that treats null as
zero silently discards every venue that does not publish it.
What history you can actually read
Section titled “What history you can actually read”Two limits apply, and they are different:
- Venue coverage. Not every venue has history for every resolution. Historical data records what exists, including which venues have sub-minute data and in what id format.
- Plan window. Your plan caps how far back you may read. Requesting beyond it returns
PLAN_REQUIREDrather than a silently truncated series — see Credits & billing.
Check meta.provenance on the response: venue-native means every returned bucket came from
the venue, predictefy-store means our own store served it, and merged means both. A backtest
that spans a provenance change is comparing two datasets.
History reads are priced above catalog reads, and a backtest is many of them — one per outcome per window. Pull once and cache locally; re-running a strategy should not re-read the API. Current weights are in Credits & billing.
Related
Section titled “Related”- Historical data — coverage per venue and resolution
- Identifiers — why candles key on
outcomeId - Capability-honest data — reading the honesty fields generally