Futures Webhook Duplicate Orders and Idempotency
A practical model for preventing duplicate futures orders across TradingView retries, repeated Pine conditions, timeouts, manual replays, and uncertain broker acknowledgements.
How do you prevent duplicate futures webhook orders?
Give each logical strategy event a stable identity, preserve that identity across delivery retries, and refuse to submit a second order while the first event is accepted, submitted, filled, rejected, or unresolved according to policy. Also prevent Pine from creating repeated events for one condition. Cooldowns and quantity caps are useful guardrails, but they are not substitutes for durable idempotency and broker reconciliation.
First identify the duplicate's origin. TradingView may resend one trigger after a qualifying 5xx; that is repeated delivery of the same intent. Pine may emit once per bar while a broad condition remains true; those are separate sender events even if a human considers them one signal. An operator may click or recreate an alert. Finally, a receiver may retry a broker call after losing its response. Applying one generic cooldown to all four causes hides the actual control failure.
The financial risk is asymmetric. Suppressing a genuine second signal can leave exposure below plan, while submitting a duplicate can double exposure instantly. A safe design records a decision for every logical event and exposes unknown states rather than treating missing confirmation as failure. The exact implementation belongs to the receiving service. Do not add an `idempotencyKey` to a HexTrade payload unless its current docs explicitly support it; undocumented fields should never carry a safety guarantee.
- Event identity answers whether two arrivals represent the same strategy decision.
- State answers whether another broker submission is safe, unsafe, or requires reconciliation.
- Pine gating prevents multiple decisions from a condition that never transitioned.
- Risk guardrails limit damage but cannot prove only one order exists.
What should identify one logical webhook event?
Use values that remain unchanged when the same event is resent: strategy and alert version, destination account, destination symbol, action, quantity, and a sender event time or sequence. Avoid receiver arrival time, random values generated per request, or mutable account state. The identity must distinguish a genuine later signal while collapsing byte-equivalent and semantically equivalent retries.
TradingView placeholders such as ticker, timeframe, bar time, and current trigger time can contribute to a human-readable fingerprint. HexTrade documents optional `strategyName`, `alertName`, `note`, and `tags`, so a non-secret correlation label can travel with the request. Use a versioned naming convention such as strategy family, reviewed version, and event timestamp. Keep it concise and deterministic; an operator should be able to compare two records without reconstructing an entire Pine runtime.
Time alone is not always enough. Two strategies can act on the same symbol and second, and one strategy can intentionally scale in more than once. Include the semantic order identity needed by your design, such as an entry or exit role and strategy order ID when available. Conversely, including market price that changes between a manual reconstruction and the original can defeat matching. Define the identity before launch and test intentional same-bar scale-ins so deduplication does not erase valid orders.
{
"ticker": "MNQ",
"action": "{{strategy.order.action}}",
"quantity": "{{strategy.order.contracts}}",
"platformType": "tradovate",
"accountId": "replace_with_exact_account_id",
"strategyName": "ema-cross-v3",
"alertName": "order-fill",
"note": "ema-cross-v3|MNQ|{{strategy.order.id}}|{{timenow}}",
"dryRun": true
}Correlation is not a documented idempotency promise
Labels make incidents easier to trace. They do not, by themselves, prove the receiver enforces exactly-once submission. Verify current product behavior in official documentation.
How do you stop Pine from creating repeated signals?
Trigger on a transition rather than a condition that stays true, select an alert frequency that matches the strategy, and maintain explicit state when one transition must remain suppressed until a reset. For confirmed-bar systems, require `barstate.isconfirmed` and use once-per-bar-close. Test realtime behavior because historical plots do not reproduce every tick available to live alerts.
`close > movingAverage` can remain true for many bars, while `ta.crossover(close, movingAverage)` is true only on the transition. That simple change often removes apparent duplicates at the source. More complex strategies should record whether they are flat, pending, long, or short and emit only on allowed transitions. Reset the state on a deliberate opposite event or confirmed exit, not merely after an arbitrary number of seconds that can expire while the first order is still working.
Strategies execute at bar close by default unless configured for every tick, and realtime bars can recalculate with fluid values. An `alert()` frequency cannot repair strategy logic that enters repeatedly. Order-fill events may align more closely with the broker emulator's simulated fills, but they still describe TradingView's strategy environment rather than the destination broker. Repainting and every-tick recalculation must be evaluated separately from webhook retry duplicates.
- Transition test: the alert fires when state changes, not on every bar that state remains true.
- Frequency test: multiple eligible calls in one realtime bar behave as designed.
- Reset test: an exit or opposite transition re-arms exactly when intended.
- Snapshot test: the active alert is recreated after the reviewed code or input changes.
//@version=6
indicator("Single transition alert", overlay = true)
fast = ta.ema(close, 9)
slow = ta.ema(close, 21)
newLong = ta.crossover(fast, slow) and barstate.isconfirmed
if newLong
alert('{"ticker":"MNQ","action":"buy","quantity":"1","platformType":"projectx","accountId":"replace_with_exact_account_id","dryRun":true}', alert.freq_once_per_bar_close)What state should an idempotent receiver record?
Record the event identity, validated intent, submission attempt, downstream identifier, and final known state as one transaction. A repeated delivery should retrieve that transaction before any broker call. Distinguish rejected-before-submission, submitted, accepted, working, partially filled, filled, cancelled, and unknown. Never convert `unknown` into `not submitted` merely because an acknowledgement is missing.
Exactly-once network delivery is not a realistic assumption; exactly-once business effect is approached through identity, atomic state changes, and reconciliation. The receiver should claim an unseen event before side effects, then let concurrent or later arrivals observe the claim. If the broker offers a client order identifier, the receiver can carry a stable value downstream within that broker's documented rules. If it does not, account-side reconciliation becomes even more important after connection loss.
The three-second TradingView deadline adds pressure but does not remove state requirements. A receiver can acknowledge accepted work only after it has retained enough information to continue safely. If a temporary internal failure returns a qualifying 5xx, later deliveries must find the original state. If a broker call times out, hold the event and query or inspect the destination before retrying. Automated retries are safest before external submission and most dangerous after an uncertain one.
| Existing state | Meaning | Safe duplicate behavior |
|---|---|---|
| Rejected before submission | Validation prevented a broker call | Return the same rejection unless the event is deliberately corrected as a new version. |
| Accepted or queued | Work is durably retained | Return the existing reference and do not enqueue another copy. |
| Submitted or working | Broker side effect may exist | Return existing state and continue observation rather than resubmitting. |
| Filled or cancelled | Terminal result is known | Return the recorded result with no new order. |
| Unknown | Submission outcome cannot be proven | Quarantine and reconcile at the broker before any new attempt. |
Which documented HexTrade controls reduce duplicate damage?
HexTrade documents `cooldown` in seconds for another fill on the same account and symbol, `maxQty` as a hard size cap, `allowedSymbols` as a whitelist, and `maxTradesPerDay` as an in-memory cap. Use them as layered guardrails. The docs state that cooldown and daily counters are in-memory and that dry runs do not update them.
Scope matters. A same-account, same-symbol cooldown can suppress rapid repetition, but it may also block a valid scale-in and may not cover another account or symbol. An in-memory daily cap resets on process restart, so it cannot be presented as a permanent ledger. `maxQty` limits each request's size but cannot prevent two separate capped orders. `allowedSymbols` prevents routing to an unexpected instrument but does not determine whether two MNQ events are duplicates.
Configure these controls from the risk policy outward. If the strategy intentionally sends entry and exit events close together, a cooldown requires careful testing so it does not interfere with the exit path. Keep an emergency pause outside the sender, monitor the destination account, and begin with the smallest approved quantity. The product docs are the authority for current fields; avoid assuming undocumented global deduplication, exactly-once guarantees, or persistence semantics.
- `cooldown`: narrow temporal guard for the documented account-and-symbol scope.
- `maxQty`: per-request size ceiling, not a count of open or repeated orders.
- `allowedSymbols`: route whitelist, useful against chart and mapping mistakes.
- `maxTradesPerDay`: in-memory count with the documented restart caveat.
What should you do after a suspected duplicate order?
Pause the alert or execution route, inspect the destination account, and classify every order before closing or resending anything. Preserve TradingView alert events, Webhook statuses, sanitized payload fingerprints, receiver records, broker identifiers, quantities, and timestamps. Reduce exposure only through an authorized risk procedure; do not fire an opposite webhook blindly because it can create a new position.
Build a row for each sender event and each HTTP delivery. If one event has several qualifying retry deliveries but one broker order, delivery idempotency worked. If separate alert events share a continuous Pine condition, fix signal gating. If one receiver event maps to multiple broker submissions, inspect concurrency and timeout recovery. If a human replay created the second order, improve unknown-state escalation and remove informal retry instructions from the runbook.
After reconciliation, reproduce the cause in dry mode or an isolated receiver. Add a regression case for the exact failure: delayed response, qualifying 5xx, simultaneous duplicate, stale snapshot, repeated condition, or missing broker acknowledgement. Review guardrail scope and alert ownership. Only resume with a new versioned alert after the test demonstrates one intended effect, and monitor the first live execution at minimum size.
- 1
Freeze
Stop new automated and manual submissions while preserving the current evidence.
- 2
Reconcile
Compare logical signals, HTTP deliveries, receiver transactions, and actual broker orders.
- 3
Classify
Name the cause as sender repetition, transport resend, receiver resubmission, or operator replay.
- 4
Prove the correction
Run the same failure case without live risk, then resume with controlled size and direct observation.
Sources and methodology
HexTrade Research uses official product, exchange, regulator, and vendor documentation. Policies and platform behavior can change; follow the linked source and verify current terms before trading.
- 1.Webhook resubmission — TradingView, accessed Aug 30, 2026
- 2.How to configure webhook alerts — TradingView, accessed Aug 30, 2026
- 3.Pine Script alerts — TradingView, accessed Aug 30, 2026
- 4.Pine Script alerts FAQ — TradingView, accessed Aug 30, 2026
- 5.TradingView webhook automation — HexTrade Docs, accessed Aug 30, 2026
- 6.Webhook troubleshooting — HexTrade Docs, accessed Aug 30, 2026
Frequently asked questions
Does TradingView retry every failed webhook?
No. TradingView documents retries only for HTTP 500–599 responses except 504. It can resend three times after the initial attempt, five seconds apart. Do not assume 4xx, 504, timeout, DNS, TLS, or connection failures follow that same path.
Is a cooldown the same as idempotency?
No. A cooldown suppresses activity within a time and scope; idempotency recognizes the same logical event regardless of repeated arrival. A cooldown can block valid scale-ins or expire before a late replay, while a stable event identity can return the original result.
Can I add an `idempotencyKey` to the HexTrade JSON?
Do not rely on an undocumented field. HexTrade's published webhook reference lists supported route, label, and risk controls but does not establish that arbitrary `idempotencyKey` input enforces exactly-once behavior. Use current official docs and supported product behavior for any safety claim.
Why do I receive repeated alerts even without a 5xx?
Pine may be generating distinct events because a condition stays true, every-tick logic recalculates, more than one alert exists, or an old snapshot remains active. Compare alert event IDs and times before blaming transport retries. Qualifying resends repeat one event after a receiver response.
Should an unknown broker submission be retried?
Not automatically. Unknown means the side effect may already exist. Query or inspect the destination account and reconcile by correlation, symbol, side, quantity, and time. A blind retry can convert an observability problem into doubled futures exposure.
Next step
Put the research into a controlled workflow
Start small, verify the broker and account rules, and keep risk controls between every signal and live order.
Explore webhook automationContinue reading
Educational content only. Futures are leveraged products and can produce losses greater than the amount you expected to risk. This article is not financial, legal, or prop-firm compliance advice.