A fast, low-level Telegram Bot API library for MQL5.
Requests are built directly into raw byte buffers (fixed-offset literal tables + ArrayCopy, a custom CJsonBuilder, and multipart with boundary reuse) instead of going through an intermediate DOM — no per-field allocation, no generic serialization pass.

--- ## Main Features - **Full Bot API surface** (`CTelegramAPI`): messages, polls (regular/quiz), documents/video/audio/voice/animation/photo (multipart), rich messages, chat actions, reactions, member management (ban/unban/restrict/promote), bot profile, chat management, callback query answers, message/reply-markup editing, poll stopping, deletes. - **Independent long-polling updater** (`CTelegramBotUpdater` + `CTelegramHandler`): decoupled from `CTelegramAPI` — the bot only calls the API, the updater only polls and dispatches. Handlers register per event (27 event types) via bitmask or one at a time; `AllowedUpdates()` can auto-compute the `allowed_updates` filter from whichever events actually have a handler registered, so you don't get updates nobody is listening for. - **Perfect-hash update dispatch**: incoming `getUpdates` keys are matched via a generated perfect hash (`EnumReg`), not string comparisons, before landing in the event `switch`. - **Keyboard builders** (`CTlgInlineKeyboard`, `CTlgReplyKeyboard`): chainable, raw-buffer builders for `InlineKeyboardMarkup` / `ReplyKeyboardMarkup`. Both share a `CTlgKeyboardBase` (buffer + row/button bookkeeping) to avoid duplicating the same comma/bracket logic twice — not an "is-a" hierarchy, just shared plumbing. - **Snapshot/rollback for speculative writes**: `JsonBuilderSnapshot` (JSON builder) and `TlgKeyboardSnapshot` (keyboards) capture position + internal stack state so an optional nested object (e.g. `reply_parameters`) can be written speculatively and rolled back cleanly if it ends up empty, without corrupting the builder's structural state. - **Validated vs. trusted string writes**: library-controlled constants (parse mode names, chat actions, field keys) go through the unvalidated/raw path (`KeyWV`/`ValUWV`/`SetBuffer`); arbitrary user input always goes through the escaping path (`ValS`/`SetStr`) — chosen per call site, never blanket-escaped or blanket-trusted. ### Send a message ```mql5 #include "Src\\MainAPI.mqh" TSN::CTelegramAPI bot; bot.Token("123456:ABC-your-bot-token"); bot.ChatId(-100123456789); bot.SendMessage("Hello from MQL5", TSN::TELEGRAM_PARSE_MODE_HTML); ``` ### Long polling with handlers ```mql5 #include "Src\\Events.mqh" class CMyHandler : public TSN::CTelegramHandler { public: void OnMessage(TSN::CJsonNode& node) override { Print("Got message: ", node["text"].ToString()); } }; TSN::CTelegramBotUpdater updater; CMyHandler handler; void OnInit() { updater.Token("123456:ABC-your-bot-token"); updater.RegisterEvents(&handler, TSN::TELEGRAMBYLEO_REG_FLAG_ON_MESSAGE); // 20 seconds timeout telegram long polling updater.Timeout(30000); // 30 seg for web req updater.Init(20); // getUpdates() body: {"offset":-1,"limit":1}, discards backlog updater.AllowedUpdates(); // zero parameters (Auto) } void OnTimer() { updater.GetUpdates(); } ``` ### Inline keyboard ```mql5 #include "Src\\Bottons\\Inline.mqh" TSN::CTlgInlineKeyboard kb; kb.Init(); kb.AddRow().AddBtnCallbackData("Yes", "vote_yes").AddBtnCallbackData("No", "vote_no").EndRow(); kb.Finish(); // {"inline_keyboard":[[{"text":"Yes","callback_data":"vote_yes"},{"text":"No","callback_data":"vote_no"}]]} uchar reply_markup[]; bot.SendMessage("Vote:", WRONG_VALUE, base, rp, ep, kb.m_buf, kb.m_pos); ``` ### Reply keyboard ```mql5 #include "Src\\Bottons\\ReplyMarkup.mqh" TSN::CTlgReplyKeyboard kb; kb.Init(); kb.IsPersistent(false).ResizeKeyboard(true).OneTimeKeyboard(true); kb.InitArr(); kb.AddRow().AddBtn("Option A").AddBtn("Option B").EndRow(); kb.Finish(); // {"resize_keyboard":true,"one_time_keyboard":true,"keyboard":[["Option A","Option B"]]} ``` --- ## Repository Structure ``` TelegramByLeo/ ├── Bots/ # Example EAs using the library ├── EnumReg/ # Perfect-hash generator config for update-key dispatch └── Src/ ├── Base/ # Endpoints, shared structs, error/parse-mode enums ├── Bottons/ # Inline/Reply keyboard builders + shared keyboard base ├── Emojis/ # Emoji constant table └── Old/ # Previous (pre-rewrite) implementation, kept for reference ``` --- ## Requirements See [dependencies.json](./dependencies.json) for the full list. - MetaTrader 5, build 5430+ - [`WebUtilsByLeo`](https://forge.mql5.io/nique_372/WebUtilsByLeo) — currently a private dependency; contact [@nique_372](https://www.mql5.com/es/users/nique_372) for access. - `WebRequest` access enabled for `https://api.telegram.org` --- ## Installation ```bash cd "C:\Users\YOUR_USER\AppData\Roaming\MetaQuotes\Terminal\YOUR_ID\MQL5\Shared Projects" tsndep install "https://forge.mql5.io/nique_372/TelegramByLeo.git" ``` Requires the `tsndep` package, available on [PyPI](https://pypi.org/project/tsndep). It automatically downloads and installs all declared dependencies. --- ## Quick Start **1. Include the library:** ```mql5 #include "..\\TelegramByLeo\\Src\\MainAPI.mqh" ``` **2. Set the token and chat, and send something:** ```mql5 TSN::CTelegramAPI bot; bot.Token("123456:ABC-your-bot-token"); bot.ChatId(-100123456789); bot.SendMessage("Hello from MQL5"); ``` **3. (Optional) Add polling:** see [Long polling with handlers](#long-polling-with-handlers) above. --- ## License **[Read Full License](./LICENSE)** By downloading or using this repository, you accept the license terms. --- ## Contact - **Platform:** [MQL5 Community](https://www.mql5.com/es/users/nique_372) - **Profile:** https://www.mql5.com/es/users/nique_372 - **Articles:** https://www.mql5.com/es/users/nique_372/publications --- ## Roadmap - Finish `Get*` methods (`GetMyName`, `GetMyDescription`, `GetMyShortDescription`) using the JSON parser side [In progress] - `RestrictChatMember` / `PromoteChatMember` bodies - `KeyboardButtonRequestUsers` / `RequestChat` support in `CTlgReplyKeyboard`