WebSocket vs REST APIs on Crypto Exchanges: What's the Difference
If you are wiring a strategy up to an exchange, one of the first technical forks you hit is WebSocket vs REST APIs on a crypto exchange. Both let your code talk...
Pine Script's alertcondition() and alert() both create TradingView alerts, but they fire differently and one is far better for webhook automation. Here's what each does, when to use it, and which to reach for when a signal has to become an order.
If you write Pine Script strategies or indicators, sooner or later you hit a fork in the road: should your alerts use `alertcondition()` or `alert()`? Getting Pine Script alertcondition vs alert() right matters the moment you stop watching charts by hand and start wiring alerts to real orders. The two functions look similar, but they behave differently in how they fire, what message they can send, and whether they work in a strategy at all. This guide explains what each one does, where each fits, and which to reach for when your goal is automated execution through a webhook.
Signals are easy. Reliable execution is hard. A misconfigured alert is one of the most common reasons a strategy that looks perfect in backtesting never places a single live order.
`alertcondition()` is a compile-time declaration. You call it once at the top level of an indicator, and it registers a named alert condition that appears in TradingView's "Create Alert" dialog. It does not fire anything by itself. Instead, it tells TradingView, "here is a condition worth watching," and you then create an alert that points at it.
A typical call looks like `alertcondition(ta.crossover(fast, slow), title="Long entry", message="Buy signal")`. The `title` is what you select in the alert dialog; the `message` is the default text sent when the condition becomes true. You can override that message when you create the alert, and you can inject a handful of built-in placeholders such as `{{ticker}}`, `{{close}}`, or `{{interval}}` that TradingView substitutes at fire time.
Two constraints shape everything about `alertcondition()`. First, it only works in indicators (studies), not in strategy scripts. Second, each condition you want to alert on needs its own `alertcondition()` call and its own alert in the dialog. Ten signals can mean ten conditions and ten alerts to manage.
`alert()` is a runtime function. You call it from inside your script's logic, within an `if` block, on the bar where a condition is met, and it fires an alert event at that moment. The signature is `alert(message, freq)`, where `freq` controls how often it can fire: `alert.freq_once_per_bar`, `alert.freq_once_per_bar_close`, or `alert.freq_all`.
The important difference is that the message is built at runtime. Because `alert()` runs as code, you can assemble the string from live values. That means you can emit a complete, correctly formatted payload with the exact values your receiver expects, something a static message field cannot do as flexibly.
Setup is also simpler on the dashboard. No matter how many `alert()` calls your script contains, you create one alert with the condition set to "Any alert() function call." Every `alert()` in the code routes through that single alert. And crucially, `alert()` works in both indicators and strategies.
Both functions ultimately produce a TradingView alert that can hit a webhook, but they get there differently:
One thing they share: neither fires during backtesting or bar replay. Both only produce live alerts on real-time bars, which is why you should always test your automation before going live rather than trusting backtest results alone.
`alertcondition()` still earns its place. It works well when you want discrete, human-readable conditions that a person can switch on and off individually from the alert dialog, for example a shared indicator where each subscriber decides which signals to enable. It is also fine for simple notifications where a static message with a couple of placeholders is all you need, and where you are not routing to an exchange.
If your endpoint only needs "symbol X crossed level Y," and a person is choosing which alerts to arm, `alertcondition()` keeps the setup explicit and legible.
For automated execution, `alert()` is usually the better fit. When a webhook has to receive a precise instruction, an action, a symbol, a quantity, an idempotency id, the ability to build that string from live values is the whole game. You control the exact message your receiver parses, you keep all signal logic in one script, and you manage a single alert instead of a growing list.
`alert()` is also the only option inside a strategy script. If you are converting a backtested strategy into live orders, you will reach for `alert()`, or the `alert_message` argument on `strategy.entry` and `strategy.exit`, which attaches text to order-fill alerts. Our walkthrough on Pine Script automation from backtest to live covers that path end to end.
This is where the choice becomes concrete. A webhook receiver needs structured data, not prose. With `alert()` you can output a JSON object your relay can parse directly, concatenating a unique id, an action, the live `syminfo.ticker`, and a size into a single string with `str.tostring()` for any numeric values.
That kind of payload carries a unique id for deduplication, a clear action, the live ticker, and a size. Compare that to an `alertcondition()` message, which is largely fixed text with placeholder substitution: workable for simple cases, but harder to shape into exactly the JSON contract your endpoint expects. If you want a reference for the fields a receiver typically wants, see our TradingView alert message format guide.
Whichever function you choose, a few habits keep automated alerts reliable:
Once your Pine Script is firing a clean payload, something has to receive it, validate it, and place the order. That is the job SignalToExchange does. It is a non-custodial relay: your alert posts to it, it checks the request, and it submits a single order to your exchange using trade-only API keys that cannot move funds off the platform. You keep custody; the relay handles reliable, deduplicated execution so one alert becomes exactly one order. Whether your signal comes from `alert()` in a strategy or an `alertcondition()` in a shared indicator, the relay meets it on the other side of the webhook.
No. `alertcondition()` is only available in indicators (studies). If you need alerts from a strategy, use `alert()` inside the strategy logic, or set the `alert_message` argument on your `strategy.entry` and `strategy.exit` calls to attach text to order-fill alerts.
Not entirely. `alert()` is more flexible for automation, but `alertcondition()` is still useful when you want named conditions a person can enable individually from the alert dialog. Many published indicators keep `alertcondition()` for that reason.
Neither `alert()` nor `alertcondition()` fires on historical bars or during bar replay. They only generate alerts on live, real-time bars. To confirm your wiring works, run it against a paper or testnet endpoint before pointing it at real funds.
Use `alert()` and build the string from live variables, for example concatenating `syminfo.ticker` and a fixed quantity into a JSON object. Then create one "Any alert() function call" alert with your webhook URL in the alert's notification settings.
With `alert()`, yes. You can convert numeric values to strings with `str.tostring()` and concatenate them. With `alertcondition()`, you are limited to TradingView's built-in placeholders such as `{{close}}`, which cover common values but not arbitrary computed sizes.
The short version: reach for `alert()` when you are automating orders through a webhook, and keep `alertcondition()` for notifications and user-selectable signals. `alert()` gives you a dynamic message, works in strategies, and needs only one alert to manage, everything you want when a signal has to become an order. When your alert is ready to route to a live exchange, SignalToExchange can receive it and execute it securely. Request access / start your free trial.
Automated trading involves risk. SignalToExchange is execution infrastructure and does not provide financial advice, trading signals, or guarantees of any kind.
Non-custodial execution. Trade-only API keys. Independent infrastructure built for reliability.
Request Early AccessTrade-only API key enforcement. No withdrawal permissions. No custody.