Build a trading algorithm
An algorithm is a condition and a loop. The condition side is one computed SQL table — every ticker × every signal — queryable in three tenses. Your strategy, your broker; the data layer is done.
The recipe
1. Define the entry condition
A SQL WHERE clause over 421+ precomputed columns: the whole market evaluated in one call, right now.
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" }'2. Validate it historically
The same query with ?asof= reruns it against the market as it was — delisted tickers included, unlimited depth. Walk it across dates for a candidate history.
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" }'The full walk-through is the backtester guide: candidate sets per date, trades priced from aligned series.
3. Run it live
Subscribe the same query as a webhook: a ticker entering your condition is your signal to decide; your handler routes any order to your broker.
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" }'4. Write the algorithm
The payload's matches are tickers that just entered the condition; current_matches is everything matching now — entries and exits from one delivery. (Payload lists cap at 100 rows; confirm any single position with GET /v2/tickers/{ticker}.)
// POST from Tickerbot whenever the match set changes:
// { "event": "webhook.fired",
// "q": "rsi_14 < 30 AND above_sma_200 AND market_cap > 1e9",
// "as_of": "2026-08-14T15:05:00Z",
// "matches": [ { "ticker": "RIOT", "rsi_14": 27.4, ... } ],
// "current_matches": [ /* every ticker matching right now */ ] }
app.post('/hook', async (req, res) => {
const { matches, current_matches } = req.body
const matching = new Set(current_matches.map((r) => r.ticker))
// ENTRIES — tickers that just entered the condition.
for (const row of matches) {
if (!portfolio.has(row.ticker) && passesRisk(row)) {
await broker.buy(row.ticker, positionSize(row)) // your broker's API
}
}
// EXITS — held positions whose entry condition no longer holds.
for (const pos of portfolio.positions()) {
if (!matching.has(pos.ticker) && exitRules(pos)) {
await broker.sell(pos.ticker, pos.qty)
}
}
res.sendStatus(200)
})Endpoints used
| Endpoint | Role in this build |
|---|---|
POST /v2/scan | The condition, evaluated across the whole market: live or ?asof= |
POST /v2/scan/subscribe | The same condition as a push: fires on match-set changes |
GET /v2/tickers/{ticker} | Everything about one ticker in one row: position context |
GET /v2/series | Aligned time series, up to 50 tickers × 25 columns |