How TradingView Alert Messages Work
When a TradingView alert with a webhook fires, TradingView sends the text of the alert's Message field to your webhook URL. It first replaces any placeholders, such as {{ticker}}, with live values. It does not check, format or fix the text.
TradingView itself does not require JSON. The service that receives the message does. Each service defines its own keys, so a message written for one tool will not work in another. This reference documents the JSON format Roboquant Connect accepts for Tradovate orders, and the TradingView rules that apply to any receiver.
The short version: build your alert in Connect's Alert Builder and copy the JSON it generates. Use this page to understand what the builder produced, or to adjust a message by hand.
The Minimal Message
This is what the Alert Builder generates for a strategy alert on a single Tradovate account:
{
"exchange": "tradovate",
"accountId": 12345678,
"symbol": "{{ticker}}",
"side": "{{strategy.order.action}}",
"quantity": "{{strategy.order.contracts}}",
"price": "{{strategy.order.price}}"
}
When the strategy buys 2 contracts, TradingView fills in the placeholders and the message arrives with "side": "buy" and "quantity": "2". With the account's position sizing on Fixed Qty (the default), Connect places a market buy for 2 contracts on account 12345678.
For an indicator alert, there is no strategy order to read, so side and quantity are fixed and the price comes from the bar close:
{
"exchange": "tradovate",
"accountId": 12345678,
"symbol": "{{ticker}}",
"side": "buy",
"quantity": 1,
"price": "{{close}}"
}
With indicator alerts you create one alert per action, for example one with "side": "buy", one with "side": "sell" and one with "side": "close".
JSON Rules TradingView Won't Check for You
- Double quotes only.
{'side': 'buy'}is not valid JSON. - Quote placeholders. Write
"quantity": "{{strategy.order.contracts}}", not"quantity": {{strategy.order.contracts}}. The quoted form stays valid JSON before and after TradingView fills it in. Connect reads numbers sent as text. - No trailing commas after the last field.
- No comments. JSON has no
//comments. - Stay within TradingView's size limits. The Message field holds up to 4,000 characters. Messages built in Pine with
alert()oralert_messagecan be up to 40,960 characters (TradingView size limits).
If you edit a message by hand, paste it into any JSON validator before saving the alert.
Field Reference
Most fields accept both camelCase and snake_case, so accountId and account_id mean the same thing.
Order fields
| Field | Accepted names | Values | Notes |
|---|---|---|---|
| Symbol | symbol | Root symbol (MNQ) or {{ticker}} | Required |
| Side | side or action | buy, sell, close, cancel_all | Case-insensitive, so Buy works |
| Quantity | quantity, qty or contracts | Number of contracts | Use exactly one of the three |
| Order type | order_type (snake_case only) | market, limit, stop | Market if omitted |
| Price | price | Price for limit and stop orders | Strategy alerts send {{strategy.order.price}} |
What the sides do:
buy/sell: open, add to or reduce a position.close: exit the position on that symbol. Exits andclosestill go through when the daily loss limit has blocked new entries.cancel_all: cancel working orders for that symbol.
Account fields
| Field | Accepted names | Use it for |
|---|---|---|
| One account | accountId / account_id | A single Tradovate account |
| Several accounts | accountIds / account_ids | The same order on each account |
| Accounts with their own sizing | accounts | A list of { "accountId", "fixedQuantity" or "quantityMultiplier" } |
Every message must name at least one account. A message without accountId, accountIds or accounts does not place an order.
Sizing fields
| Field | Accepted names | Effect |
|---|---|---|
| Multiplier | quantityMultiplier / quantity_multiplier | Multiplies the alert's quantity |
| Fixed quantity | fixedQuantity / fixed_quantity | Ignores the alert's quantity and trades this size |
The multiplier applies when the account's position sizing is Fixed Qty, the default. A fixed quantity always wins.
For one account the Alert Builder puts these at the top level. For several accounts with different sizing it puts them inside each entry of accounts.
Exit fields
| Field | Accepted names | Values |
|---|---|---|
| Stop loss | stopLoss / stop_loss | A number |
| Stop loss unit | stopLossType / stop_loss_type | price, ticks, points, percent |
| Take profit | takeProfit / take_profit | A number |
| Take profit unit | takeProfitType / take_profit_type | price, ticks, points, percent |
price is an absolute price. ticks and points are distances from the entry. percent is a percentage of price.
Reversal field
| Field | Accepted names | Values |
|---|---|---|
| Flatten first | flattenFirst, flatten_first, closePositions, close_positions | true or false |
When true and you hold a position in the opposite direction, Connect adds that position's size to the order, so a single order closes the old position and opens the new one.
Examples
Fixed stop loss and take profit
A strategy entry with a 10-point stop and a 20-point target:
{
"exchange": "tradovate",
"accountId": 12345678,
"symbol": "{{ticker}}",
"side": "{{strategy.order.action}}",
"quantity": "{{strategy.order.contracts}}",
"price": "{{strategy.order.price}}",
"stopLoss": 10,
"stopLossType": "points",
"takeProfit": 20,
"takeProfitType": "points"
}
Stop and target calculated by your strategy
If your Pine strategy calculates its own stop and target prices, the Alert Builder can pass them through instead of fixed distances. It generates this message:
{
"exchange": "tradovate",
"accountId": 12345678,
"symbol": "{{ticker}}",
"side": "{{strategy.order.action}}",
"quantity": "{{strategy.order.contracts}}",
"price": "{{strategy.order.price}}",
"bracketSource": "strategy",
"stopLoss": "{{strategy.order.alert_message}}",
"stopLossType": "price",
"takeProfit": "{{strategy.order.alert_message}}",
"takeProfitType": "price"
}
In Pine, you add the rqBracket() helper the Alert Builder provides and pass it to each entry as alert_message:
if longEntryCondition
strategy.entry("Long", strategy.long, alert_message = rqBracket(longStopPrice, longTargetPrice))
The helper outputs rqbracket:<stop>:<target>. Connect decodes it and rejects the order if the stop and target are not on the correct sides of the entry price. Add disable_alert = true to the matching strategy.exit() calls, because the bracket already handles the exit at the broker.
Limit order
{
"exchange": "tradovate",
"accountId": 12345678,
"symbol": "MNQ",
"side": "buy",
"quantity": 1,
"order_type": "limit",
"price": "{{close}}"
}
order_type only works in snake_case.
Close the position
{
"exchange": "tradovate",
"accountId": 12345678,
"symbol": "{{ticker}}",
"side": "close"
}
Reverse in one alert
{
"exchange": "tradovate",
"accountId": 12345678,
"symbol": "{{ticker}}",
"side": "sell",
"quantity": 1,
"flattenFirst": true
}
If the account is long 1 contract, this sends a single sell for 2: one closes the long, one opens the short.
Several accounts with different sizes
{
"exchange": "tradovate",
"symbol": "{{ticker}}",
"side": "{{strategy.order.action}}",
"quantity": "{{strategy.order.contracts}}",
"price": "{{strategy.order.price}}",
"accounts": [
{ "accountId": 11111111 },
{ "accountId": 22222222, "quantityMultiplier": 2 },
{ "accountId": 33333333, "fixedQuantity": 1 }
]
}
When the strategy trades 1 contract, the first account trades 1, the second trades 2 and the third always trades 1. More on this in multi-account futures trading.
TradingView Placeholders Reference
From TradingView's variable documentation:
| Placeholder | Contains | Works in |
|---|---|---|
{{ticker}} | Chart symbol | All alerts |
{{exchange}} | Exchange of the symbol | All alerts |
{{close}} | Bar close price | All alerts |
{{time}} | Bar time | All alerts |
{{interval}} | Chart timeframe | All alerts |
{{strategy.order.action}} | Order side (buy or sell) | Strategy alerts |
{{strategy.order.contracts}} | Order size | Strategy alerts |
{{strategy.order.price}} | Order fill price | Strategy alerts |
{{strategy.order.id}} | Order ID from your Pine code | Strategy alerts |
{{strategy.order.alert_message}} | The order's alert_message argument | Strategy alerts |
{{strategy.market_position}} | Position after the order | Strategy alerts |
{{strategy.position_size}} | Position size after the order | Strategy alerts |
Common Mistakes
Hardcoding an expired contract. "symbol": "ESH5" stops working when that contract expires. Use the root symbol (ES) or {{ticker}} so the alert trades the current front month. If you use Allowed Symbols with {{ticker}}, list continuous symbols such as ES1! exactly as the alert sends them.
Leaving out the account. Connect needs accountId, accountIds or accounts in every message.
Pasting the URL into the message. The webhook URL goes in the Notifications tab. The message holds only the JSON.
Using strategy placeholders in an indicator alert. {{strategy.order.action}} is empty outside strategy alerts, so the order has no side.
Writing orderType. Only order_type is read. A camelCase orderType is ignored, and the order goes in as market.
Unquoted placeholders. They make the saved message invalid JSON and fail in ways that are hard to spot. Quote them.
Expecting a symbol filter in the JSON. Symbol restrictions live in Connect's Allowed Symbols setting, not in the message. If a symbol isn't on the list, the order is blocked. On continuous-contract charts {{ticker}} sends symbols such as MNQ1!, which does not match MNQ, so list each symbol exactly as your alert sends it, or send a fixed root symbol instead of {{ticker}}.
Related Guides
- The Complete Guide to TradingView Webhooks
- How to Connect TradingView to Tradovate
- Multi-Account Futures Trading With One Alert
- TradingView to Tradovate automation with Roboquant Connect
Skip the Hand-Written JSON
Connect's Alert Builder generates a correct message for your accounts, sizing and exits, ready to paste into TradingView. Every order it places shows up in Executions with the exact payload that triggered it.
Start your 7-day free trial · Read the Connect setup guide
Automated trading involves risk of loss.