Send TradingView alerts to MT4 and MT5
Paste one Tickwire URL into a TradingView alert and each alert becomes a checked, recorded order on your MT4 or MT5 account. Size by risk, set stops in points or pips, and a repeated alert never trades twice.
A signal webhook is a private URL for one trading account. TradingView posts the alert message to it, and Tickwire turns that message into orders. Every order goes through the same checks as the rest of the API: idempotency, your kill switch, your pre-trade hook and the audit log.
TradingView only sends webhooks on a paid plan. On the free plan the “Webhook URL” box is not available. TradingView may also ask you to turn on two-factor authentication first.
Set it up in the dashboard
You do not need the command line. In the dashboard, open TradingView alerts (or press TradingView alerts on an account’s page).
- Press New webhook. Pick the account and give the webhook a name.
- Say what sends the alerts: a strategy or an indicator.
- Choose the position size, the stop loss and the take profit, and what happens when a new alert arrives. Limits and symbol names are optional and start off.
- Press Create webhook. Copy the URL now. It works like a password and is shown only once.
- Copy the alert message the page gives you.
- In TradingView, create the alert, tick Webhook URL, paste the URL, and paste the message into the Message box.
Each webhook lists its last alert. Press Recent alerts to see every alert and its outcome. From the same list you can edit, pause, get a new URL or delete a webhook. Creating and changing webhooks needs an admin or owner.
The rest of this guide shows the same steps with the API, and every field an alert can send.
1. Create a webhook
Create one webhook per account and strategy. Use a full API key (X-API-Key) or a dashboard
session.
curl -X POST https://api.tickwire.io/v1/signal-webhooks \
-H "X-API-Key: $TICKWIRE_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: create-gold-trend" \
-H "X-Reason: TradingView gold trend strategy" \
-d '{
"account_id": "acc_123",
"name": "Gold trend",
"symbol_map": {"XAUUSD": "GOLD"},
"sizing": {"mode": "risk_pct", "risk_pct": 1},
"stops": {"sl": {"type": "pips", "value": 30}, "tp": {"type": "r", "value": 2}}
}'
The answer has token, path and url:
{
"id": "swh_9f2c",
"name": "Gold trend",
"account_id": "acc_123",
"token_prefix": "twsig_Ab3dEf",
"token": "twsig_Ab3dEf...",
"path": "/v1/signals/twsig_Ab3dEf...",
"url": "https://api.tickwire.io/v1/signals/twsig_Ab3dEf...",
"enabled": true
}
Copy the url now. It is shown once. Tickwire stores only a hash of the token, so nobody can
show it to you again. If you lose it, rotate the webhook to get a new one.
Running the same command again with the same Idempotency-Key returns the same webhook, but
token, path and url are null, with a token_notice that says why. Use
POST /v1/signal-webhooks/{id}/rotate to get a new URL. url is also null if no public API
address is set on our side. Then build it from path: https://api.tickwire.io plus path.
The URL is the password. Anyone who has it can send alerts to this account. Keep it out of screenshots, chat and public scripts.
2. Paste the URL into TradingView
- Open the chart and create an alert (the clock icon, or right click on the chart).
- Pick the condition: your strategy, or an indicator.
- Open the Notifications tab and tick Webhook URL.
- Paste the Tickwire
url. - Paste one of the messages below into the Message box.
- Save the alert.
3. Pick the message
The shortest message
All other values come from your webhook settings.
{"symbol": "{{ticker}}", "action": "{{strategy.order.action}}"}
Buy with 1% risk, a stop at a price, and a target at 2R
{"symbol": "{{ticker}}", "action": "buy", "risk_pct": 1, "sl": {{plot("Stop")}}, "tp_r": 2}
Tickwire sizes the trade so that a hit stop loses 1% of your balance. tp_r: 2 puts the take
profit twice the stop distance away.
Strategy alerts: target position
Tell Tickwire where the position should be, not what to do. If the same alert arrives twice, the second one finds the position already there and sends nothing.
{
"symbol": "{{ticker}}",
"market_position": "{{strategy.market_position}}",
"market_position_size": "{{strategy.market_position_size}}",
"alert_id": "{{strategy.order.id}}-{{timenow}}"
}
market_position is long, short or flat. Tickwire reads the webhook’s open positions on that
symbol and sends only the orders needed to reach the target.
TradingView sizes strategies in its own units. If your strategy trades 100000 units of EURUSD per
lot, set the sizing multiplier to 0.00001 so that 100000 becomes 1 lot.
Indicator alerts
Indicators have no strategy placeholders, so write the action yourself. Make one alert per direction.
{"symbol": "{{ticker}}", "action": "buy", "risk_money": 50, "sl_pips": 20, "tp_pips": 40}
{"symbol": "{{ticker}}", "action": "close"}
Manage an open trade
{"symbol": "{{ticker}}", "action": "close_pct", "pct": 50}
{"symbol": "{{ticker}}", "action": "breakeven", "offset_points": 10}
{"symbol": "{{ticker}}", "action": "move_sl", "sl_points": 150}
Alert fields
Every field is optional except symbol, and action or a position. Field names are case
sensitive. Where a field has two names, the first one present is used.
{
"symbol": "EURUSD", // or "ticker". "FX:" and other prefixes are dropped.
"action": "buy", // or "side" or "order_action". See the actions below
"position": 0.5, // a target position: signed, or with "side"
"alert_id": "{{timenow}}-1", // or "signal_id" or "client_id". One id per alert: the best way to make a repeat harmless.
"time": "{{timenow}}", // used by the max alert age limit
// size: send one of these
"risk_pct": 1, // % of your risk basis (balance, equity or a fixed amount)
"risk_money": 100, // the loss at the stop, in the account currency
"lots": 0.10, // fixed lots ("volume", "lot", "qty", "quantity", "contracts" and "size" work too)
"multiplier": 0.5, // scales lots or a target sent in the alert
// stop loss: send one of these
"sl": 1.08500, "sl_points": 200, "sl_pips": 20, "sl_pct": 0.5,
// take profit: send one of these
"tp": 1.09500, "tp_points": 400, "tp_pips": 40, "tp_pct": 1.0, "tp_r": 2,
// trade management
"pct": 50, // for close_pct ("percent" works too)
"offset_points": 10, // for breakeven
"comment": "breakout" // the order comment. A longer one is cut to 20 characters
}
Sending two of one kind, such as lots and risk_pct, is refused with conflicting_fields.
0 for a stop or target means none.
| Action | What it does |
|---|---|
buy, sell | Open a new trade. Your opposite and same-side settings decide what happens to trades already open. |
long, short | A target position, harmless to repeat. |
close, flat, exit | Close every trade of this webhook on the symbol. |
close_long, close_short | Close one side only. |
close_pct | Close a share (pct) of the open lots, newest trades first. |
move_sl, move_tp | Move the stop loss or take profit of open trades. |
breakeven | Move the stop loss to the entry price, plus offset_points. |
cancel | Cancel this webhook’s pending orders on the symbol. |
TradingView sends numbers inside quotes as text. That is fine: "0.1" and 0.1 mean the same.
Some values are never taken from an alert: the account, the magic number, your limits, the symbol
map and the risk basis. If an alert sends them, they are listed in ignored and not used.
If a {{placeholder}} reaches Tickwire unfilled, the alert is refused with placeholder_not_filled
and nothing is sent. This usually means a strategy placeholder was used in an indicator alert.
How risk sizing works
Tickwire works out the size from the live quote, not the alert’s price:
- Risk money is your basis times
risk_pct, orrisk_moneyas sent. - The entry is the ask for a buy and the bid for a sell.
- The loss for one lot is the stop distance in ticks times the terminal’s tick value.
- Lots are risk money divided by the loss for one lot, rounded down to the volume step.
Tickwire never rounds a size up. If the size is below the symbol’s minimum, the alert is refused
with size_below_min_volume and the answer says how much risk the minimum needs. Above the
broker’s maximum, the size is capped and the answer says so.
Risk sizing needs a stop loss. No stop means no trade (stop_loss_required).
The answer shows the working in sizing, and a short summary line:
Bought 0.2 lots EURUSD. Planned loss at stop: 100.00 USD of 100.00 USD (1% of balance). Before costs.
The planned loss is before costs. Spread, commission and slippage are not included. On MT4 the
terminal has one tick value for profit and loss, so MT4 sizes are marked mt4_approximate.
pips work on forex symbols only. For an index or a metal, use points.
Webhook settings
Set these on create, or change them later with PATCH /v1/signal-webhooks/{id}. A group you send
is merged field by field. A field sent as null goes back to its default.
Alert values
The sizing, stops and management groups each have use_alert_values:
true: Use alert values when sent. The alert’s own values win. Your settings fill the gaps.false: Always use these settings. The alert’s values for that group are ignored and listed inignored.
The answer’s sources says where each value came from: alert or dashboard.
Position size (sizing)
How big each trade is. Risk % sizes the trade so a stop-loss hit loses that share of your balance.
| Field | Default | Meaning |
|---|---|---|
mode | lots | lots, risk_pct or risk_money. |
lots | none | Fixed lots. |
risk_pct | none | Risk per trade, in %. |
risk_money | none | Fixed cash risk per trade, in the account currency. |
risk_basis | balance | balance, equity or fixed. |
fixed_amount | none | The basis for fixed. Use your starting balance for prop accounts. |
multiplier | 1 | Scales a size sent in the alert. |
Stops (stops)
| Field | Default | Meaning |
|---|---|---|
sl | none | Default stop loss, used when the alert has none. {"type": "pips", "value": 20}. Types: price, points, pips, pct. |
tp | none | Default take profit. The same types, plus r: a multiple of your stop (2R is twice the stop). |
require_sl | false | Refuse any new trade without a stop loss. |
A stop on the wrong side of the price is refused with stop_wrong_side. A stop closer than the
broker allows is refused with stop_too_close.
Trade management (management)
| Field | Default | Meaning |
|---|---|---|
on_opposite | reverse | A signal against an open trade. reverse: close it and open the new one. close: close only. ignore: do nothing. keep_both: open the new one too. |
on_same_side | ignore | A signal in the same direction. ignore if already in, or add up to max_entries. |
max_entries | 2 | Most trades on one side, with add. |
close_pct | 50 | The share close_pct closes when the alert sends no pct. |
breakeven_offset_points | 0 | The offset breakeven uses when the alert sends none. |
Limits (limits)
Tickwire sets no limits. Add your own. Each one is off until you set it.
| Field | Meaning |
|---|---|
max_lots_per_order | Max lots per trade. With over_max_lots: "reject" (the default) a bigger trade is refused. With "cap" it is cut to the limit. |
max_risk_pct | Max risk per trade, in % of your basis. A trade without a stop is refused. |
max_open_positions | Max open trades for this webhook. |
max_open_positions_per_symbol | Max open trades for this webhook on one symbol. |
trading_hours | {"timezone": "Europe/London", "start": "08:00", "end": "16:00", "days": ["mon", "tue", "wed", "thu", "fri"]}. New trades outside these hours are refused. Closing still works. |
max_spread_points | New trades are refused when the spread is wider. |
max_alert_age_s | Alerts older than this are refused. The alert must send time. |
allowed_sides | both, long or short. On a reversal the close still runs and the new trade is skipped. |
Other settings
| Setting | Default | Meaning |
|---|---|---|
name | A label for you. | |
symbol_map | {} | TradingView symbol to broker symbol, for example {"XAUUSD": "GOLD"}. |
symbol_suffix | none | Added to every symbol, for example .m. |
allowed_symbols | all | Only these symbols may trade. Others are refused with symbol_not_allowed. |
magic | random | The magic number on this webhook’s orders. |
comment | none | Default order comment. |
manage_others | false | Also manage other trades on this symbol. |
allow_netting_shared | false | On an MT5 netting account, allow trading a symbol that has trades from elsewhere. |
enabled | true | false pauses the webhook. |
Which trades a webhook touches
This webhook only touches trades it opened: those with its magic number on the alert’s symbol.
Trades you place by hand, or from other tools, are left alone. Turn on manage_others to manage
every trade on the symbol.
An MT5 netting account holds one position per symbol, so it can’t keep the webhook’s trades apart
from yours. If the symbol already has a position from elsewhere, the alert is refused with
netting_shared_symbol unless you turn on allow_netting_shared. keep_both and add need a
hedging account (hedging_required). MT4 accounts always keep trades apart.
Not part of signal webhooks
Signal webhooks do not run break-even at a set R, trailing stops, more than one take profit, ATR stops, time-based exits, daily loss limits or prop-firm rules. Use your pre-trade hook or your own tools for those.
What Tickwire answers
TradingView ignores the answer, but it is kept with the alert so you can read it later.
| Outcome | HTTP | Meaning |
|---|---|---|
applied | 200 | The terminal confirmed every order. |
no_change | 200 | Nothing needed doing. Nothing was sent. |
held | 202 | Your pre-trade hook is holding the next order for approval. It has not been sent. |
unknown | 200 | An order may have executed. The rest of the plan was not sent. Check your positions before doing anything else. |
rejected | 4xx or 5xx | Refused, with an error code. sent: false means nothing left Tickwire. |
Common error codes:
- Message:
invalid_json,symbol_required,action_required,invalid_action,placeholder_not_filled,invalid_signal,invalid_alert_time,conflicting_fields,volume_required,payload_too_large. - Sizing:
size_below_min_volume,tick_value_unavailable,stop_loss_required,pip_size_unavailable. - Stops:
stop_wrong_side,stop_too_close,take_profit_required. - Your limits:
above_max_lots,above_max_risk,max_open_positions_reached,side_not_allowed,outside_trading_hours,spread_too_wide,alert_too_old,alert_time_required. - Account:
signal_webhook_paused,kill_switch_engaged,hook_denied,symbol_not_allowed,symbol_not_found,netting_shared_symbol,hedging_required,too_many_positions. - Other:
signal_webhook_not_found,signal_in_flight,rate_limited.
See Errors.
Repeats never trade twice
TradingView can resend an alert, and alerts can fire twice on the same bar. Tickwire treats an alert as one order request:
- With an
alert_id, the same id always gets the first answer back, withreplayed: true. - Without one, the same message within about a minute is the same alert.
- The plan is saved before the first order. A repeat sends the same orders, at the same size. It is never re-sized from a newer quote.
- Target position messages are safe even beyond that, because a second alert finds nothing to do.
To send two identical orders on purpose, give each its own alert_id.
See what happened
curl "https://api.tickwire.io/v1/signal-webhooks/swh_9f2c/events?limit=20" \
-H "X-API-Key: $TICKWIRE_API_KEY"
Each event shows the parsed signal, the outcome, the sizing and every order step. The orders also
appear in the account’s audit log with the actor signal-webhook:<id>.
Stay in control
- Pause:
PATCH /v1/signal-webhooks/{id}with{"enabled": false}. Alerts are refused and nothing is sent until you turn it back on. - Rotate:
POST /v1/signal-webhooks/{id}/rotategives a new URL, shown once. The old URL stops working at once. Paste the new one into each TradingView alert. - Revoke:
DELETE /v1/signal-webhooks/{id}ends the webhook for good. - Kill switch and pre-trade hook: both apply to every alert, exactly as they do to the API and to AI agents. A held order waits for your approval. A denied one is never sent.
Rate limits
Each webhook accepts 60 alerts a minute, with bursts of 30. Alert messages can be up to 16 KiB. See Rate limits.
MT4 and MT5
The same URL and messages work on both. Sizing uses each terminal’s own tick value. The answer’s
steps show exactly what was sent.