Telegram alerts for trading bots
How to wire up a Telegram bot for trade alerts using the bot-monitor.js pattern -- bot token, chat_id, and simple POST to api.telegram.org.
Why Telegram
When a bot is running unattended overnight, you need instant notification when something goes wrong -- or right. Telegram is ideal because:
- The API is simple (single HTTP POST, no SDK needed).
- Messages arrive in under a second.
- Works on mobile, desktop, and web.
- The bot API is free with no rate limit for normal use.
Creating a bot
- Message
@BotFatheron Telegram. - Send
/newbot, follow the prompts, and note the bot token (format:123456789:ABCdef...). - Start a conversation with your new bot.
- Get your chat ID: send any message to the bot, then call
https://api.telegram.org/bot<TOKEN>/getUpdates. Thechat.idfield in the result is your numeric chat ID.
Store both values in secrets.json:
{
"telegramBotToken": "123456789:ABCdef...",
"telegramChatId": "-100123456789"
}The send function
async function sendTelegram(token, chatId, message) {
const url = `https://api.telegram.org/bot${token}/sendMessage`
const body = {
chat_id: chatId,
text: message,
parse_mode: 'HTML',
disable_web_page_preview: true,
}
const res = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
})
if (!res.ok) {
const err = await res.text()
console.error('Telegram send failed:', err)
}
}HTML formatting lets you bold key numbers and add line breaks cleanly.
The bot-monitor.js pattern
Our bots separate trade execution from alerting. The bot writes structured JSON lines to a log file; bot-monitor.js tails the log and sends Telegram messages when it sees certain patterns (BUY, WIN, LOSS, EXIT).
This decoupling means:
- The trading bot never blocks on a Telegram API call.
- You can restart the monitor without affecting trading.
- Multiple bots can be monitored by a single monitor process.
Log format written by bots:
function logTrade(event, data) {
const line = JSON.stringify({
ts: Date.now(),
event, // 'BUY' | 'WIN' | 'LOSS' | 'EXIT'
...data,
})
fs.appendFileSync(LOG_PATH, line + '\n')
}Monitor reads and tails:
const { Tail } = require('tail')
function startMonitor(logPath, telegramToken, chatId) {
const tail = new Tail(logPath)
tail.on('line', async (line) => {
try {
const event = JSON.parse(line)
const msg = formatAlert(event)
if (msg) await sendTelegram(telegramToken, chatId, msg)
} catch (_) {}
})
}
function formatAlert(event) {
if (event.event === 'BUY') {
return `<b>BUY</b> ${event.asset} ${event.shares} shares @ $${event.price.toFixed(2)}\nMarket: ${event.market}`
}
if (event.event === 'WIN') {
return `<b>WIN</b> +$${event.pnl.toFixed(2)} | ${event.asset}`
}
if (event.event === 'LOSS') {
return `<b>LOSS</b> -$${Math.abs(event.pnl).toFixed(2)} | ${event.asset}`
}
return null
}Direct alerts for polycopy
The polycopy bot skips the log-tail pattern and sends Telegram messages directly. When it copies a whale trade, it posts immediately:
async function alertCopiedTrade(token, chatId, whale, market, shares, price) {
const msg = [
`<b>COPY TRADE</b>`,
`Whale: <code>${whale.slice(0, 8)}...</code>`,
`Market: ${market}`,
`${shares} shares @ $${price.toFixed(2)}`,
].join('\n')
await sendTelegram(token, chatId, msg)
}Rate limiting
Telegram limits bots to 30 messages per second to the same chat, and 20 per minute to the same group. For a bot firing many trades quickly, batch alerts or add a minimum interval:
let lastAlertTs = 0
const MIN_ALERT_INTERVAL_MS = 1000
async function throttledAlert(token, chatId, msg) {
const now = Date.now()
if (now - lastAlertTs < MIN_ALERT_INTERVAL_MS) {
await sleep(MIN_ALERT_INTERVAL_MS - (now - lastAlertTs))
}
await sendTelegram(token, chatId, msg)
lastAlertTs = Date.now()
}Startup and shutdown notifications
Always send a startup message so you know when the bot (re)started, and a shutdown message on clean exit. This makes it easy to spot unexpected restarts in your Telegram history.
async function main() {
await sendTelegram(TOKEN, CHAT_ID, `<b>BOT STARTED</b> poly5m-v4 | ${new Date().toLocaleString('fr-FR', { timeZone: 'Europe/Paris' })}`)
process.on('SIGTERM', async () => {
await sendTelegram(TOKEN, CHAT_ID, '<b>BOT STOPPED</b> poly5m-v4 (SIGTERM)')
process.exit(0)
})
// ... bot loop
}Summary
- Create a bot via
@BotFather, store token and chat ID insecrets.json. - Use a single
sendTelegram(token, chatId, htmlMessage)function withparse_mode: 'HTML'. - Prefer the log-tail pattern for trading bots: decouple execution from alerting.
- Send startup and shutdown notifications to track unexpected restarts.
- Throttle to 1 message/second to stay within Telegram rate limits.
Related bots
poly5m-v4 — Split-window momentum BTC scalper
Buy-both-sides Gabagool on 5-min BTC. Picks up cheap YES + NO at $0.49 or less, locks profit when pair stays below $0.98. CLOB v2 / pUSD, polls books every 2s from 10s to 260s.
polycopy — Whale copy-trading bot
Mirrors trades from profitable Polymarket wallets within seconds. Per-whale WR gate ≥55% after 10 trades, 24h stale exit, $0.10 best-bid collapse exit. Adaptive 3s polling after whale activity.