A TradingView webhook JSON alert message is the text TradingView posts to a URL when an alert fires, and on a prop account it is the whole order: symbol, side, size, order type and protection. TradingView does not check that text, so a missing quote or a misspelled field only shows up as a refused signal after the market has moved.
Below is the format QATS accepts, field by field, with examples for entries, exits, protection and Pine strategies, then the alert log and the most common errors.
How an alert reaches your QATS account
In QATS, open Profile → External connections → Trade from charts → TradingView alerts (or Keys & connections on the sandbox) and choose Create webhook. Each webhook belongs to one account, expires after the period you pick and by default accepts only TradingView’s servers. Your personal URL is shown once and ends with your key, so treat it like a password.
In TradingView, tick Webhook URL under Notifications, paste that URL and replace everything under Message with a QATS JSON message. TradingView requires two-factor authentication and a plan with webhooks.
TradingView webhook JSON alert message fields QATS reads
The message must be a single JSON object with case-sensitive field names. Numbers may be sent as numbers or quoted strings, which matters because TradingView placeholders such as {{close}} arrive as text. An entry needs exactly one size field.
| Field | Values | What it does |
|---|---|---|
| symbol | {{ticker}} on a supported chart | BINANCE:BTCUSDT.P becomes BTCUSDT; a TradFi chart such as OANDA:XAUUSD maps only if that perpetual is in the QATS catalogue and your plan |
| action | buy, sell, close, flatten, cancel_all | long and short also work for buy and sell; leave it out for a Pine strategy sync |
| type | market (default), limit, stop | limit and stop need price |
| price | A number or {{close}} | Entry price for limit and stop; the price-check reference on a market entry |
| notionalUsd, quantity, lots | Exactly one | US dollars, coins of the base asset, or QATS lots |
| stopLoss, takeProfit | Prices | Protective levels; stopLossPercent and takeProfitPercent set them as a distance instead |
| maxDeviationPct | 0.01 to 2 | Price-check tolerance in percent on a market entry; 0.25% when omitted |
| reduceOnly | true or false | On buy or sell, only reduce an open position |
| id | Text | Lets QATS ignore a repeated delivery of the same event |
| position, positionSize | long, short or flat, plus a size | Pine strategy sync: QATS trades the difference |
Entry examples: market, limit and stop
A market buy of $1,000 with a 1% stop and a 2% target. For a short, change "buy" to "sell":
{"symbol": "{{ticker}}", "action": "buy", "notionalUsd": 1000, "price": "{{close}}", "stopLossPercent": 1, "takeProfitPercent": 2}
With price on a market entry, QATS refuses the fill with PRICE_REFERENCE_MISMATCH if its own price is more than 0.25% away, which catches a chart of another market or a price that ran while the alert was queued. maxDeviationPct changes the tolerance.
A limit buy that rests with its stop and target attached (the price is only an example):
{"symbol": "{{ticker}}", "action": "buy", "type": "limit", "price": 80000, "notionalUsd": 1000, "stopLossPercent": 1, "takeProfitPercent": 2}
A stop entry that sells a breakdown, with protective levels as prices:
{"symbol": "{{ticker}}", "action": "sell", "type": "stop", "price": 76000, "quantity": 0.01, "stopLoss": 77500, "takeProfit": 73000}
notionalUsd is converted into lots at the current price (or at the order price for a limit or stop) and rounded down to the instrument step, so the filled size can be slightly smaller than the dollars you sent.
Stop loss and take profit in the same message
Use stopLoss and takeProfit for prices, or stopLossPercent and takeProfitPercent for a distance from the entry. Send one form per leg; both forms for the same leg are refused as AMBIGUOUS_PROTECTION.
On a market entry, QATS submits the stop and target after the fill, from the fill price, and the log shows a result for each. A limit or stop entry rests with both attached as a bracket, so one with only a stop or only a target is refused (BRACKET_NEEDS_BOTH). A stop on the wrong side of the entry gets INVALID_STOP_LOSS.
Each instrument holds one net position. A market sell against an open long reduces it; a larger one closes it and opens the rest as a short. An alert that only reduces a position sets no new stop or target.
Exit examples: close, partial close, flatten and cancel
A close never carries the price check, so a late exit alert still closes. If there is no position, the log says Nothing to do.
- Close the whole position on the chart symbol: {"symbol": "{{ticker}}", "action": "close"}
- Reduce it by $500 without reversing, as a reduce-only order: {"symbol": "{{ticker}}", "action": "close", "notionalUsd": 500}
- Close every position and cancel every order on the account: {"action": "flatten"}
- Cancel working entry orders only: {"action": "cancel_all"}. Stops and targets on open positions stay in place.
Pine strategy alerts: sync the position, not the signal
For a Pine strategy, create one alert on the strategy with the Order fills condition and this message:
{"symbol": "{{ticker}}", "position": "{{strategy.market_position}}", "positionSize": "{{strategy.market_position_size}}", "id": "{{strategy.order.id}}-{{timenow}}"}
TradingView fills in the target state (long, short or flat) and its size; QATS trades only the difference from the account’s position, so flat closes the instrument. The id stops a repeated delivery from trading twice. Strategy size units can differ from QATS lots, so check the first fills on the sandbox.
Read the alert log after every signal
In QATS, open TradingView alerts → Alerts → Refresh. Each signal shows its time, symbol and outcome: Done, Nothing to do (the account was already in that state) or Refused with a code and a reason. A Done row can hold several results, such as the entry, stop and target; read each, then check positions and working orders in the terminal.
No row can mean TradingView never sent the webhook, or QATS rejected an invalid key before logging: check TradingView’s alert history, the URL, the webhook’s expiry and its account. Recreating an alert can send another command, so check the log before resending.
Common errors and how to fix them
| Code | Usual cause | Fix |
|---|---|---|
| ALERT_NOT_JSON | TradingView’s default text left in Message, or a missing quote or comma | Paste a complete QATS message and check its brackets and quotes |
| PLACEHOLDER_NOT_REPLACED | A strategy placeholder in an alert that is not on a strategy | Create the alert on the strategy with Order fills, or use fixed values |
| UNKNOWN_SYMBOL | The chart symbol is not a QATS instrument | Chart the perpetual, such as BINANCE:BTCUSDT.P, and send {{ticker}} |
| INVALID_ALERT_ACTION | action missing or misspelled | Use buy, sell, close, flatten or cancel_all |
| SIZE_REQUIRED, AMBIGUOUS_SIZE | No size field, or more than one | Send exactly one of notionalUsd, quantity or lots |
| SIZE_BELOW_ONE_LOT | The size rounds down to less than one lot | Increase the size to at least one instrument step |
| PRICE_REQUIRED | A limit or stop entry without price | Add a valid price for the instrument |
| BRACKET_NEEDS_BOTH | A resting entry with only a stop or only a target | Send both levels, or use a market entry |
| PRICE_REFERENCE_MISMATCH | The QATS price is too far from the alert’s price | Check the chart shows the same perpetual, then wait for a fresh signal |
Risk rules still apply to every alert
A webhook order goes through the same server-side checks as one placed in the terminal. On a QATS Crypto evaluation that means a 10% profit target, a 4% daily loss limit, a 6% end-of-day trailing maximum loss that stops trailing at the starting balance, a 40% consistency rule and 2 minimum trading days, with up to 20× on BTC and ETH, 10× on large caps and 5× on other coins. Margin, risk and plan refusals appear in the log; check Risk center rather than resending.
QATS evaluations and initial funded accounts are simulated. An account in Bybit native / Bybit Demo mode trades directly through Bybit and does not receive a QATS webhook. Test every alert on the free sandbox, which applies the same risk rules, before a paid evaluation.
Related guideTradingView prop firm trading: the three options
Frequently asked questions
01What should a TradingView webhook message contain for QATS?
A JSON object with symbol (usually {{ticker}}), action and, for entries, exactly one size field: notionalUsd, quantity or lots. Optional fields set the order type, price, stop loss, take profit and price-check tolerance.
02Do I need to put my key in the alert message?
No. The personal webhook URL ends with your key, so the message carries only the order. Older webhooks with a token field in the message still work, but a URL and message with different keys are refused.
03Why did my alert fire but no trade appear?
A fired alert is only a delivery. In the QATS alert log, Refused gives the code and reason, Nothing to do means the account was already in that state, and no row points to the URL, expiry or key.
04Can a TradingView alert set a stop loss and take profit?
Yes. Add stopLoss and takeProfit as prices, or stopLossPercent and takeProfitPercent as distances. A market entry receives them after it fills; a limit or stop entry needs both and rests with them as a bracket.
Educational content, not investment advice. QATS evaluations and initial funded accounts are simulated; payouts depend on eligibility, verification and the applicable agreement.