Your Pine script finds the signal. The graph decides what to do about it.
You already have the signal. It is a Pine script you have tuned, you trust it, and you are not looking to rewrite it. What you want is for the trade that follows to be a good one.
When my script fires, size the position against current volatility — not a fixed quantity I typed in months ago. Skip it if the daily trend disagrees. Skip it if I am already exposed to this move through a correlated pair. Skip it if I am two losses down today. And if the price has run more than half a percent since the alert was generated, do not chase it.
Why this is hard with a webhook bridge
A bridge treats the alert as a decision already made. It arrives, it becomes an order. There is no room between the two, because a pipe has no middle.
So every filter above has to go back into Pine — and Pine cannot see any of the things those filters need.
| The filter needs to know | Pine can see it? |
|---|---|
| Current volatility on this chart | Yes |
| Your open positions on other pairs | No |
| Your realised P&L today, across all strategies | No |
| Your exchange balance and margin state | No |
| Whether the last three alerts already fired | Barely, and not across scripts |
| How far price moved between alert and arrival | No |
Pine knows about charts. It does not know about your account. That is the whole problem. The portfolio-aware half of your strategy has nowhere to live, so it ends up living in your head — you watch the fills come in and intervene when something looks wrong, which is the opposite of automation.
The graph
The webhook is a node at the top, not a pipe at the end.
- Verification comes first.
- The alert is checked against a shared secret before it reaches any logic — an HMAC signature over the body, with a timestamp so a captured request cannot be replayed. A webhook URL on the open internet that fires orders needs more than a hard-to-guess path.
- Acknowledge fast, work after.
- The node returns 200 as soon as the payload is accepted, not after the strategy has run. TradingView times out in seconds, and a timeout is read as a failure and retried — which is how one alert becomes three orders.
- Duplicates are dropped.
- Put an id in your alert body and the graph discards a repeat. Retries are normal; double positions should not be.
- Every rejection is a visible node.
- When a trade does not happen, the graph shows which filter stopped it and what the value was.
The daily-loss veto in that chain is not local to this graph — it reads the account-wide guard described in one risk limit across everything.
Setting up the alert
Point your TradingView alert at the node's URL and write the body yourself:
{
"signal": "long",
"symbol": "BTCUSDT",
"price": {{close}},
"timeframe": "15m",
"id": "{{timenow}}-btc-long"
}Nothing about position size is in there, deliberately. The chart does not know what size is appropriate — your account does.
What you see while it runs
Alerts arrive on a visible edge. You watch one enter, travel through the filters, and either reach the order node or stop at the guard that refused it.
The common failure mode with a bridge is silent: the alert fired, no fill appeared, and you cannot tell whether the webhook failed, the exchange rejected it, or the position was already open. Here, the alert either shows up at a node or it never arrived, and those are different pictures. The same graph without the order on the end is signal routing and alerts — filtering and delivery, no keys involved.
Variations on the same shape
- Several scripts into one graph.
- Multiple alerts, each its own webhook node, sharing one risk guard and one exposure model.
- Alert as a filter, not a trigger.
- Let the alert set a state the graph reads, rather than firing a trade directly.
- Outbound reporting.
- A second webhook node posting fills and vetoes to Discord, so you find out without opening anything.
- Paper first.
- Run the identical graph against a testnet venue and compare what it would have done with what your script expected.