# Terminal alerts for Freqtrade A Python helper a Freqtrade strategy can import. It reads your recent Terminal alerts and keeps them by coin. Your strategy decides what to do with them. This helper does not place an order. Python 3.10 or newer. The helper uses the standard library only. You do not install a package for it. Freqtrade is your own install. ## Install Copy `terminal_feed.py` and `example_strategy.py` into your Freqtrade `user_data/strategies/` folder. Freqtrade loads the strategy by its class name. ```sh export TERMINAL_API_KEY="the API key from Settings" freqtrade trade --strategy TerminalAlertsStrategy ``` Create an API key in Settings. The developers page is [https://terminal.tokensmarketcap.com/developers](https://terminal.tokensmarketcap.com/developers). Every key can read the events feed. The helper starts in `bot_start`, and only when Freqtrade is in live or dry-run mode. A backtest does not call the API, and the informational columns stay empty there. The helper does not invent past alerts. ## Environment variables | Name | Required | Meaning | | --- | --- | --- | | `TERMINAL_API_KEY` | yes, for live reading | Your API key. The helper sends it only as `Authorization: Bearer`. | | `TERMINAL_API_URL` | no | The site origin. Defaults to `https://terminal.tokensmarketcap.com`. The helper requests `/v1/events`. A value that already ends in `/v1` or `/v1/events` works too. | | `TERMINAL_CURSOR_PATH` | no | File for the saved cursor. Defaults to `terminal-events.cursor` in the current directory when the feed is running. A dry run writes a cursor file only when this variable is set. | The API key is not written into a URL, a query string, or a log line. Do not put the key in `TERMINAL_API_URL`. The helper does not follow a redirect, so the key stays on the host you set. A key with a space or a line break in it (a copy that picked up a line end) is refused before any request. ## What the helper does A background thread requests `GET /v1/events?wait=25`. With no saved cursor, the first request sends `start=latest`, so you get alerts recorded from then on. Each answer includes `next_cursor`. The helper stores that cursor and sends it on the next request. Do not commit that file. Delete it to start again from the newest alert. The helper drops an event whose `id` it has already seen. It keeps the last 50 events for each `asset.symbol`, in memory. After a restart it reads on from the saved cursor, so alerts it had already read before the restart are not shown again, and `recent()` starts empty. A cursor file it cannot read is reported in the log, and the feed then starts after the newest alert. `recent(symbol, minutes)` returns the kept events for that coin whose `fired_at` is within the last `minutes` minutes, oldest first. The match ignores letter case. `symbol_from_pair` turns a Freqtrade pair into that symbol: `SOL/USDT` and `SOL/USDT:USDT` both become `SOL`. The symbol has to match `asset.symbol` on the alert. When the answer says `has_more`, the helper asks again at once. When an answer comes back at once with no new alert, the helper waits one second before asking again. A normal answer stays open for up to 25 seconds, and that wait needs no extra pause. `gap` means an alert after your cursor is older than 7 days and is no longer in the feed. The helper logs the gap. Read `GET /v1/rules/{id}/record` for a rule you still need. The helper does not call that route for you. A lost connection delays an alert. The next request uses the saved cursor. A `429` answer includes `Retry-After` as a whole number of seconds. The helper waits that long. It treats a value below 1 as 1, and a value above 120 as 120. When an error has no `Retry-After`, the helper waits 1 second, then 2, 4, 8, 16, 32, and then 60. A successful answer starts that count over. The helper stops, and says why in the log, when asking again cannot help: a `401` or `403` (the key was refused or lacks the `read` scope), a `400` about the cursor (delete the cursor file, then start again), or another `400` or `404` (check `TERMINAL_API_URL`). The helper keeps one request open. Terminal allows two open event requests per API key. ## Add your own logic `populate_indicators` writes two informational columns. Only the latest row carries the current alerts. Older rows stay at 0 and blank, because the number is the alerts in memory now, not a value from that candle's own time. - `terminal_alert_count`: how many alerts for that coin fired in the last `terminal_recent_minutes` (60, until you change it) - `terminal_alert_headline`: the headline of the latest of those alerts `populate_entry_trend` and `populate_exit_trend` leave the entry and exit columns at 0, next to the comment `# your own conditions here`. Write your conditions there. Terminal does not choose an entry or an exit for you. The file sets `timeframe`, `minimal_roi`, and `stoploss` because Freqtrade requires them before it will load a strategy. Terminal does not choose them for you: `minimal_roi` is an empty map, which leaves that exit off, and `stoploss` is `-1.0`, a 100% stop, so it does not act. Replace each value with your own. The entry and exit columns stay 0, so the strategy does not open or close a trade until you write a condition. `bot_loop_start` runs once per loop. The example does not request the API from that callback. The feed thread is already reading. The example starts the feed with `shared_feed()`, which keeps one feed per Freqtrade process. When `/reload_config` builds the strategy again, the new strategy gets the running feed instead of a second one. The feed's lines go to Freqtrade's log. A `TerminalFeed` you make yourself prints them to standard error unless you pass `log=`. ## Freqtrade callbacks Read on 2026-10-13: - Strategy callbacks, including `bot_start` and `bot_loop_start`: [https://www.freqtrade.io/en/stable/strategy-callbacks/](https://www.freqtrade.io/en/stable/strategy-callbacks/) - `populate_indicators`, and the entry and exit methods: [https://www.freqtrade.io/en/stable/strategy-customization/](https://www.freqtrade.io/en/stable/strategy-customization/) `bot_start` runs once when the strategy loads, after the data provider and wallet are set. The Freqtrade docs show a remote read there for live and dry-run. `bot_loop_start` runs once at the start of every loop: about every 5 seconds in dry-run and live, unless you configured a different throttle, or once per candle in a backtest. The docs describe it as the place for work that is not tied to one pair, including loading outside data. `populate_indicators` fills indicator columns on the candle table. In a backtest, Freqtrade calls it once for the whole table. The example reads `TerminalFeed.recent()` there. ## Replay a recorded file Example. These are not live prices. ```sh python3 terminal_feed.py --dry-run fixtures/events.jsonl ``` This reads the file. It does not call the API and it does not need an API key. `fixtures/events.jsonl` holds sample feed answers built from the developer documentation's example alert (`terminal.alert.v1`, id `alert_9001`). In the feed, `sequence` is null. The webhook copy of that example numbers `sequence`. The feed does not. The Bitcoin row uses the example's Bitcoin price, the example headline for a price above that level, and the documentation's re-arm formula. Example. These are not live prices. ## Licence MIT. Copyright (c) 2026 Virtus Blockchain Labs. See [../LICENSE](../LICENSE). Terminal reports market events for conditions you set. It does not tell you to buy, sell, or hold, and it does not place trades.