Build a backtester
The hard part of a backtester was never the loop; it's the data honesty. ?asof= reruns any query against the market as it was — delisted names still in it — so the loop is the only part you write.
The recipe
1. Pick candidates without look-ahead
An as-of scan evaluates your entry condition with only what was knowable at that moment.
curl -s -X POST "https://api.tickerbot.io/v2/scan" \
-H "Authorization: Bearer $TICKERBOT_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "q": "rsi_14 < 30 AND above_sma_200 AND market_cap > 1e9",
"asof": "2024-01-05" }'Delisted names keep their rows and bar history — ask about SIVB or LEH and you get records, not a 404 — so match sets are not conditioned on survival.
2. Walk the dates
The backtest loop is the same call in a for-loop: one as-of scan per rebalance date.
for (const date of rebalanceDates) { // e.g. every Monday, 2020 → today
const res = await fetch('https://api.tickerbot.io/v2/scan', {
method: 'POST',
headers: { Authorization: `Bearer ${KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ q: ENTRY_CONDITION, asof: date }),
})
const { results } = await res.json()
positions = strategy.rebalance(positions, results, date) // your rules
}3. Price the trades
Fills and the equity curve come from /v2/series: up to 50 tickers × 25 columns on one aligned time grid.
curl -s "https://api.tickerbot.io/v2/series?tickers=AAPL,MSFT,RIOT\
&columns=close,volume_today&interval=1d&from=2024-01-01&to=2024-06-30" \
-H "Authorization: Bearer $TICKERBOT_API_KEY"
# One shared grid: each row is a date, every ticker's close aligned.4. Take it live
The exact q the backtest validated becomes the live subscription — no rewrite between research and production.
curl -s -X POST https://api.tickerbot.io/v2/scan/subscribe \
-H "Authorization: Bearer $TICKERBOT_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "q": "rsi_14 < 30 AND above_sma_200 AND market_cap > 1e9",
"target_url": "https://your-bot.example.com/hook" }'Endpoints used
| Endpoint | Role in this build |
|---|---|
POST /v2/scan + asof | The candidate set at any past moment: the backtest’s selection side |
GET /v2/series | Aligned history, 50 tickers × 25 columns: fills and the equity curve |
GET /v2/tickers/{ticker}/bars/{interval} | OHLCV bars down to 1s: intraday fill detail |
POST /v2/scan/subscribe | The validated condition, running live: same q |