# Custom signal — Tickerbot Custom signal development

Build guide from https://tickerbot.io/docs/build/custom-signal/ · all guides: https://tickerbot.io/docs/build.md

Tickerbot is the stock market, in SQL. A custom signal is a named SQL expression on it, usable anywhere a built-in is.

Chart-platform indicators (Pine Script, ThinkScript) are invisible to everything else you build. A custom signal lives in the API: define it once as a SQL predicate and the name works everywhere the built-in signals do.

## 1. Define it

A boolean SQL predicate over the 421+ built-in columns — and over other custom signals you own, so indicators compose.

```shell
curl -X POST "https://api.tickerbot.io/v2/signals" \
  -H "Authorization: Bearer YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "oversold_quality",
        "expr": "rsi_14 < 30 AND above_sma_200 AND pe_ratio < 20",
        "description": "Oversold pullback in a profitable uptrend" }'
```

Response:

```json
{
  "as_of": "2026-08-21T11:01:52Z",
  "signal": {
    "name": "oversold_quality",
    "kind": "custom",
    "description": "Oversold pullback in a profitable uptrend",
    "expr": "rsi_14 < 30 AND above_sma_200 AND pe_ratio < 20",
    …
  }
}
```

## 2. Use it like a built-in

Screen the whole market for it.

```shell
curl -X POST "https://api.tickerbot.io/v2/scan" \
  -H "Authorization: Bearer YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "q": "oversold_quality AND market_cap > 1e9" }'
```

Response:

```json
{
  "as_of": "2026-08-21T11:01:57Z",
  "count": 2,
  "results": [
    { "ticker": "GTX", "name": "Garrett Motion Inc. Common Stock",
      "price": 26.48, "day_change_pct": 0.0028, "market_cap": 5063296190, … },
    { "ticker": "DVA", "name": "DaVita Inc.",
      "price": 175.55, "day_change_pct": 0.0017, "market_cap": 11309826000, … }
  ]
}
```

## 3. Ask for its history

Custom signals mix into /v2/series; transitions_only returns just the rows where the indicator flipped — its full on/off history, as if it had always existed.

```shell
curl "https://api.tickerbot.io/v2/series?tickers=DVA,GTX&columns=close,oversold_quality&interval=1d&from=2024-01-01&transitions_only=true" \
  -H "Authorization: Bearer YOUR_KEY"
```

Response:

```json
{
  "as_of": "2026-08-21T11:02:00Z",
  "interval": "1d",
  "tickers": ["DVA", "GTX"],
  "columns": ["close", "oversold_quality"],
  "count": 2,
  "series": {
    "DVA": [ { "t": "2026-08-05", "close": 188.69, "oversold_quality": true,
               "transitions": { "oversold_quality": "enter" } } ],
    "GTX": [ { "t": "2026-08-20", "close": 26.39, "oversold_quality": true,
               "transitions": { "oversold_quality": "enter" } } ]
  },
  …
}
```

DVA entered on 2026-08-05 — before this signal was defined. The same retroactivity applies to as-of reads: define it today, query its value at any past moment.

## 4. Wire it to a push

Because it's a signal, it subscribes like one.

```shell
curl -X POST "https://api.tickerbot.io/v2/scan/subscribe" \
  -H "Authorization: Bearer YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "q": "oversold_quality AND market_cap > 1e9",
        "target_url": "https://your-app.example.com/hook" }'
```

Response:

```json
{
  "id": "wh_q-s2lOSjLTM",
  "q": "(rsi_14 < 30 AND above_sma_200 AND pe_ratio < 20) AND market_cap > 1e9",
  "channel": "webhook",
  "target_url": "https://your-app.example.com/hook",
  "signing_secret": "whsec_…",
  "status": "active",
  …
}
```

The subscription stores the expanded predicate — the custom name compiles into its SQL at create time.

## The calls behind it

- `POST /v2/signals` — Create the indicator: name + SQL predicate; composes with other customs (https://tickerbot.io/docs/endpoints/signals/custom)
- `POST /v2/scan` — Screen on it across the whole market, mixed with any built-in (https://tickerbot.io/docs/endpoints/scan/live)
- `GET /v2/series?transitions_only=true` — Its flip history: every on/off edge on an aligned grid (https://tickerbot.io/docs/endpoints/series/get)
- `POST /v2/scan/subscribe` — The indicator as a push: fires when a ticker starts matching (https://tickerbot.io/docs/endpoints/scan/subscribe)
