Sentiment Filters and Signal Priority in Automated Entries
Learn how sentiment filters and signal priority work in automated trading entries, and why the arbitration decision must be built into your stack, not assumed.
Marketing
When two signals reach a webhook endpoint within the same second, nothing in the system decides which one wins. Whichever payload is processed first determines the position state, and the second may act on a state that no longer exists. This is not an edge case: it is the default behavior of every webhook-driven automation stack, and sentiment filters signal priority is a design problem you have to solve before signals are emitted, not after they arrive.
The fix is not faster infrastructure. It is a deliberate architecture: collapse conflicting logic upstream, use the sentiment field as a positional guard at execution time, and layer subscription-level gates that evaluate each signal on its own merits regardless of when it arrived. This article walks through each of those layers in order.
The concepts here apply to any webhook-driven system, but the field names and gate behaviors reference a specific implementation. Read each section with your own stack in mind and map the patterns to whatever controls you have available.
Nothing Sorts Conflicts for You
The race condition problem
When two signals arrive within the same second, the system has no built-in arbitration layer. Whichever payload reaches the broker first wins, and the second signal may attempt to act on a position that has already changed. This is documented plainly: signals sent in the exact same second with only milliseconds between them carry no guarantee that the first order will be sent and filled before the second is processed.
That is not a bug waiting to be patched. It is a structural property of webhook-driven systems. HTTP requests are not queued with execution-order guarantees by default, and adding a receiving layer between the alert source and the broker does not change that. The designer has to account for it.
Why higher timeframes reduce but don't eliminate the risk
Spacing signals at least one to five minutes apart reduces the probability of a collision, but it does not address the case where two independent strategies are trading the same ticker. Multi-strategy portfolios can generate genuinely simultaneous, conflicting signals even on daily charts when bar close times coincide. A regime-filter indicator and a trend-following strategy both watching the same symbol will both fire at the 4:00 PM bar close if their conditions are met.
Slowing signals down is not the solution. Deciding priority before signals are emitted is.
Put the Arbitration Upstream
Collapsing logic at the signal source
The cleanest arbitration point is the Pine Script strategy itself. When conflicting conditions are evaluated inside one script, only one alert fires per bar. The standard TradingView strategy payload sends one action and one sentiment per bar, and that single alert is the only signal the downstream system has to process. No race is possible because there is only one contestant.
Splitting logic across two indicators, each with its own alertcondition() call, reintroduces the race. Both can fire on the same bar close, and there is no mechanism inside TradingView or at the webhook receiver that serializes them with an execution order guarantee.
Regime filters as upstream gates
A regime filter, such as a trend classifier or a volatility state, belongs inside the strategy logic. When it is encoded as a condition inside the script, it suppresses the alert entirely when the regime is unfavorable. No signal is emitted, so there is nothing to arrive out of order.
A filter placed downstream, sent as a separate webhook payload, is itself a signal. It can arrive before or after the trigger it was meant to suppress, and the system has no way to know which came first. The upstream placement is the only design that makes the filter deterministic. A condition that blocks an alert inside Pine Script always runs before the alert fires, by definition.
Two Different Things Called Sentiment
Sentiment as a directional declaration
In the webhook payload, the sentiment field is a string that declares what the position state should be after the trade executes. The accepted values are bullish, bearish, and flat. This is not a sentiment-analysis score derived from news feeds or social data. It is a positional assertion supplied by the signal sender, evaluated at execution time against the current open position.
For TradingView strategies, the value maps directly to the {{strategy.market_position}} variable, which outputs long, short, or flat. The standard strategy payload template passes this through automatically, which is why a single strategy alert carries enough information for the receiving system to determine both the action and the intended resulting position.
Sentiment scores as regime inputs
External sentiment scores, such as those derived from options flow, market breadth indicators, or news-based models, are a different concept entirely. These scores are most useful as inputs to the regime filter that lives upstream in the strategy logic, deciding whether a signal is emitted at all. They are pre-signal data, not in-signal data.
Conflating the two concepts leads to a design where a sentiment score is sent as a second payload or a second signal, which puts it back in the timing race it was meant to resolve. The external score belongs in the condition block that decides whether strategy.entry() is called; the sentiment field in the payload reports the result of that decision.
Sentiment as a Veto on the Order
Flat sentiment and position exits
Sending action=sell with sentiment=flat exits a bullish position without opening a bearish one. The sentiment field overrides the directional implication of the action field. When sentiment is flat, the system exits the full quantity of the open position and does not enter a new position on the other side.
This makes flat sentiment a veto on the entry half of an action=sell signal. TradersPost evaluates the sentiment field at execution time: a flat value stops the order that would otherwise open the opposite side, giving the signal sender a deterministic veto without requiring a second payload.
The veto is clean because it operates within a single payload. There is no second signal to arrive out of order, no timing dependency between a close instruction and a suppress instruction. One payload carries both the action and the positional constraint.
Resize signals and directional guards
Including sentiment in a resize or partial-exit signal ensures the system does not interpret a quantity reduction as an entry on the opposite side. Because sentiment is evaluated against the current open position, it can also catch cases where the broker state has drifted from the expected state and prevent an unintended reversal.
The field is optional in the payload. Omitting it leaves the action field to determine direction without the positional guard. For partial exits where you want to reduce size without any risk of a flip, including sentiment=bullish or sentiment=bearish alongside the exit quantity is the safer pattern.
Gates That Run Regardless of Arrival Order
Allowed sides and isolate sides
The subscription-level allowed sides setting restricts which trade directions are accepted: bullish only, bearish only, both, or none. A signal for a disallowed direction is rejected before any order is created, regardless of when it arrived relative to other signals. The gate does not inspect the sequence of payloads; it evaluates each payload independently against a fixed configuration.
This makes allowed sides a deterministic priority gate. If a strategy is configured for bullish only and a bearish signal arrives, it is rejected. The rejection happens even if the bearish signal arrived after a bullish signal that has already been processed. Arrival order is irrelevant to the outcome.
Staleness cutoffs and trading windows
The rejectAfter field sets a maximum signal age in seconds, measured against the time field in the payload or the webhook receive time if no time field is present. The accepted range is 1-30 seconds. A signal that exceeds the cutoff is rejected before execution, preventing a delayed webhook from acting on a market condition that no longer exists.
Trading window settings in the subscription configuration reject signals that arrive outside defined hours, independently of the order in which signals arrive. A signal landing at 3:58 PM for a strategy with a window that closes at 4:00 PM executes; one landing at 4:01 PM is rejected. The window evaluation is time-of-receipt against a fixed schedule, not a comparison between signals.
Bid-ask spread filters
The bidAskSpreadFilter and bidAskSpreadFilterPercent fields set a maximum acceptable spread at execution time, not at signal generation time. These two fields cannot be combined in the same payload: sending both is invalid. A spread filter acts as a market-quality gate rather than a directional gate, but it runs at execution and therefore operates independently of signal arrival order. A signal that passes all other gates will still be rejected if the spread at the moment of order creation exceeds the configured threshold.
Signal Timing Controls
The expiresAt field
The expiresAt field accepts an ISO-8601 datetime after which the signal will not be executed. This is distinct from rejectAfter, which measures a relative age in seconds from the time field. expiresAt sets an absolute deadline: regardless of when the signal arrives or how long it spends in any queue, if the current time is past the specified datetime the signal is discarded.
Using expiresAt on entry signals ensures that a queued or delayed payload does not execute into a market session or price environment for which it was not intended. A signal generated at a daily bar close can carry an expiresAt set to the open of the next session, guaranteeing it does not execute late.
The delay field and cancelAfter
The delay field postpones execution by a specified number of seconds, a relative expression, or an absolute datetime. This gives other signals time to settle before the delayed one executes, which is useful when a second signal needs to act after a position has fully opened.
The cancelAfter field automatically cancels an unfilled entry order after a set number of seconds, preventing a stale limit order from filling into a market that has moved. Together, delay and cancelAfter can bracket the execution window of an entry signal: the order does not submit until after the delay, and it is canceled if it does not fill within the cancelAfter window. That window reduces the surface area where a conflicting signal could act on a partially open position.
A Priority Design That Holds Up
Consolidate to one signal source per ticker
Running two separate indicators on the same ticker through the same webhook doubles the race condition surface area. The safest design routes one strategy per ticker. If a regime filter is required, encode it as a condition inside the strategy rather than as a second indicator with its own alert. The filter then runs at the same bar evaluation as the entry logic, and only one alert fires when all conditions are met.
Batch signals allow a single webhook request to carry multiple payloads, but all signals in the batch are processed as individual signals. They do not guarantee sequential execution order. Batching is useful for acting on multiple tickers at once; it is not a solution to the arbitration problem on a single ticker.
Layer subscription gates for defense in depth
Subscription-level gates, including allowed sides, staleness cutoffs, trading windows, and spread filters, run after signal receipt and before order creation. They form a second arbitration layer that is independent of upstream logic. In TradersPost, these gates evaluate each signal on its own merits rather than on when it arrived, making them robust to timing noise in the delivery layer.
Combining a single-source signal with subscription-level gates produces a priority system that does not rely on arrival timing at any stage. The upstream logic prevents the conflict from occurring; the subscription gates catch anything that slips through due to logic errors or unexpected conditions at the broker. Neither layer depends on the other, so a failure in one does not collapse the whole design.
If your current setup uses two indicators alerting on the same ticker, the migration path is straightforward: consolidate the logic into one strategy, move any regime conditions inside the script, replace separate exit alerts with sentiment=flat, and configure allowed sides and a rejectAfter cutoff at the subscription level. The result is a stack where priority is declared, not assumed.
Bottom Line
- When two signals arrive simultaneously, there is no built-in arbitration: whichever is processed first wins.
- The correct fix is upstream consolidation: one strategy per ticker, regime filters encoded inside the script, not as separate alerts.
- The
sentimentfield in the payload is a positional declaration evaluated at execution time, not a sentiment-analysis score. Use it as a directional guard, especially on exits and resizes. - Subscription-level gates, including allowed sides,
rejectAfter, trading windows, and spread filters, are deterministic. They evaluate each signal independently of arrival order. - Fields like
expiresAt,delay, andcancelAfterlet you bracket the execution window of a signal, reducing the overlap where a competing signal could act on an intermediate position state.
Frequently Asked Questions
What happens if two signals arrive at exactly the same time?
There is no built-in arbitration. Whichever signal is processed first wins, and the second may act on a position state that has already changed. The documented recommendation is to leave at least one to five minutes between signals. Simultaneous signals with only milliseconds between them carry no execution order guarantee. The correct fix is to prevent the conflict at the source, either by consolidating logic into one strategy or by using subscription-level gates that reject invalid directions before any order is created.
Does sentiment=flat exit a partial position or the full position?
Sending sentiment=flat always exits the full quantity of the open position. It does not open a new position on the opposite side, regardless of the action field value. To exit a partial position, send a quantity in the payload rather than relying on the sentiment field alone.
Can I use rejectAfter and expiresAt on the same signal?
Yes, and they measure staleness differently. The rejectAfter field is a relative age in seconds from the time field or webhook receive time. The expiresAt field is an absolute ISO-8601 datetime. Using both lets you set a maximum signal age in seconds and an absolute deadline simultaneously, which is useful for signals generated at bar close that should not execute after the next bar opens. Note that rejectAfter requires the Allow signal overrides setting or the matching per-field override to be enabled in the strategy subscription settings.
Should a regime filter be a separate webhook or part of the strategy?
It should be part of the strategy. A regime filter sent as a separate webhook is itself a signal and can arrive out of order relative to the trigger it is meant to suppress. Encoding the regime filter as a condition inside the Pine Script strategy means only one alert fires when all conditions are met, eliminating the timing dependency entirely. Downstream subscription gates such as allowed sides and trading windows can reinforce the filter but should not replace upstream logic.
What is the difference between the sentiment field and an external sentiment score?
The sentiment field in the webhook payload is a positional declaration: it states what the position should look like after execution, accepting bullish, bearish, or flat as values. An external sentiment score is a market-derived input, such as an options flow index or a breadth indicator, used to decide whether a signal should be generated at all. External sentiment scores belong in the upstream strategy logic as regime inputs. The payload sentiment field is a per-signal execution instruction, and conflating the two leads to designs where the score is sent as a second payload that competes with the signal it was meant to modify.