TradingView Webhook 到 Telegram
一個 alert 只吃一個 URL,你要在哪一層 fan-out
你在 TradingView 上把 alert 設好了,webhook(也就是把訊號 HTTP POST 到你指定 URL 的那條通道)那格填的是自己交易所的 bot;接著發現只能填一個 URL——你想順便在 Telegram 收一則「進場了、成交價多少」的通知,卻找不到第二格可以填。
這件事沒有人先跟你講:TradingView 的 alert 一次只吃一個 webhook URL。想「TradingView Webhook 同時打進 Telegram 與交易所」就得在中間加一層——不管是你自己寫個 proxy、把 alert 直接指到 Telegram bot(不下單)、還是走一個中間服務把兩件事一起做掉。而中間層要不要真的下單,就牽涉到 API key(也就是授權下單/查詢用的一組金鑰)該由誰來保管。這篇不比較哪個做法比較好,也不評論你的策略。給你三件事:三種 fan-out 位置的取捨、順序與去重會踩到什麼坑、以及只推 Telegram、不真下單的觀察期怎麼設。
為什麼「同時打到 Telegram 與交易所」不是 TradingView 該做的事
TradingView 的 alert 面板長這樣:條件、名稱、有效期限、通知管道(App、Email、Webhook)。Webhook 那格是一個文字輸入框,不是清單——你只能填一個 URL、一份 payload。這是產品設計,不是 bug。TradingView 選擇把「發到哪」交給你自己決定的一個端點,之後那個端點要怎麼展開,跟它沒關係。
所以「下單同時通知我」這件事,得在 webhook URL 那一頭自己接。訊息裡的「進場了、成交價多少、有沒有失敗」這些欄位,都要等到交易所回單之後才存在——alert 剛觸發那一刻它們還沒有值。fan-out 因此不是「TradingView 一次發兩份」的問題,而是「你在 webhook 收到訊號之後,怎麼在同一段流程裡把下單結果同時送到 Telegram」的問題。這個框錯了,後面的順序、去重、rate limit 都會跟著設錯。
三個可以放 fan-out 的位置,各自優化什麼
同樣是「下單同時通知我」,中間那層放哪裡差很多。這張表是給你比對用的,不用背——挑一個之後回頭看那一欄的取捨就好。
| 自己寫 proxy | TradingView 直發 Telegram bot(不下單) | 走中間服務同時做兩件事 | ||
|---|---|---|---|---|
| 誰握你的交易所 API key | 你自己的伺服器 | 沒人握(只發訊息,不下單) | 中間服務 | |
| 誰扛 uptime | 你自己 | Telegram + 你的 bot server | 中間服務 | |
| 去重誰做 | 要自己寫(記住 dedup key) | 沒下單所以不會重複下,但訊息會來兩則 | 中間服務內建 | |
| 順序保證 | 要自己寫(先下單再通知) | 不下單,沒有順序問題 | 中間服務內建(下單結果為準) | |
| 適合誰 | 會寫後端、想全掌握 | 只想看訊號、還在觀察期 | 要真下單但不想維運 |
第二種「TradingView 直發 Telegram bot」是最被低估的一種——你把 alert 的 webhook URL 直接指向https://api.telegram.org/bot<TOKEN>/sendMessage,在 alert message 裡把訊息內容寫成 chat_id 與 text 兩個 JSON 欄位,就會收到訊息但完全不下單。適合還在觀察策略準不準、還不敢真下單的階段;缺點是 TradingView 在 5xx 時會重送、你會收到重複訊息(Telegram 的 sendMessage 沒有 idempotency key)。
順序踩雷:先發 Telegram 才下單,就等於誤報成功
這是最容易寫壞的一段。假設你的中間層寫成「先發 Telegram 告訴用戶已收到、再去交易所下單」。訊息會這樣:「已收到訊號 BTCUSDT buy 0.01」。然後你的下單去撞到餘額不足、min notional、或 API key(授權下單/查詢用的一組金鑰)沒開合約權限——任何一個都會讓下單根本沒發生,但用戶已經以為「進場了」。
正確順序是把 Telegram 通知綁到「下單流程的最後一步」——先跑完 pre-checks、送去交易所 API、拿到 fill 或明確的錯誤訊息之後才推 Telegram。這個順序是機制上的正確答案,不是憑口味挑:因為 Telegram 訊息裡的每個欄位都需要下單後才存在(成交價、實際數量、剩餘餘額、失敗原因)。「舉例來說」,TVSBot 執行端的通知就是在 process_signal 跑完之後才進 _send_notification(backend/app/services/orders.py),訊息裡的成交價、per-key ✓/✗ 結果、失敗時具體錯誤都是從交易所回單後才有的資料。
去重踩雷:TradingView 會在 5xx 時重送,Telegram 會來兩則
TradingView 的官方 webhook 送達規格是接收端 3 秒內沒回應就取消、不重試;4xx 也不重試;只有 5xx 會等 5 秒後重送,最多 3 次(見我們的另一篇:TradingView Webhook 延遲有多嚴重?官方規格、常見成因與能修好的地方)。這代表:若你的中間層在下單當下遇到交易所短暫回 5xx,又把 5xx 直接透傳回 TradingView,同一個 alert 會被送 2 到 4 次。結果 Telegram 收到 2 到 4 則「成交」訊息,但實際部位只開了 1 個——其他次可能因為交易所自身的 idempotency 或 dedup 而 no-op。
解法是中間層自己做 dedup,不要把重送往下游傳。可用的鍵至少要包含 strategy、symbol、action、qty,最好加上時間窗(60 秒內同 hash 直接 skip)。同一份設計 TVSBot 執行端在 backend/app/routers/webhook.py 的第 4 步是這樣寫的:payload hash user_id|strategy|symbol|action|qty,60 秒內重複直接不執行。
Rate limit 踩雷:Telegram Bot API 有秒級上限
Telegram Bot API 對 sendMessage 有秒級的速率限制——單一 chat 大約 1 條/秒,跨 chat 累計還有另一個上限,超過會回 429 並附 retry_after(實際數字請去 Telegram Bot API 官方 FAQ 那頁查證,他們保留隨時調整的權利)。單人自用大概撞不到,但如果你在跑「一策略多帳戶 fan-out」或「同時通知社群 100 個訂閱者」,就會在某次高頻 alert 上一次撞爆。
這件事會安靜地壞掉:Telegram 只回 429、不會補送,你不主動去看就不會知道有訊息丟了。可行的做法:在中間層加一個訊息佇列,超過秒級上限就往後排、記錄丟過幾則。或更務實地:把 Telegram 通知從「每筆訂單一則」改成「每小時彙整一則」,散戶自用完全夠。
只推 Telegram、不真下單的觀察期:dry-run 是給這件事用的
一個常被忽略的用法:把 Telegram 當「策略試跑板」。你想看新策略在真實市場上會發多少訊號、什麼時間、方向對不對——但還不敢接真錢。這時候你不是要「同時通知 + 下單」,你要的是「只通知,不下單」。
兩種做法都行。第一種:TradingView alert 直接指向 Telegram Bot API 的 sendMessage,中間不放任何下單邏輯。缺點如上一節寫的——重送與 rate limit 都由你自己扛,而且訊息裡沒有「這個訊號真的能被交易所吃嗎」的驗證(min notional、槓桿設定、可用餘額都沒查)。第二種:走中間服務但設成 dry-run。「舉例來說」,TVSBot 的每個策略有 dry_run 開關,開了之後訊號會走完整個 pre-check + 假下單流程、把「這筆理論上會下 0.03 BTC,模擬成交價 65,432」寫進 Telegram 通知,但完全不打到交易所——訂閱守門也會放行讓沒付費的用戶也能試(backend/app/services/orders.py 的 force_dry_run 與策略層的 dry_run 兩處都指向同一段邏輯)。
你不用真的自己寫 proxy——只要看得懂它在做哪四件事
你要不要自己寫這個中間層是取捨題。看清楚它在做什麼、再決定要不要接手就好。任何做「TradingView → Telegram + 交易所」fan-out 的中間層都會處理下面這四層。列出來給你當檢查表——你自己寫、還是選中間服務,都是看它有沒有把這四件事處理完。
- 驗身分。Webhook URL 全世界都能打,一定要在 URL 或 payload 帶一組長 token 驗證。用
hmac.compare_digest這種常數時間比對——直接==會被 timing attack 逐字元反推。 - 限流。per-token 與 per-IP 各一個上限,攻擊者知道你的 URL 也不能把中間層打掛。
- 去重。拿
strategy + symbol + action + qty算 hash,60 秒窗口內重複的訊號直接 skip。這一步擋掉 TradingView 5xx 重送與人為 replay。 - 先下單、後通知。Telegram 訊息一定綁在下單流程的最後一步——這樣訊息裡的成交價、失敗原因才會是真的,而不是「我以為」。
誠實的一段:Telegram 不能當你的 kill switch
這一段是我們自己做過會後悔的:把 Telegram 當唯一的通知管道。Telegram 不保證即時、不保證送達、你也不會收到「這則訊息丟了」的通知——Telegram 沒有這個機制。任何自動化交易架構都保證不了 100% 送達——包括我們自己。如果你打算靠 Telegram 通知在下單失敗時「趕快去補救」,那條依賴是脆的:你可能因為手機沒訊號、Telegram 通知被系統批次靜音、或訊息本身在中間層 rate-limit 掉,就錯過整整一次事件。
真的要有可以在半夜叫醒你的通知,走 SMS 或電話輪詢(PagerDuty、Opsgenie 這類),不要押在 IM 上。Telegram 適合「事後對帳」與「例行通知」,不適合「異常必須被看到」的用途。反過來,這也代表 kill switch 這種真的要能立刻停單的按鈕不能只放在 Telegram bot 裡——它一定要有一個 web dashboard 版本,你手機 App 或朋友的電腦都能點得到。
常見問題
為什麼還要 fan-out?TradingView alert 不能一次送到多個地方嗎?
把 TradingView alert 的 webhook URL 直接指到 Telegram Bot API,這樣算作弊嗎?
如果我先發 Telegram「已收到訊號」再下單,會怎樣?
Telegram Bot API 的 rate limit 我怎麼知道自己會不會撞到?
我要用 TVSBot 的話,Telegram 通知還要自己設嗎?
/start <code>就綁好, 之後下單結果會自動推。也支援 /balance、/positions、/status三個查詢指令(見backend/app/services/telegram.py)。 Kill switch 還是要在 web dashboard 上按, 不是靠 Telegram——這是上一節那段誠實話的落地。Get started
把 TradingView alert 指過來,下單同時把成交結果推到你的 Telegram——TVSBot 用你自己的 API key、內建 60 秒去重、先下單再通知、支援 dry-run 觀察期。
免費開始使用