View as Markdown

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).

  1. Press New webhook. Pick the account and give the webhook a name.
  2. Say what sends the alerts: a strategy or an indicator.
  3. 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.
  4. Press Create webhook. Copy the URL now. It works like a password and is shown only once.
  5. Copy the alert message the page gives you.
  6. 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

  1. Open the chart and create an alert (the clock icon, or right click on the chart).
  2. Pick the condition: your strategy, or an indicator.
  3. Open the Notifications tab and tick Webhook URL.
  4. Paste the Tickwire url.
  5. Paste one of the messages below into the Message box.
  6. 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.

ActionWhat it does
buy, sellOpen a new trade. Your opposite and same-side settings decide what happens to trades already open.
long, shortA target position, harmless to repeat.
close, flat, exitClose every trade of this webhook on the symbol.
close_long, close_shortClose one side only.
close_pctClose a share (pct) of the open lots, newest trades first.
move_sl, move_tpMove the stop loss or take profit of open trades.
breakevenMove the stop loss to the entry price, plus offset_points.
cancelCancel 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:

  1. Risk money is your basis times risk_pct, or risk_money as sent.
  2. The entry is the ask for a buy and the bid for a sell.
  3. The loss for one lot is the stop distance in ticks times the terminal’s tick value.
  4. 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 in ignored.

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.

FieldDefaultMeaning
modelotslots, risk_pct or risk_money.
lotsnoneFixed lots.
risk_pctnoneRisk per trade, in %.
risk_moneynoneFixed cash risk per trade, in the account currency.
risk_basisbalancebalance, equity or fixed.
fixed_amountnoneThe basis for fixed. Use your starting balance for prop accounts.
multiplier1Scales a size sent in the alert.

Stops (stops)

FieldDefaultMeaning
slnoneDefault stop loss, used when the alert has none. {"type": "pips", "value": 20}. Types: price, points, pips, pct.
tpnoneDefault take profit. The same types, plus r: a multiple of your stop (2R is twice the stop).
require_slfalseRefuse 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)

FieldDefaultMeaning
on_oppositereverseA 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_sideignoreA signal in the same direction. ignore if already in, or add up to max_entries.
max_entries2Most trades on one side, with add.
close_pct50The share close_pct closes when the alert sends no pct.
breakeven_offset_points0The 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.

FieldMeaning
max_lots_per_orderMax 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_pctMax risk per trade, in % of your basis. A trade without a stop is refused.
max_open_positionsMax open trades for this webhook.
max_open_positions_per_symbolMax 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_pointsNew trades are refused when the spread is wider.
max_alert_age_sAlerts older than this are refused. The alert must send time.
allowed_sidesboth, long or short. On a reversal the close still runs and the new trade is skipped.

Other settings

SettingDefaultMeaning
nameA label for you.
symbol_map{}TradingView symbol to broker symbol, for example {"XAUUSD": "GOLD"}.
symbol_suffixnoneAdded to every symbol, for example .m.
allowed_symbolsallOnly these symbols may trade. Others are refused with symbol_not_allowed.
magicrandomThe magic number on this webhook’s orders.
commentnoneDefault order comment.
manage_othersfalseAlso manage other trades on this symbol.
allow_netting_sharedfalseOn an MT5 netting account, allow trading a symbol that has trades from elsewhere.
enabledtruefalse 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.

OutcomeHTTPMeaning
applied200The terminal confirmed every order.
no_change200Nothing needed doing. Nothing was sent.
held202Your pre-trade hook is holding the next order for approval. It has not been sent.
unknown200An order may have executed. The rest of the plan was not sent. Check your positions before doing anything else.
rejected4xx or 5xxRefused, 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, with replayed: 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}/rotate gives 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.