# Terminal events for Hummingbot This script reads your Terminal alerts and publishes each one to your Hummingbot MQTT broker. Your bot's own logic decides what to do with an event. This script only sends the event. It does not place an order, and it does not call a trading API. ## Install Python 3.10 or newer. A live run needs the MQTT client: ```sh pip install paho-mqtt ``` A dry run does not import that package. If it is missing when you publish for real, the script says to install it and stops. ## Configure Read every secret from the environment. The script does not write the API key, a broker password, or either value into the cursor file, the log, or the URL. | Variable | Meaning | Default | | --- | --- | --- | | `TERMINAL_API_KEY` | Your Terminal API key. Every key can read events. | Required for a live run | | `TERMINAL_API_URL` | Origin of the Terminal site. The script calls `GET /v1/events`. | `https://terminal.tokensmarketcap.com` | | `TERMINAL_START` | Where to begin when the cursor file is empty: `latest` (alerts from now on) or `earliest` (alerts kept from the last 7 days). | `latest` | | `TERMINAL_CURSOR_FILE` | File that stores the feed cursor. | `~/.local/share/terminal/hummingbot-cursor` | | `MQTT_HOST` | Broker hostname. | `localhost` | | `MQTT_PORT` | Broker port. | `1883` | | `MQTT_TOPIC` | Topic your bot reads. | `hbot/{instance_id}/external/event/terminal` | | `MQTT_USERNAME` | Broker user, when the broker asks for one. | Empty | | `MQTT_PASSWORD` | Broker password, when the broker asks for one. | Empty | A `TERMINAL_API_URL` that already ends in `/v1` or `/v1/events` works too. Replace `{instance_id}` with the `instance_id` in the bot's `conf_client.yml`. A live run stops while `MQTT_TOPIC` still contains `{instance_id}`. Do not put `+` or `#` in the topic. Those are for subscribers. ## What Hummingbot listens on Read on 2026-10-13. - [Bot orchestration](https://hummingbot.org/installation/broker/) (page dated September 22, 2026) describes the MQTT bridge and the `mqtt_external_events` switch. It does not name the topic. - The client source that day, [hummingbot/remote_iface/mqtt.py](https://github.com/hummingbot/hummingbot/blob/master/hummingbot/remote_iface/mqtt.py), subscribes to `{namespace}/{instance_id}/external/event/#`. The namespace, host, and port defaults are in [client_config_map.py](https://github.com/hummingbot/hummingbot/blob/master/hummingbot/client/config/client_config_map.py): namespace `hbot`, host `localhost`, port `1883`. `mqtt_external_events` defaults to on. `mqtt_autostart` defaults to off, so start the bridge in the client (or turn autostart on) before you expect events to arrive. - [scripts/external_events_example.py](https://github.com/hummingbot/hummingbot/blob/master/scripts/external_events_example.py) comments the topic as `hbot/{id}/external/events/*`. That comment does not match the subscription in `mqtt.py`, which uses `external/event` (singular). This script follows `mqtt.py`. The topic stays configurable. The last segment of the default topic is `terminal`. That is the event name Hummingbot derives from the topic. The published payload is the Terminal event JSON, compact, with the same fields the feed returned. This script does not wrap it and does not add an order. Hummingbot's external-event listener rebuilds a message that keeps `timestamp`, `sequence`, `type`, and `data`, and drops other fields. A script that needs the whole event should listen with `ExternalTopicFactory`, which receives the raw JSON. `ExternalEventFactory` does not. Create a key from the [developer pages](https://terminal.tokensmarketcap.com/developers). The feed shape is `GET /v1/events` in the [API reference](https://terminal.tokensmarketcap.com/developers/openapi.json). The API terms are a draft under review and are not published yet. ## Run ```sh export TERMINAL_API_KEY="your API key" export MQTT_TOPIC="hbot/your-instance-id/external/event/terminal" python3 terminal_bridge.py ``` The script asks `GET /v1/events` and leaves the request open for up to 25 seconds when no alert is ready (a long-poll). When the answer says more events are ready, it asks again at once. It stores `next_cursor` and sends that cursor on the next request, including after a restart. On HTTP 429 it waits the `Retry-After` seconds (at least 1, at most 3600), then asks again. A 5xx answer, a lost connection or a cut-off answer waits 5 seconds, then 10, 20, 40 and 60 while the trouble lasts, or the `Retry-After` seconds when they are longer. The log names only the kind of error, never the request. An empty answer that comes back at once waits 1 second before the next ask. It does not follow redirects. It stops on 401 or 403, and before the first request when `TERMINAL_API_KEY` has a space or a line break in it. An event id already published in this run is dropped. The script remembers the last 10,000 ids. The cursor file is updated only after every event in that answer has been accepted by the broker. While the broker refuses, the script keeps that answer and publishes it again after 5, 10, 20, 40 and then 60 seconds. It does not ask the feed again meanwhile, because an answer with events counts as an API call. The broker publish uses QoS 1, so the script waits for the broker to accept the message before it stores the cursor. The bot's own subscription is QoS 0, and it still receives the message. ## Dry run Example. These are not live prices. ```sh python3 terminal_bridge.py --dry-run fixtures/events.jsonl ``` Each line of that file is one events-feed answer. The script prints each event it would publish, one JSON object per line. It does not open a network connection and it does not load `paho-mqtt`. A repeated event id is dropped. The cursor file is set to the last `next_cursor` in the file. Pass `--cursor-file` to choose the file. The numbers in the fixture are the documented example alert (`alert_9001`), plus a second example id so a duplicate can be shown. They are not live prices. ## Cursor file The file holds one line: the opaque `next_cursor` from the feed, which starts with `c1_`. It does not hold the API key. A file that holds anything else stops the script before the first request, so another file passed by mistake never reaches a URL. Delete it to start again from `TERMINAL_START`. ## Licence MIT. Copyright (c) 2026 Virtus Blockchain Labs. See the LICENSE file in the parent directory. Terminal reports market events for conditions you set. It does not tell you to buy, sell, or hold, and it does not place trades.