Telegram
Overview
The Tradeboard Telegram Bot provides a convenient interface to your trading account through Telegram. It gives you read access to orders, trades, positions, holdings, funds, P&L, quotes and charts, and it also exposes a small set of remote actions: closing all positions, stopping running Python strategies, and switching the instance between Live and Analyze mode. Order alerts are pushed to you automatically when orders flow through the Tradeboard API.
Features
- Account Linking: Securely link your Tradeboard account using an API key and host URL
- Real-time Data Access: View orderbook, tradebook, positions, holdings, and funds
- P&L Tracking: Monitor realized and unrealized profit/loss
- Quote Information: Get real-time quotes for any symbol
- Chart Generation: Generate intraday and daily candlestick charts with volume
- Remote Actions: Close all positions, stop running Python strategies, toggle Live/Analyze mode
- Automatic Order Alerts: Every order, basket, split, options and GTT event pushed to your chat
- Interactive Menu: Inline button interface for quick access
- Programmatic Sends:
POST /api/v1/telegram/notifyandclient.telegram(...)in the Python SDK
Setup
1. Create Your Telegram Bot
- Open Telegram and search for @BotFather
- Send the
/newbotcommand - Follow the instructions to name your bot and choose its username
- Copy the bot token provided by BotFather
- Use this token in the Tradeboard configuration below
2. Enable the Telegram Bot in Tradeboard
- Log in to Tradeboard. From the profile dropdown (top right) click Telegram Bot, or navigate to
/telegram - Click Configuration to open
/telegram/config - Paste the bot token into the Bot Token field
- Optionally adjust Broadcast Messages and Rate Limit (messages per minute), then click Save Configuration
- Return to
/telegramand click Start Bot
The status badge on /telegram flips to Online once polling starts. If the bot was running when the server was last shut down, it auto-starts on the next boot, so you normally only press Start Bot once.
3. Link Your Account
Start a conversation with your bot on Telegram and send
/startSend the
/linkcommand with your API key and host URL:/link your_api_key_here http://127.0.0.1:5000The bot validates the credentials by calling
fundsagainst that host. On success it stores the encrypted key, records your Tradeboard username and broker, and confirms that the account is linked
Both arguments are required. /link with anything other than exactly two arguments returns a usage message.
Available Commands
Account Management
/start- Initialize the bot and see the welcome message/link <api_key> <host_url>- Link your Tradeboard account/unlink- Unlink your account and delete the stored credentials/status- Check connection status, host URL and link date
Trading Data
/orderbook- View orders (first 10 shown)/tradebook- View executed trades (first 10 shown)/positions- View open positions (first 10 shown)/holdings- View holdings (first 10 shown)/funds- View available cash, collateral, utilized margin and total/pnl- View realized, unrealized and total P&L
Amounts are printed with the currency symbol that matches the broker recorded when you linked: $ for crypto brokers (currently Delta Exchange), otherwise the rupee symbol.
Market Data
/quote <symbol> [exchange]- Get quote for a symbol. Exchange defaults toNSE- Example:
/quote RELIANCE - Example:
/quote NIFTY NSE_INDEX - Returns LTP, change, change percent, open, high, low, previous close and volume
- Example:
Charts
/chart <symbol> [exchange] [type] [interval] [days]- Generate price charts- Exchange: defaults to
NSE - Type:
intraday(default),daily, orboth - Interval: any interval the history API accepts. The bot's own help lists
1m,5m,15m,30m,1handD - Days: lookback period. Defaults to 5 for intraday and 252 for daily
- Examples:
/chart RELIANCE- 5-minute intraday chart over 5 days/chart RELIANCE NSE intraday 15m 10- 15-minute chart for 10 days/chart RELIANCE NSE daily D 100- Daily chart for 100 days/chart RELIANCE NSE both- Intraday and daily charts sent together as a media group
- Exchange: defaults to
Remote Actions
These commands change state on the Tradeboard instance. None of them act on the command alone: each replies with inline buttons, and nothing happens until you press one.
/closeall- Close all open positions. Offers Yes, close all, Close all + Stop strategies, and Cancel. The second option closes every position and then stops every running Python strategy/stoppython- List running Python strategies as buttons. Pick one to stop it, or Stop All to stop every running strategy. Each choice is confirmed before it runs. If nothing is running the bot says so and stops there/mode- Show whether the instance is in Live Mode or Analyze Mode, with a single button to switch to the other. The change is applied server-side and pushed to the web UI over SocketIO
Interactive Interface
/menu- Display the inline button menu. Buttons: Orderbook, Tradebook, Positions, Holdings, Funds, P&L, and Refresh. The Refresh button edits the same message in place and stamps it with the update time/help- Show the help message with all commands
The P&L button and the /pnl command read the same fields from the funds response, so the two always agree.
Order Alerts (Automatic Notifications)
Overview
The bot automatically sends real-time notifications for order-related API activity. No additional commands are needed: alerts are sent when orders are placed through the Tradeboard API. Delivery goes over a direct HTTPS call to the Telegram Bot API rather than through the polling bot, so alerts do not depend on the polling loop being mid-cycle. They do depend on the bot being started: if the bot is stopped from /telegram, automatic alerts stop with it.
Supported Order Types
Alerts are driven by the internal event bus. The events that produce a Telegram message are:
| Event topic | Trigger |
|---|---|
order.placed | placeorder or placesmartorder succeeded |
order.no_action | Smart order evaluated and found nothing to do |
order.modified | modifyorder succeeded |
order.cancelled | cancelorder succeeded |
orders.all_cancelled | cancelallorder succeeded |
position.closed | closeposition succeeded |
basket.completed | All legs of a basketorder completed |
split.completed | All sub-orders of a splitorder completed |
options.completed | All legs of an optionsorder completed |
multiorder.completed | All legs of an optionsmultiorder completed |
gtt.placed | placegttorder succeeded |
gtt.modified | modifygttorder succeeded |
gtt.cancelled | cancelgttorder succeeded |
gtt.triggered | A resting GTT fired and placed its order |
gtt.expired | A GTT lapsed past its expires_at without firing |
Failure events (order.failed, order.modify_failed, order.cancel_failed, gtt.failed, gtt.modify_failed, gtt.cancel_failed, analyzer.error) deliberately do not send a Telegram message, so a run of validation rejections cannot flood your chat.
gtt.placed, gtt.modified and gtt.cancelled fire in both Live and Analyze mode. gtt.triggered and gtt.expired are published by the sandbox GTT manager, so today they only reach you in Analyze mode: a live GTT fires at the broker, where Tradeboard does not observe the moment it triggers.
The alert formatter has a dedicated layout for each order API type. GTT events do not have one yet, so they arrive under the generic Order Update heading with the mode line, strategy name and timestamp but no per-trigger detail.
Alert Format
Each alert includes:
- Strategy Name: First line, if
strategywas supplied in the API call - Mode Indicator:
LIVE MODE - Real Orderfor real broker orders,ANALYZE MODE - No Real Orderfor sandbox orders, followed by a horizontal rule - Order Details: Symbol, action, quantity, price type, exchange, product type
- Status: Order ID on success, or an error line with the failure message
- Timestamp:
Time: HH:MM:SSon the last line
The bot sends its messages with Telegram Markdown, so mode indicators, strategy names and symbols arrive bold or monospaced rather than decorated with icons. Status markers inside multi-leg alerts are written as plain tags such as [OK] and [FAILED].
Example Notifications
Live order placed:
Order Placed
Strategy: MyStrategy
LIVE MODE - Real Order
─────────────────────
Symbol: RELIANCE
Action: BUY
Quantity: 10
Price Type: MARKET
Exchange: NSE
Product: MIS
Order ID: 250408000989443
Time: 14:23:45Analyze mode order:
Order Placed
Strategy: TestStrategy
ANALYZE MODE - No Real Order
─────────────────────
Symbol: RELIANCE
Action: BUY
Quantity: 10
Price Type: MARKET
Exchange: NSE
Product: MIS
Order ID: ANALYZE123456
Time: 14:23:45Configuration
- Alerts are enabled by default for every linked user. The gate is the
notifications_enabledflag on the linked-user row, which is shown on/telegram/usersand defaults to on - A send that fails (bad token, Telegram API error, timeout) is recorded in the
notification_queuetable at priority 8. There is no background worker that drains this queue, so treat it as a delivery audit trail rather than an automatic retry - If Telegram rejects the message because of a Markdown parsing error, the alert is immediately re-sent as plain text
- Zero impact on order execution speed: formatting and sending happen on a five-worker thread pool, never on the order-placement path
Requirements for Receiving Alerts
- The Telegram bot must be started (Start Bot on
/telegram, orPOST /telegram/bot/start). While the bot is stopped, automatic alerts are suppressed andPOST /api/v1/telegram/notifyreturns HTTP 409 - Your account must be linked with the
/linkcommand notifications_enabledmust be on for your linked user (the default)- Orders must be placed through the Tradeboard API. Orders placed directly on a broker website do not raise events
Chart Features
Intraday Charts
- Default interval: 5 minutes
- Default period: 5 days
- Candlestick price panel plus a volume panel, with volume bars colored green or red by candle direction
- Category-type x-axis, so there are no blank gaps for non-trading hours
Daily Charts
- Default interval: Daily (
D) - Default period: 252 trading days. The history request reaches back 1.5 times that many calendar days to make sure enough sessions are returned, then the series is trimmed to the requested count
- Candlestick price panel plus a volume panel, using the same layout as the intraday chart. No moving averages or other overlays are drawn
Chart Customization
- Intervals: passed straight through to the history API.
1m,5m,15m,30m,1hfor intraday,Dfor daily - Days: customize the lookback period
- Exchange: any exchange the history API supports, for example NSE, BSE, NFO, CDS, MCX, NSE_INDEX, BSE_INDEX
Security
API Key Encryption
- API keys are encrypted with Fernet before storage in the
telegram_userstable - The Fernet key is derived with PBKDF2-SHA256 (100,000 iterations) from
API_KEY_PEPPERand theTELEGRAM_KEY_SALTsalt - Keys are never stored in plain text and each user's key is isolated
Authentication
/linkrequires a valid API key and is validated against the Tradeboard server before anything is stored- The bot management pages and routes under
/telegramare behind the Flask login session - The public
/api/v1/telegram/*endpoints are authenticated with an Tradeboard API key, sent either as theapikeybody field or theX-API-KEYheader POST /api/v1/telegram/webhookis verified against theX-Telegram-Bot-Api-Secret-Tokenheader. The expected value isTELEGRAM_WEBHOOK_SECRETif set, otherwise the first 32 characters of the SHA-256 digest of the bot token
Privacy
- Each Telegram user can only access their own linked account
- No cross-user data access
- Command usage is logged for security audit
Database Schema
The bot uses SQLAlchemy ORM with the following tables:
TelegramUser
- Table
telegram_users. Stores user-bot linkage:telegram_id,tradeboard_username,encrypted_api_key,host_url,telegram_username,first_name,last_name,broker,is_active,notifications_enabled,last_command_at
BotConfig
- Table
bot_config, a single row withid=1. Holds the encryptedtoken,bot_username,is_active,max_message_length(default 4096),rate_limit_per_minute(default 30) andbroadcast_enabled - There is no webhook URL or polling-mode column. The bot always runs in polling mode; the webhook route exists but does not yet dispatch updates
CommandLog
- Table
command_logs. Audit trail of every command and inline-button callback:telegram_id,command,chat_id,parameters,executed_at. This table backs the/telegram/analyticspage andGET /api/v1/telegram/stats
NotificationQueue
- Table
notification_queue. Rows written when a send fails, carryingmessage,priority,status,error_message
UserPreference
- Table
user_preferences. Per-user flags:order_notifications,trade_notifications,pnl_notifications,daily_summary,summary_time,language,timezone. These are readable and writable throughGET/POST /api/v1/telegram/preferences; the order-alert path currently gates only onnotifications_enabled
Technical Architecture
Components
- TelegramBotService (
services/telegram_bot_service.py)- Core bot logic and command handlers, built on python-telegram-bot
- Tradeboard Python SDK integration for every data call
- Chart generation using Plotly
- TelegramAlertService (
services/telegram_alert_service.py)- Formats and delivers order alerts using a synchronous
httpx.Clientstraight tohttps://api.telegram.org, so no asyncio or greenlet boundary is crossed under Gunicorn plus eventlet - Owns the five-worker
alert_executorthread pool
- Formats and delivers order alerts using a synchronous
- Event bus subscriber (
subscribers/telegram_subscriber.py)- Registered in
subscribers/__init__.register_all()on every order, position, batch and GTT topic
- Registered in
- Database Layer (
database/telegram_db.py)- SQLAlchemy models and queries
- Fernet encryption and decryption helpers
- Configuration management, with TTL caches on user and preference lookups
- Blueprint (
blueprints/telegram.py)- Session-authenticated routes for bot management, consumed by the React pages
- REST namespace (
restx_api/telegram_bot.py)- The public
/api/v1/telegram/*surface
- The public
- React pages (
frontend/src/pages/telegram/)/telegram,/telegram/config,/telegram/usersand/telegram/analytics
- Auto-start Feature
- Bot automatically starts on application launch if it was active when the server stopped
- State persistence across restarts, configured in
app.py
Threading Model
- Bot runs in a separate thread with its own event loop
- Non-blocking operation with the main Flask application
- Graceful shutdown handling, with automatic reconnect and backoff on Telegram network errors
Chart Generation
- Uses Plotly for chart creation
- Kaleido engine for PNG export
- Pandas for data manipulation
- Category-type x-axis to handle gaps
- Tradeboard pins
kaleido==1.3.0. Kaleido 1.x no longer bundles a browser: it drives a real headless Chromium over the Chrome DevTools Protocol, so Chromium must be installed on the host or in the container. Each render spawns a browser process for roughly one to three seconds. A missing Chromium is the usual reason/chartreplies "Failed to generate charts" - The render runs on a genuine, un-monkey-patched OS thread. Kaleido calls
asyncio.run()internally, which cannot run inside the bot's live event loop, and eventlet's patchedthreading.Threaddoes not escape it
Troubleshooting
Bot Not Responding
- Check that the badge on
/telegramreads Online - Verify the bot token is correct on
/telegram/config - Check network connectivity to
api.telegram.org - Review the server logs for errors
Chart Generation Issues
- Confirm Chromium is installed and reachable. On Docker:
docker exec tradeboard-web /usr/bin/chromium --version. On bare metal:which chromium || which chromium-browser - Ensure market data is available for the symbol
- Check that the exchange is correct
- Verify the interval is supported and the date range is valid
Linking Issues
- Verify the API key is correct and active
- Ensure the host URL is reachable from the machine running the bot, and that you passed both arguments to
/link - Check that the API key resolves to an Tradeboard user
- Verify the Tradeboard server is running
Alerts Stopped Arriving
- Check whether the bot was stopped. Stopping the bot also stops automatic order alerts
- Confirm
notifications_enabledis on for your row on/telegram/users - Confirm the order actually went through the Tradeboard API
- Look for
notification_queuerows, which record sends that failed
Environment Variables
The bot respects the following environment variables:
DATABASE_URL- Database connection string. The Telegram tables live in the main Tradeboard databaseAPI_KEY_PEPPER- Pepper fed into the PBKDF2 key derivation for the stored API keys and bot tokenTELEGRAM_KEY_SALT- Salt for that derivation. Defaults totelegram-tradeboard-saltHOST_SERVER- Tradeboard server URLTELEGRAM_RATE_LIMIT- Rate limit for the/api/v1/telegram/*endpoints. Defaults to30 per minuteTELEGRAM_MESSAGE_RATE_LIMIT- Rate limit forPOST /telegram/send-message. Defaults to10 per minuteTELEGRAM_WEBHOOK_SECRET- Shared secret for webhook verification. Derived from the bot token when unset
API Endpoints
Web Interface
All routes below are under /telegram and require a logged-in Flask session. The pages themselves (/telegram, /telegram/config, /telegram/users, /telegram/analytics) are React routes served by the single-page app.
POST /telegram/config- Update bot configuration (token,broadcast_enabled,rate_limit_per_minute)POST /telegram/bot/start- Start the botPOST /telegram/bot/stop- Stop the botGET /telegram/bot/status- Bot lifecycle statePOST /telegram/broadcast- Send a message to all users with notifications enabledPOST /telegram/test-message- Send a test message to the logged-in user's linked chatPOST /telegram/send-message- Send a message to onetelegram_idPOST /telegram/user/<telegram_id>/unlink- Unlink a user from the admin UIGET /telegram/api/index- Dashboard payload for the React pageGET /telegram/api/config- Config payload (never returns the token itself)GET /telegram/api/users- Linked users plus 30-day command statsGET /telegram/api/analytics- 7-day and 30-day command stats
There is no restart route. To restart the bot, stop it and start it again.
Public REST API
Mounted at /api/v1/telegram. Authenticate with an Tradeboard API key in the apikey body field or the X-API-KEY header.
GET /api/v1/telegram/config- Read bot configuration. The token is truncated in the responsePOST /api/v1/telegram/config- Update configuration.rate_limit_per_minutemust be between 1 and 120POST /api/v1/telegram/start- Initialize and start the botPOST /api/v1/telegram/stop- Stop the botGET /api/v1/telegram/users- List linked users. Optionalbrokerandnotifications_enabledquery filtersPOST /api/v1/telegram/notify- Send a message to one linked userPOST /api/v1/telegram/broadcast- Broadcast endpoint. Limited to 5 requests per minute and refuses with HTTP 403 when broadcast is disabled. The fan-out itself is not wired up yet, so it returnssuccess_countandfail_countof 0. Use the Send Broadcast button on/telegram, which posts toPOST /telegram/broadcastand does sendGET /api/v1/telegram/stats- Command usage statistics. Optionaldays(1 to 365, default 7)GET /api/v1/telegram/preferences- Read per-user preferences. Requirestelegram_idPOST /api/v1/telegram/preferences- Update per-user preferencesPOST /api/v1/telegram/webhook- Inbound webhook receiver, verified by secret token
POST /api/v1/telegram/notify takes:
| Field | Type | Description |
|---|---|---|
apikey | string | Required. Tradeboard API key |
username | string | Required. Tradeboard login username, not the Telegram username |
message | string | Required. Message body, up to 4096 characters |
priority | integer | Optional, 1 to 10, default 5. Out-of-range values fall back to 5 |
wait_for_delivery | bool | Optional, default false. When true, the call blocks until Telegram replies |
curl -X POST http://127.0.0.1:5000/api/v1/telegram/notify \
-H 'Content-Type: application/json' \
-d '{
"apikey": "your_api_key",
"username": "your_tradeboard_username",
"message": "NIFTY crossed 24000",
"priority": 8
}'The endpoint returns HTTP 409 when the bot is stopped, HTTP 404 when the username has no linked Telegram account, and HTTP 401 for a bad API key.
Python SDK
from tradeboard import api
client = api(api_key="your_api_key", host="http://127.0.0.1:5000")
client.telegram(
username="your_tradeboard_username",
message="Stop loss hit on BANKNIFTY",
priority=10,
)username, message and priority are keyword-only. username is the Tradeboard login username, not the Telegram handle.
Error Handling
- All errors are logged with context
- User-friendly error messages in Telegram
- A Markdown parse failure is retried once as plain text
- Network errors during polling trigger a reconnect with backoff, up to five attempts
- Graceful degradation for missing data
Performance Considerations
- Alerts are dispatched on a five-worker thread pool, off the request path
- User, credential and preference lookups are served from 30-minute TTL caches
- Database queries are optimized with indexes
- Chart rendering is the one blocking step: it pauses the bot's event loop for the duration of the Chromium render, which is acceptable for personal, low-volume use
Future Enhancements
- [ ] Real-time price alerts
- [ ] Portfolio analytics
- [ ] Custom indicators on charts
- [ ] Webhook dispatch (the route exists and is authenticated, but updates are not yet processed)
- [ ] Inline queries for quick quotes
Support
For issues or questions:
- Check the logs in the Tradeboard dashboard
- Review this documentation
- Contact Tradeboard support
