Not every strategy ends in an order
You have a signal source you trust and an execution habit you are not ready to hand over. What is missing is the layer in between: something that filters, confirms and formats, and that you can see working.
When my script fires, check that the daily trend agrees and that the 4-hour RSI is not already stretched. Ignore anything I have already been alerted about in the last fifteen minutes. Then POST what is left wherever I want it — my Telegram bot, my Discord channel, my own service — with the reason attached, and never touch my exchange account.
Why this is hard today
Filtering a signal and delivering it somewhere are both easy. Doing both, in that order, with a condition in between, is where the existing options run out.
| What you would use | What it cannot do |
|---|---|
| TradingView alerts straight to Discord | No confirmation across timeframes, no cooldown, no shaping — every alert goes through |
| A webhook-to-order bridge | Turns the alert into a trade; there is no branch where it is only a message |
| A Python script on a VPS | Does all of it, and you now own a server, a deploy and a 2am restart |
| Zapier or Make | Fine at plumbing, blind to candles, indicators and market state |
The trap is the second condition. One filter fits in an alert message. The moment your filter needs a second timeframe, or memory of the last alert you sent, the no-code options are out and you are writing software — for a job that is not really software, it is a strategy with a delivery step on the end.
The graph
One inbound webhook, four checks that can stop it, and three outbound requests.
The three nodes at the bottom are the same node type three times. What differs between them is a URL, a header and a body — not a different integration, and not a different part of the product.
What gets sent
{
"symbol": "BTCUSDT",
"side": "long",
"timeframe": "5m",
"received_at": "2026-08-28T09:14:22Z",
"passed": ["freshness", "daily_trend", "rsi_4h", "cooldown"],
"note": "daily EMA200 rising, 4h RSI 58.2",
"signature": "sha256=…"
}The body is yours. That shape is the default, and the node sends whatever method, headers and body you give it — so a Telegram sendMessage call, a Discord webhook and your own service each get the format they expect, from the same graph.
A chat message is a rendered version of the same object, which is the point of sending both: the line a human reads and the payload a machine reads cannot drift apart, because there is only one of them.
No keys, no exposure
- No exchange credentials
- This graph has no action that needs one, so nothing asks for one. Connecting an exchange is something a graph opts into by having an order in it.
- Nothing custodial, ever
- anvas never holds funds under any configuration — with a key connected or without.
- Signed both ways
- Inbound webhooks verify an HMAC you set, so a leaked URL is not a way in. Outbound requests can be signed too, so your endpoint can tell that it was us.
- The same trace as a live graph
- Every dropped signal shows the node that dropped it and the value it saw, exactly as a fill does. See glass box.
When you do want it to trade
Add an order node on the end. Nothing else about the graph changes — the same confirmation group, the same cooldown, the same trace — and the alert branch keeps running beside it, so you get the message whether or not the order fires.
That is the version with sizing and portfolio-aware risk in it: TradingView alerts with a strategy in between.