Signal Flow and Processing
This page explains what happens to a webhook signal between the moment TradingView (or your own script) sends it and the moment an order reaches your exchange. Knowing the order of the checks makes it much easier to understand why a signal was accepted, skipped or rejected.
Webhook endpoint
POST https://api.optalgo.com/signal-listener/signal
Content-Type: application/json
The endpoint is /signal-listener/signal. Older versions of this documentation showed https://api.optalgo.com/signal, which does not exist. If your TradingView alerts use the old address, update them.
Responses
| Status | When |
|---|---|
204 No Content | The signal was received and processed. This includes signals that were rejected or skipped by a check further down the pipeline. |
400 Bad Request | strategy_key is missing (Strategy key is empty.) or cannot be decoded (Invalid strategy key.). |
422 Unprocessable Entity | The body is not valid JSON for the signal model, for example position_side is missing. |
Because a rejected signal still answers 204, a successful HTTP response only means "OptAlgo received it". To know what happened, look at the bot's logs and notifications in the OptAlgo app. Every rejection reason described below is written there.
Processing order
Each signal is processed for one bot (the bot whose strategy_key it carries). The checks run in this order; the first one that fails decides the outcome.
- Key check. The
strategy_keyis decoded into your user and bot. Missing or invalid keys are answered with400. - Input validation. Field lengths, the
transaction_idformat and negative prices are checked. A negativetake_profit_priceon a webhook signal is dropped (set to empty) and you are notified; other negative prices are reported. - Bot lookup. If the bot does not exist or was deleted, the signal is rejected with
Strategy not found. AVALIDATE_ALERTwaits 30 seconds and looks again, so you can create the alert while the bot is still being created. - Multi-symbol routing. If the key belongs to a multi-symbol bot, the signal is routed to the child bot for its
ticker. A child is created on the ticker's first entry, a position slot is reserved, and the entry is sized on one slot. See Multi-symbol bots for the rules. - Auto bot setup. An auto bot that has not received a signal yet takes its exchange, symbol and market type (Spot, or Futures for a
.Pticker) from its first entry orVALIDATE_ALERT. Exit signals that arrive before that are skipped, because there is nothing to close. - Bot active. A stopped bot rejects new entries (
Strategy deactivated). You are notified once; later signals are skipped quietly until you start the bot again. - Safety check (
VALIDATE_ALERTwithin_position). The heartbeat settings are stored and the position state is compared. If TradingView says you are flat but OptAlgo holds an open trade, the signal becomes aCLOSE. See Safety checks. - Ticker must match the bot. For a single-symbol bot, every signal, exits included, must carry the bot's symbol in
ticker. Otherwise it is rejected withSignal symbol does not match strategy symbol. A mismatch never changes the bot's verified state. - Plan and quota. Your plan is checked. Plus and Pro plans have no monthly trade limit for your own bots. On the Free plan, a monthly limit for live trades and a separate limit for paper trades apply. When the plan check fails, new entries are rejected (
subscription_not_found_or_expired_or_monthly_limit_reached),UPDATE_ORDERandCHANGE_DIRECTIONare reduced to aCLOSE, and the bot is stopped. ForLONGandSHORTthis step also checks that the stop loss is on the correct side of the take profit and thatactionisBUYorSELL. - Account state. A deleted or deactivated user account receives no new entries. Exits still go through.
- Exchange connection. A live bot needs an active connection to its exchange (
Connection not found). Paper bots do not need one. - Exchange match. The signal's
exchangemust match the bot's exchange. Case does not matter. Otherwise:Exchange not found or does not match with strategy. - Ticker exists in the market type. The ticker is looked up on the bot's exchange and market type. If it exists only in the other market type (for example
BTCUSDTon a Futures bot), the rejection tells you which symbol to use. If it does not exist at all:Ticker not supported or not found. - Verification. The first valid signal marks a new bot as verified, and you are notified.
- Adjustments. Stop and take-profit floors, leverage and margin mode are applied (see Automatic adjustments), and alias position types are converted (see Conversions).
- Spot shorts. A
SHORTon a Spot bot is rejected. Use the.Pfutures ticker on a Futures bot instead. - Dispatch. The signal is queued for execution. An unverified bot dispatches nothing except exits for an open trade (see Exit pass).
After dispatch, the execution service places the orders on the exchange. It records each attempt, retries temporary failures, and protects the position with its stop loss. See Reliability and safety.
Exit pass
Several checks exist only to stop new risk: a stopped bot, a paused or stopped subscription, an expired plan, or an unverified bot. These checks must never leave an open position without its exit or its stop. So when you already have an open trade on the bot, exit and protective signals pass them:
| Signal | Behavior when an open trade exists |
|---|---|
CLOSE, FLAT, CANCEL, CLOSE_LONG, CLOSE_SHORT, CLOSE_ALL, CLOSE_PARTIAL | Passes the gate and closes as requested. |
MOVE_STOP_LOSS, SET_ORDERS | Passes the gate and moves the protective orders. |
UPDATE_ORDER, CHANGE_DIRECTION | Only the exit half is executed: the signal becomes a CLOSE. |
Entries (LONG, SHORT and the entry half of the replace signals) keep every gate. Without an open trade, nothing is bypassed. The exit pass does not bypass the ticker, exchange or connection checks: an exit must still name the bot's own symbol and exchange.
Multi-symbol routing
For a multi-symbol bot, the ticker decides which child bot handles the signal:
- Entry for a new ticker: the platform checks the plan's position cap and reserves a free slot. Then it creates the child bot for that ticker and sizes the entry on one slot (budget divided by max positions). If all slots are taken, the entry is rejected with
Max positions (N) reached ...and the message lists the open tickers. - Entry for a ticker that is already open or reserved: uses its existing slot.
- Exit for a ticker: goes to that ticker's child bot. An exit for a ticker the bot has never traded is skipped (
No ... position on this multi-symbol bot).
Details: Multi-symbol bots.
Position side conversions
| Sent | Executed as | Notes |
|---|---|---|
FLAT, CANCEL, CLOSE_LONG, CLOSE_SHORT | CLOSE | |
CLOSE with close_ratio below 1 | CLOSE_PARTIAL | |
CLOSE_LIMIT_ORDER | MOVE_STOP_LOSS | |
SET_ORDERS | MOVE_STOP_LOSS | processing_delay defaults to 3 seconds |
CHASE_LIMIT_UPDATE | CHASE_LIMIT | chase_order_type defaults to QUEUE |
CHANGE_DIRECTION | closes every open trade of the bot, then opens the new position |
position_side and action are case-sensitive: use upper case (LONG, BUY). TradingView placeholders such as {{strategy.order.action}} produce lower case (buy) and cannot be used for action directly.
Automatic adjustments
Stop and take-profit floor
For a LONG (or UPDATE_ORDER) with action: BUY, a stop_loss_price below 1% of entry_price is raised to 1% of entry_price. For a SHORT (or UPDATE_ORDER) with action: SELL, a take_profit_price below 1% of entry_price is raised the same way.
Leverage and account leverage
If your exchange connection has an account leverage configured, and the signal carries both leverage and tradable_ratio above 0, both are rescaled:
effective_leverage = leverage * account_leverage
effective_tradable_ratio = tradable_ratio / account_leverage
The product of leverage and ratio, and therefore the position's notional size, stays the same. Only the margin used changes.
Margin mode
The signal's margin_mode wins. Without it, the connection's margin mode is used, and isolated is the default. A connection in Binance BNFCR mode always uses cross margin with multi-asset mode.
Processing delay
processing_delay (seconds) waits before the signal is queued. SET_ORDERS uses 3 seconds when no delay is given.
Tracking a signal
- Correlation ID: each signal gets a unique id that follows it through the listener and the execution service. It appears in the logs.
- Transaction ID: an optional id you can send. The execution service creates one when an entry has none, and it uses the id to group the orders of a trade. See
transaction_id. - Logs: every decision (accepted, skipped with a reason, rejected with a reason) is written to the bot's logs in the app.
Next Steps
- Troubleshooting - What each rejection means
- My Bots - Single, auto and multi-symbol bots
- Reliability and safety - What happens after dispatch