Timing & Idempotency
Three fields that govern when a payload runs and how often TVH retries on transient errors.
alertTimestampis the single most important field for production setups. It's the idempotency key. TVH stores one lock row per(token, exchange/apiKey, alertTimestamp)triple — duplicate triples are rejected for as long as the lock row exists.- Recommended Pine value:
"{{ticker}}-{{timenow}}". delaypauses the signal before forwarding to the exchange (max 604800 = 7 days). Useful for "wait, then act" patterns.retriescontrols how many times TVH re-sends an order on a Binance overload response (default 1, max 10).
Quick reference table
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
delay | int | no | 0 | Seconds to wait before TVH forwards the signal to the exchange. Useful for staggered exits or letting the spread settle after news. |
retries | int | no | 1 | How many times TVH re-sends an order when Binance returns an overload / server-busy response. Binance-specific overload guard, not a general cross-exchange retry; does not retry hard rejections or IP bans. Capped at 10. |
alertTimestamp | string | no | — | Idempotency key. TVH builds a deduplication key from (token, apiKey-or-exchange, alertTimestamp) the first time it processes the payload; a later payload with the same triple is recognised as a duplicate and silently dropped. Recommended Pine value: "{{ticker}}-{{timenow}}". |
alertTimestamp — the idempotency key
TradingView can retry a webhook on transient network errors. The same alert can also be re-fired by an alertcondition() rule that triggers on every bar close in volatile conditions. Without a deduplication mechanism, a single intended fill can become two or three.
alertTimestamp solves this. TVH builds a deduplication key from (token, apiKey-or-exchange, alertTimestamp) the first time it sees a payload. A duplicate payload — same token, same apiKey/exchange, same alertTimestamp — produces the same key, gets recognised as already processed, and is silently dropped.
Recommended Pine pattern
alertcondition(
longSignal,
title="Long Entry",
message='{"exchange":"binance-futures","pair":"{{ticker}}","apiKey":"binance-futures-main","isBuy":true,"unitsType":"percent","unitsPercent":2,"alertTimestamp":"{{ticker}}-{{timenow}}","token":"<token>"}'
)
{{ticker}} is the symbol (e.g. BTCUSDT); {{timenow}} is the millisecond Unix timestamp of the bar. The concatenation produces a value like:
BTCUSDT-1715900400000
Unique per bar, per pair. If TradingView retries the same alert, the timestamp matches and TVH drops the duplicate.
Why {{timenow}} and not {{time}}?
{{time}}is the bar's open time. Twoalertconditioncalls on the same bar share the same{{time}}— useful when you want dedup across the same bar.{{timenow}}is the current time when the alert fires. Different fills on the same bar get different values.
Pick the one that matches your "what counts as a duplicate" definition. For most setups, {{timenow}} is right.
How long the lock lasts
Deduplication is effectively permanent: as long as TVH retains the record, replaying the exact same (token, apiKey, alertTimestamp) triple is rejected. In practice that means:
- A retry from TradingView seconds after the original always dedups.
- Re-using a static
alertTimestampstring across days dedups — only the first run gets through. - Treat the dedup as permanent for the lifetime of any given alert template.
The lock row key includes the apiKey (or, if blank, the exchange slug) as a discriminator. The same alertTimestamp value sent to two different apiKeys is not dedup'd — both go through. This is intentional: copy-trade fan-out maps one master signal to many follower signals, each with its own apiKey.
delay — staggered execution
{
"delay": 10
}
Wait 10 seconds, then forward the signal to the exchange. The webhook accepts the payload immediately, but the actual exchange submission is delayed.
Use cases:
- Spread settles after news. A scheduled news release widens spreads briefly. Delay the entry by 10–30 s so it fills closer to the new fair value.
- Staggered legs. Two TradingView alerts fire on the same bar (e.g. two pairs). Use different
delayvalues to space the exchange calls apart and avoid rate limits. - Bias confirmation. Pine signal fires on bar close; you want to wait for the next bar's first tick to confirm.
delay: 60(on a 1-minute chart) buys you the confirmation window.
Range: 0 to 604800 seconds (= 7 days). Practical maxes are usually under 300 s.
Negative delay for email override. A value of -1 is used internally for email-driven signals — when present, TVH dispatches the trade without the default 5-second delay applied to other email-path signals. You should not set this manually; it's left untouched on direct webhook payloads. See Email Backup.
retries — transient-error backoff
{
"retries": 3
}
When a Binance order call comes back with an overload / server-busy response, TVH re-sends it up to retries times before giving up. The field exists specifically for Binance's busy-server bursts (its in-code comment is literally "retries for overload on binance"). It does not retry hard rejections like bad parameters or an IP ban, and it is not a general cross-exchange retry layer.
Default is 1. That's enough for the vast majority of cases. Crank it up to 3 or 5 for setups that absolutely must land — retries: 5 adds at most a few seconds of latency on a healthy exchange. The value is capped at 10; higher numbers are clamped.
The retry uses a short backoff between attempts (a small increasing delay). The exact schedule is internal and may evolve; you don't tune it.
Not a substitute for alertTimestamp. Retries on TVH's side are different from retries on TradingView's side. The first protects against exchange flakiness; the second is what alertTimestamp dedups.
Detail per property
alertTimestamp
| Attribute | Value |
|---|---|
| Type | string |
| Required | no (but strongly recommended in production) |
| Default | "" |
| TV placeholder compatible | yes |
Idempotency key. TVH inserts a lock row keyed on (token, apiKey-or-exchange, alertTimestamp) when the trade-queue worker first processes the payload. Any later payload that produces the same key is recognised as a duplicate and silently dropped. The lock row persists; treat dedup as permanent per template.
delay
| Attribute | Value |
|---|---|
| Type | int (seconds) |
| Required | no |
| Default | 0 |
| TV placeholder compatible | no |
Seconds to wait before forwarding to the exchange. Max 604800.
retries
| Attribute | Value |
|---|---|
| Type | int |
| Required | no |
| Default | 1 |
| TV placeholder compatible | no |
How many times TVH re-sends an order on a Binance overload (server-busy) response. Capped at 10. Not a general cross-exchange retry.
Common mistakes
- No
alertTimestampin production. A TradingView retry doubles the position. Always set it. - Same
alertTimestampacross pairs."{{timenow}}"alone (without{{ticker}}-) collides when two pairs fire on the same bar. Prefix with the ticker. delay > 60on a strategy alert. TradingView strategy alerts trigger on bar close and Pine doesn't know about the delay — your Pine SL might fire on the next bar before the entry has even been submitted. Keepdelayshort for strategy-mode alerts.
Next
Math Expressions — the dedicated reference for the stopLossExpression / takeProfitExpression evaluator.