TradingView alerts to MT5 — no EA, no VPS
Turn TradingView alerts into MetaTrader 5 orders with a secret webhook URL: create a hook in the console or the API, set up the TradingView alert step by step, message formats and placeholders for indicators and strategies, closing, idempotency, the IP allowlist, troubleshooting and limits.
TradingView can send an alert to a URL, but it cannot add an Authorization
header — so it cannot call a normal API. The usual answer is an Expert Advisor
on a Windows VPS, or a paid bridge. fxapis gives you a secret alert URL
instead: paste it into a TradingView alert, and the alerts that fire become
orders on your MT5 account. We run the terminal; nothing of yours has to stay
switched on.
TradingView alert fires
→ POST https://api.fxapis.com/hooks/tradingview/<secret> answered at once (202)
→ fxapis places the order on your MT5 account(s) the same path as POST /v1/…/orders/market
→ the alert and its result appear under TradingView in the consoleTest with a demo account
An alert hook places real orders on whatever account it points at. Point your first hook at a broker demo account and fire a test alert before using a real-money account.
What you need
- An fxapis workspace with an MT5 account connected (Connect MT5 accounts). For alerts that must act within a second, set the account to always connected — an account that comes online on demand has to connect first, which takes about 10 seconds in our measurement.
- A TradingView plan that includes webhook alerts — TradingView's pricing page lists webhook notifications on its paid plans, not on Basic — and two-factor authentication switched on in your TradingView account: TradingView sends webhooks only from accounts with 2FA (About webhooks). Both checked 30 September 2026.
1. Create a hook
In the console
Open Console → TradingView → Create a TradingView hook, then:
- Name it after the strategy or chart it serves.
- Choose the account. With several accounts, each alert places one multi-account order — this needs a plan with multi-account orders.
- Set the default volume in lots. Alerts that do not send a volume use it.
- Tell it how your broker names symbols: a symbol map (
XAUUSD=XAUUSD.a, one per line) and/or a suffix added to every other symbol (.a,m,.pro…). - Leave Only from TradingView on unless you are sending test alerts yourself.
The console then shows the URL, once, with ready-to-paste messages. Copy it now: we store only a hash, so it cannot be shown again. If you lose it, rotate the hook to get a new one.
Creating and changing hooks needs a workspace owner or admin — a hook's URL can open positions, so it takes the same standing as creating a trading key.
With the API
With a key holding trading:execute:
curl -sS -X POST "https://api.fxapis.com/v1/alert-hooks" \
-H "Authorization: Bearer $FXAPIS_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Gold breakout",
"accountIds": ["2b0c7c1e-5d0b-4d8e-9a53-0e6f3b1c9a10"],
"defaults": {
"volume": "0.10",
"deviationPoints": 30,
"symbolMap": { "XAUUSD": "XAUUSD.a" },
"symbolSuffix": "",
"stripExchangePrefix": true,
"allowClose": true,
"onlyTradingViewIps": true
}
}'{
"data": {
"id": "8f1d…",
"name": "Gold breakout",
"url": "https://api.fxapis.com/hooks/tradingview/3q2-7ZkT0d8m1sQe9yVbW4nX6pLr5aHcUgJf0oKxQx4w",
"urlHint": "https://api.fxapis.com/hooks/tradingview/…Qx4w",
"enabled": true,
"…": "…"
}
}url appears in this response and in POST /v1/alert-hooks/{id}/rotate, and nowhere else. Every
other endpoint shows urlHint.
| Endpoint | What it does | Scope |
|---|---|---|
GET /v1/alert-hooks | List hooks | trading:read |
POST /v1/alert-hooks | Create one; returns url once | trading:execute |
GET /v1/alert-hooks/{id} | Read one | trading:read |
PATCH /v1/alert-hooks/{id} | Change name, accounts or defaults — the URL stays | trading:execute |
POST /v1/alert-hooks/{id}/rotate | New URL, returned once; the old one stops at once | trading:execute |
POST /v1/alert-hooks/{id}/disable | Pause: alerts are refused and logged | trading:reduce |
POST /v1/alert-hooks/{id}/enable | Resume | trading:execute |
DELETE /v1/alert-hooks/{id} | Delete; the URL stops working for good | trading:execute |
GET /v1/alert-hooks/{id}/deliveries | Every alert received and what became of it | trading:read |
2. Set up the alert in TradingView
Open the alert dialog
On the chart, open Create alert (the alarm-clock icon, or Alt+A). For a strategy, choose the strategy as the Condition; for an indicator or a drawing, choose it and the crossing or level you want.
Write the message
In Message, paste one of the messages below. TradingView replaces the {{…}} placeholders when
the alert fires.
Paste the URL
Under Notifications, tick Webhook URL and paste the hook's URL.
Create it and check the log
Save the alert. When it fires, it appears under Console → TradingView → your hook within a second, with its result. TradingView's own alert log has a webhook status column too.
3. Messages
A message can be JSON or a line of text; TradingView sends JSON as application/json and anything
else as text/plain, and fxapis reads both.
Indicators and drawings
An indicator alert knows nothing about positions, so it sends a fixed action. Make one alert per direction:
{ "action": "buy", "symbol": "{{ticker}}", "id": "{{ticker}}-{{timenow}}" }{ "action": "sell", "symbol": "{{ticker}}", "id": "{{ticker}}-{{timenow}}" }Add levels or a volume if the alert knows them:
{ "action": "buy", "symbol": "{{ticker}}", "volume": "0.20", "sl": "2310.5", "tp": "2385", "id": "{{ticker}}-{{timenow}}" }Strategies
One alert covers every entry, exit and reversal of a strategy:
{
"action": "{{strategy.order.action}}",
"symbol": "{{ticker}}",
"position": "{{strategy.market_position}}",
"prev_position": "{{strategy.prev_market_position}}",
"id": "{{strategy.order.id}}-{{timenow}}"
}{{strategy.order.action}} alone cannot tell an exit from an entry — closing a long is a sell. So
when position is present, the position after the order decides:
position after the order | prev_position | What fxapis does |
|---|---|---|
flat | anything | Closes every open position on the symbol |
short | long (a reversal) | Closes the symbol's positions, then sells |
long | short (a reversal) | Closes the symbol's positions, then buys |
| same side as the order | flat or the same side | Opens (an entry, or adding to one) |
| opposite side to the order | the same | Ignored — a partial exit. Logged, not traded |
Partial exits are not traded because there is no single honest MT5 translation: on a hedging account a "sell 1 of 3" could close part of a position or open a hedge, and guessing wrong is worse than doing nothing. Exit fully, or let stops take partial profits.
Volume is lots, not contracts
TradingView sizes forex strategies in units: {{strategy.order.contracts}} is 100000 for what
MT5 calls one lot. The template above sends no volume, so the hook's default lots are used. Send
volume only if it is in lots. Anything above 1000 lots is refused as a units mistake.
Plain text
Action, symbol, optional volume, then optional key=value pairs:
buy {{ticker}} 0.10
sell {{ticker}} 0.10 sl=1.1050 tp=1.0900 id={{timenow}}
close {{ticker}}
close_allFields
| Field | Also accepted as | Meaning |
|---|---|---|
action | side, signal | buy (long), sell (short), close (exit), close_long, close_short, flat, close_all |
symbol | ticker | Usually {{ticker}}. Mapped as described below. Not needed for close_all |
volume | qty, lots, contracts | Lots, e.g. "0.10". Default: the hook's volume |
sl | stopLoss, stop_loss | Absolute price. 0 means none |
tp | takeProfit, take_profit | Absolute price. 0 means none |
id | alert_id | Unique per alert — see duplicates |
position | market_position | {{strategy.market_position}} |
prev_position | prev_market_position | {{strategy.prev_market_position}} |
comment | Written on the MT5 order (first 31 characters). Default TradingView |
Numbers may be sent as JSON numbers or strings. Placeholders you might use: {{ticker}},
{{exchange}}, {{close}}, {{time}}, {{timenow}}, {{interval}}, and in strategies
{{strategy.order.action}}, {{strategy.order.contracts}}, {{strategy.order.price}},
{{strategy.order.id}}, {{strategy.order.comment}}, {{strategy.market_position}},
{{strategy.prev_market_position}}, {{strategy.position_size}}.
Quote your placeholders
"volume": {{strategy.order.contracts}} is valid JSON only if the placeholder fills in. Quoted
("{{…}}") it always is. A message that is almost JSON is refused with a reason saying so.
Symbols
In order:
- Exchange prefix removed —
OANDA:XAUUSDbecomesXAUUSD(unless you turn this off). - Symbol map — if the map names the symbol, its value is used exactly:
XAUUSD→XAUUSD.a. - Suffix — otherwise the suffix is added: with
.a,EURUSD→EURUSD.a.
The symbol the alert resolved to is shown on every delivery, so a wrong mapping is easy to spot.
Closing
| Action | Closes |
|---|---|
close, flat (or a strategy going flat) | Every open position on the symbol, buys and sells, on each of the hook's accounts |
close_long / close_short | Only the symbol's buys / only its sells |
close_all | Every open position on the hook's accounts, every symbol |
Closing acts on the positions the account holds, not only on those an alert opened: MT5 does not
record who opened a position in a way that can be trusted, and "close XAUUSD" meaning "close the
XAUUSD I can see" is what traders expect. Positions are read fresh from the terminal first. Each
position closed is its own order in your history. With nothing open, the alert is logged as
ignored.
Turn Act on close alerts off ("allowClose": false) if you exit with stops only — close actions
are then logged as ignored, and reversals are ignored too.
Closing is never refused for your plan's limits: you can always get flat.
Duplicates
TradingView fills {{timenow}} once, when the alert fires, so a resend of one alert carries the same
id and a new alert a new one. fxapis sends each id once: a repeat is answered 200 with
"status": "duplicate", logged, and not traded — even if the copies arrive at the same moment.
Without an id, the same message twice within 60 seconds is treated as one alert. That also
means two genuinely separate identical alerts within a minute are traded once — another reason to
include an id.
Security
- The URL is the credential. 32 random bytes, shown once, stored only as a SHA-256 hash. Anyone holding the URL can trade the hook's accounts, so keep it out of screenshots and shared templates. Rotate if it leaks: the old URL stops working at once.
- Only from TradingView (on by default) refuses any request not sent from TradingView's
published webhook addresses:
52.89.214.238,34.212.75.30,54.218.53.128,52.32.178.7. Turn it off only to send test alerts from your own machine. - Pause a hook to refuse its alerts without touching TradingView. Delete it to end the URL for good; its orders stay in your history.
- Alerts go through exactly the checks an API order does: the account must be able to trade, your plan must allow it, and nothing is sent while trading is switched off for your workspace.
- Don't put secrets in alert messages. The message is stored (up to 2 KB) with each delivery so you can see what arrived; if you paste the hook URL into a message, it is removed before storing.
Troubleshooting
Alerts that reach a hook are listed under Console → TradingView → your hook (or
GET /v1/alert-hooks/{id}/deliveries) for 30 days, with a status and a reason in plain words.
Past 30 alerts a minute, only one row a minute is recorded:
| Status | Meaning |
|---|---|
pending | Received; the order is being sent |
accepted | At least one order reached the broker. Each order's own result — filled, or rejected by the broker with its reason — is in the order history |
rejected | Nothing was sent. The reason says why |
duplicate | A repeat of an alert already taken |
ignored | Understood and deliberately not traded: a partial exit, nothing to close, closing switched off, an unknown action |
What TradingView sees:
| HTTP | Meaning |
|---|---|
202 | Taken; the order is being sent |
200 | Duplicate or ignored — nothing more will happen |
400 INVALID_ALERT | The message could not be read — see the reason |
403 SENDER_NOT_ALLOWED | Not from TradingView's addresses |
404 | No such hook — a mistyped, rotated or deleted URL |
409 HOOK_DISABLED | The hook is paused |
429 RATE_LIMITED | More than 30 alerts in a minute |
Common causes:
- Nothing in the list at all — the alert did not reach us. Check the URL was pasted whole, that
Webhook URL is ticked, and TradingView's alert log. A rotated or deleted URL answers
404. rejected— not from TradingView's addresses — you sent a test with curl or another tool. Turn off Only from TradingView while testing.rejected— the account is offline / not ready — the account was not connected. Keep it always connected, or check it under Accounts.- The broker rejected an unknown symbol — the resolved symbol is shown on the delivery; add a symbol map entry or a suffix.
rejected— plan limits — the month's orders are used up, or several accounts on a plan without multi-account orders.
Limits
- 30 alerts a minute per hook. Past that, alerts are refused with
429, and one row records it. - 25 hooks per workspace.
- Market orders only from alerts, with optional stop loss and take profit. Pending orders go through the API.
- One account per hook on every plan; several accounts on plans with multi-account orders — up to the plan's accounts-per-order limit.
- Alerts are orders: they count towards the plan's monthly orders.
- Deliveries are kept 30 days. Orders stay in the order history.
- fxapis answers TradingView immediately — TradingView cancels a webhook request that takes longer than three seconds (About webhooks, checked 30 September 2026) — and sends the order just after, in the order alerts arrived for that hook.
Idempotent MT5 orders: never double-fill on retry
Why retrying a MetaTrader 5 order can open a second position, and how the fxapis Idempotency-Key prevents it: 24-hour keys, replays, in-flight and reuse conflicts, the unknown outcome, and key patterns for signals, copiers and queues.
MCP server: let Claude, Cursor, VS Code and other AI agents trade MT5
Connect an AI assistant or agent to fxapis over the Model Context Protocol. Setup for Claude, Claude Code, Claude Desktop, Cursor, VS Code and the OpenAI and Anthropic APIs, the full tool reference, and the safety model for letting an agent near a real MetaTrader 5 account.