A multi-tenant Telegram bot: anyone can message it, follow Hyperliquid wallets, and get a
DM whenever a wallet they follow changes a perp position over the public trades firehose —
distinguishing a brand-new trade from an increase, and reporting reduces/closes with realized PnL.
- No auth, no scraping. Uses only Hyperliquid's sanctioned public API
(
wss://api.hyperliquid.xyz/ws+POST /info). See docs/hyperliquid-api-map.md. - Scales to 1k+ wallets on one connection — the
tradesfeed carries both counterparties, so one market-data subscription serves every subscriber by filtering. - Multi-tenant. Each subscriber keeps their own labelled watchlist; a wallet's activity fans out to every subscriber following it, in their own chat with their own label.
- Stores nothing but the watchlists. Positions live in memory and are rebuilt from the chain
(
clearinghouseState) on every start; the SQLitetracker.dbholds only(chat_id, address, label).
Design + rationale: docs/DESIGN.md.
trades firehose ─► resolve_deltas (users:[buyer,seller] filter) ─► apply_fill state machine
└─► open/add/reduce/close ─► Telegram push
clearinghouseState ─► silent seed (cold-start correctness) + leverage ┘
The cold-start guarantee: before a wallet is admitted to the live filter, its current on-chain positions are seeded silently, so an add on a position opened before the tracker started is correctly reported as "Added to position", never a false "Started trade".
🟢 Started trade Whale-1: BTC Long 2.5 @ 63120 (10x)
➕ Added to position Whale-1: BTC Long +1 (~$63,120.00) @ 63120 (10x)
➖ Reduced Whale-1: BTC Long -0.5 @ 64000 | realized +$440.00 | 2 left
🔴 Closed Whale-1: BTC Long 2 @ 64500 | realized +$2,760.00
One credential: a Telegram bot token. It cannot be generated by code — Telegram issues it via @BotFather:
- Open Telegram, message @BotFather, send
/newbot. - Choose a display name, then a username ending in
bot. - BotFather replies with a token like
123456789:AA...— copy it.
Put it in a .env at the repo root (loaded via load_dotenv()), or export it:
# .env
TELEGRAM_BOT_TOKEN=123456789:AA...Verify the token works (and optionally see chat ids that have messaged the bot):
uv run hl-tracker-telegram-setup # reads TELEGRAM_BOT_TOKEN from .envThat's it — there is no chat id to configure. This is a public bot: each subscriber's chat is captured automatically when they message it. (On-chain data needs no key — Hyperliquid's public API is unauthenticated.)
uv sync --extra telegram # install (omit --extra telegram for log-only mode)
uv run hl-tracker # start the botThen, in Telegram, anyone can DM the bot and manage their own watchlist:
/add 0x6bea…597f Whale-1 follow a wallet (labelled)
/remove 0x6bea…597f stop following
/rename 0x6bea…597f Whale relabel
/list show the wallets you follow
/positions live open positions of a wallet you follow (tap to pick one)
| Variable | Default | Meaning |
|---|---|---|
TELEGRAM_BOT_TOKEN |
— | Bot token from @BotFather; without it, notifications are logged only |
TRACKER_ALLOWED_CHAT_IDS |
(open to all) | Comma-separated chat-id allowlist to make the bot private |
TRACKER_NOTIFY_REDUCE_CLOSE |
true |
Notify on reduce/close (false = open+add only) |
TRACKER_RECONCILE_INTERVAL_S |
45 |
Leverage/drift reconcile cadence (0 disables) |
TRACKER_RECONCILE_BATCH |
20 |
Wallets re-seeded per reconcile cycle |
TRACKER_SEED_CONCURRENCY |
8 |
Concurrency of the startup seed sweep |
TRACKER_LIVE_COINS |
(all perps) | Comma-separated coins to restrict the feed |
TRACKER_DB_PATH |
tracker.db |
SQLite watchlist path (repo root) |
uv run ruff check . && uv run ruff format --check .
uv run ty check
uv run pytest