How to send a chart alert to a trading bot

A TradingView alert can POST to a bot that places the order. What the webhook costs, what it does not promise, and where the secret ends up.

Create a TradingView alert with a webhook URL — a paid feature from Essential up, with two-factor authentication switched on — and point it at a bot that accepts one: 3Commas or Altrady hosted, OctoBot or Gunbot on your own server, or a receiver you write around CCXT. TradingView sends one POST, cancels it after three seconds and documents no retry, so the bot has to reject stale, repeated and unauthenticated messages by itself.

The short way

TradingView does not place orders from an alert. It sends one: when an alert fires, it POSTs the message you wrote to a URL you gave it, and whatever answers that URL does the trading. So the job is three settings on the TradingView side and one bot that accepts webhooks on the other.

On the TradingView side: a paid plan, because the pricing table marks webhook notifications as absent on Basic and present from Essential upward; two-factor authentication on the account, because webhook alerts are refused without it; and a URL on port 80 or 443 over IPv4, the only ports and the only protocol the help centre accepts. Then write the alert message in whatever format the receiving bot reads — usually JSON, which TradingView sends as application/json when it parses, and as text/plain when it does not.

On the other side, the least work is a hosted signal bot. A 3Commas signal bot gives you a URL and a message template to paste into the alert; the message carries your bot's identifiers and a secret, and TradingView's placeholders fill in the rest when it fires:

{
  "secret": "YOUR_BOT_SECRET",
  "max_lag": "300",
  "timestamp": "{{timenow}}",
  "trigger_price": "{{close}}",
  "tv_exchange": "{{exchange}}",
  "tv_instrument": "{{ticker}}",
  "action": "enter_long",
  "bot_uuid": "YOUR_BOT_UUID"
}

Two of those fields are doing more work than the rest. secret is the only thing standing between the URL and anyone who learns it. max_lag is the largest delay you will accept between timestamp and execution, in seconds — anything from 10 to 86,400, 300 by default — and a signal past it is treated as invalid. It is the one field in this chain that guards against an order placed on a price from five minutes ago. Keep both. The rest of this page is about why.

What the options are

Hosted, JSON in. 3Commas, above, runs signal bots from the Pro plan; the free plan cannot trade at all. Altrady is the same shape on every tier: a webhook builder generates the JSON, which carries the api_key and api_secret from the bot's settings, and the message names the action — open, increase, reduce, close or reverse — the exchange and the market. Both run on the vendor's servers, so they keep working with your machine off, and both hold your exchange keys to do it.

Self-hosted, text in. OctoBot reads its own format, one KEY=VALUE per line or separated by semicolons:

EXCHANGE={{exchange}}
SYMBOL={{ticker}}
SIGNAL=BUY
TOKEN=YOUR_OCTOBOT_TOKEN

The webhook server listens on port 9000 by default, which TradingView will not call, so the bot either opens an ngrok tunnel — built in, with your ngrok token — or sits behind a proxy you run on 443. Gunbot takes a single space-separated line, passphrase first:

YOUR_PASSPHRASE binance buy USDT-BTC 0.1 0

— exchange, side, pair, amount and a price, where 0 means a market order — and its documentation requires the bot itself to be publicly reachable on 443. Both keep the exchange keys on your own machine, which is the reason to choose them; the network exposure is the cost.

Your own receiver. A few dozen lines of any web framework, with CCXT behind them to place the order on whichever venue you trade. This is the only version in which every check described below is code you can read: the secret comparison, the age check, the duplicate filter, and what happens to a close that arrives when there is nothing open. It is also the only one in which all of that is your bug.

Where this breaks

The secret travels in the message body. TradingView's webhook sends the message you typed and nothing else you control: the help page describes no custom header and no signing. So every bot on this page authenticates the same way — a value inside the body. 3Commas calls it secret, Altrady api_secret, OctoBot TOKEN, Gunbot a passphrase. That puts the credential in the alert definition, in the alert log, in any screenshot of either, and in any script that builds the message from inputs and gets shared. TradingView's own page asks you not to put "sensitive information such as login credentials or passwords in the webhook body", which is advice no receiver here lets you follow. What you can do is limit what the secret opens: a bot-scoped value rather than anything reused, exchange keys with withdrawals disabled, and — if the receiver is yours — a check that the request came from one of the four IPv4 addresses TradingView publishes.

One self-hosted bot ships with the check switched off. OctoBot generates a token when the TradingView service is configured, but require-token defaults to false, so until you turn it on any POST to the URL in the right format is a signal. On a URL that has been pasted into a tunnel dashboard, a chat or a support thread, that is the whole of the security.

There is no retry, and three seconds is the deadline. TradingView cancels a request the server takes longer than three seconds to answer, says webhooks "may occasionally fail to reach the specified URL", and points you at a status column in the alert log. Nothing on the page promises a second attempt. A receiver that places the order before responding can blow the deadline on a slow exchange call; one that is restarting when the alert fires simply misses it. A missed entry costs an opportunity. A missed exit leaves a position open that the chart believes is closed — which is why Altrady recommends a single reverse signal over a close followed by an open, noting that with separate signals "the timing of the close is unknown".

The alert fires later than the bar closes. With "once per bar close", TradingView waits for the first trade of the next bar before it can be sure the previous one has closed; on a thin market that can be several seconds, and with no trades at all the server closes the bar itself one minute after the formal close. Add the exchange call on the far side, and the order is priced by the market that exists then, not by {{close}}. That is what max_lag is for; a receiver of your own should compare {{timenow}} with its own clock and refuse old signals the same way.

A signal that repaints can trade and then vanish. The default frequency for a script's alert() is once per bar, which fires on the first call during the live bar — before the bar is confirmed. An indicator whose condition is true mid-bar and false at the close has sent a webhook by then, and the chart afterwards shows no signal where your bot traded. Pine's documentation defines repainting as historical and real-time calculations behaving differently, and says the simplest way to avoid it in alerts is to trigger only on bar close, at the price of immediacy. Values requested from another timeframe are the other usual cause: on real-time bars they can be unconfirmed.

An alert runs the script as it was when you created it. TradingView saves a copy of the script, its inputs, the symbol and the timeframe; later edits "will not affect running alerts previously created from them". Fix a bug in the indicator and the bot keeps trading the buggy version until the alert is deleted and made again.

An alert that fires too often is stopped. More than 15 triggers in three minutes and TradingView halts it. A condition that flickers on a fast chart can switch off your bot's only input without anything on the bot's side noticing.

If you outgrow this

If the problem is that a missed webhook is a missed trade, stop treating the alert as the order. Make it a notification that the bot reconciles against: on each message, the receiver reads the position from the exchange and moves it toward what the signal says it should be, so the next message repairs whatever the last lost one broke. A hosted signal bot cannot be made to work this way; your own receiver can.

If the problem is that the logic lives in someone else's charting language, the durable fix is to move it next to the orders. Freqtrade, Hummingbot and OctoBot compute their signals from the exchange's own feed inside the bot process, which removes the webhook, the three-second deadline and the secret in the body at once — and brings a backtest that runs the same code, which a Pine alert never had. The costs of that are covered in what a crypto backtest silently assumes.

If the problem is that the chart is not TradingView, check the webhooks line on the card before building anything. Of the nine charting cards in this catalogue that alert at all, three list webhooks — TradingView, CoinAnk and GoCharting, where alert webhooks sit on a paid plan — and the rest notify a person rather than a program. The same caution applies at the far end: Tealstreet has a local listener but no hosted path for an alert to reach it, and Bitsgap accepts no webhooks at all. The trading bots listing is where to compare the rest.

The tools named above

In the order this page puts them in, which is an editorial judgement and not a ranking anyone paid for.

  1. 3Commas

    Signal bots take a JSON body carrying the bot's secret, plus an optional max_lag that refuses a signal older than you allow. Signal bots start on Pro.

    Hosted DCA, grid and signal bots over nine exchanges, with your keys on their servers.

    $20/moFree tier

  2. Altrady

    A hosted signal bot on every tier, fed JSON carrying the bot's key and secret. Its test flag works on open signals only; any other signal goes live.

    Multi-exchange trading workspace — smart orders, scanners, bots and a journal.

    €10/moFree tier

  3. OctoBot

    Self-hosted, with its own KEY=VALUE alert format, reached through ngrok or a proxy you run — and a token check that ships switched off.

    GPL-3.0 Python bot with a web interface for grid, DCA, basket and TradingView strategies.

    FreeFree tierOpen source

  4. Gunbot

    A self-hosted licence that reads a space-separated alert starting with your passphrase, and must listen publicly on port 443.

    A closed-source bot you install once, licensed against an ERC-20 wallet you control.

    €29/mo

  5. CCXT

    Write the receiver yourself — check the secret, drop repeats, then place the order through one client. The only option where every check is yours to see.

    One MIT client for 104 crypto exchanges, 76 of them over websocket.

    FreeFree tierOpen source

FAQ

Do TradingView webhook alerts need a paid plan?

Yes. The plan comparison marks webhook notifications as unavailable on the free Basic plan and included from Essential upward. Separately from the plan, the account needs two-factor authentication switched on, and the receiving URL has to be on port 80 or 443 over IPv4.

Does TradingView retry a webhook that failed?

Nothing in its documentation says so. The help page says a request is cancelled if the server takes more than three seconds to answer, that webhooks may occasionally fail to reach the URL, and that delivery can be checked in the webhook status column of the alert log. Build the receiver on the assumption that a message can be lost.

How do I keep someone else from triggering my bot's webhook?

TradingView cannot add headers or sign a request, so the check has to be inside the message — the secret, token or passphrase each bot defines. Make sure it is actually enforced (OctoBot's is off by default), keep it out of shared scripts and screenshots, use exchange keys without withdrawal rights, and on a receiver you run, accept requests only from the four IPv4 addresses TradingView publishes.

Why did my bot trade on a signal that is not on the chart?

Usually because the alert fired during a live bar and the condition was no longer true when the bar closed. A script's alert() defaults to once per bar, which fires on the first qualifying tick. Setting the alert to once per bar close waits for confirmation — at the cost of firing later, sometimes seconds and occasionally a minute after the close.

Sources

  1. How to configure webhook alerts — TradingView, read
  2. Compare plans — TradingView, read
  3. Delays in OncePerBarClose alerts — TradingView, read
  4. Alert was triggered too often and stopped — TradingView, read
  5. Pine Script v6 User Manual — Alerts — TradingView, read
  6. Pine Script v6 User Manual — Repainting — TradingView, read
  7. Signal bot: JSON file in Custom signal type — 3Commas,
  8. Webhook Signal Reference: Open, Increase, Reduce, Close, and Reverse — Altrady, read
  9. Services/Services_bases/trading_view_service/trading_view.py — Drakkar-Software, read
  10. Services/Services_bases/webhook_service/webhook.py — Drakkar-Software, read
  11. Trading/Mode/trading_view_signals_trading_mode/trading_view_signals_trading.py — Drakkar-Software, read
  12. octobot_services/constants.py — Drakkar-Software, read
  13. Webhook alerts — Gunbot, read

The catalogue next door

This page names a handful of products. The rest of them are in Crypto Charting Platforms & Libraries, each filled in against the same schema, with the fields to narrow it yourself.

Last updated . Corrected in place — an endpoint that moves is a bug on this page, not a new post.