The pre-live checklist for a Pine strategy
Ten checks before a TradingView strategy's alerts reach a broker: v6 compile, repainting, alert payloads, sessions, sizing, paper trades and the journal.
Updated 30 Aug 2026
A strategy that backtests cleanly can still misbehave the moment its alerts start posting to a webhook. The failures are mostly plumbing: a payload that is not valid JSON, an alert that fires on every tick, a session guard that does not pin its clock to IST. Each one is cheap to catch before the first live order and expensive after.
This page is the checklist Sarathi's own house strategies go through. Work it top to bottom. Every row has a pass condition you can observe, not an opinion.
The checklist
| # | Check | Pass condition | Where to look |
|---|---|---|---|
| 1 | Compiles on Pine v6 | //@version=6 at the top, no compiler warnings | Pine Editor |
| 2 | Executes on confirmed closes only | calc_on_every_tick = false, process_orders_on_close = true, entries gated on barstate.isconfirmed | Strategy header and entry conditions |
| 3 | No lookahead | [1] offset with lookahead_on, or completed prior-period values with lookahead_off and the one-period lag documented | Every request.security() call |
| 4 | Alert fires once per bar close | alert.freq_once_per_bar_close in code; Once Per Bar Close in the dialog for alertcondition() | alert() calls and the alert dialog |
| 5 | Payload is valid JSON | The raw body from the alert log parses without edits | Alert log, webhook status column |
| 6 | Numbers are numbers | No thousands separators, no NaN, no 1e+05 | str.tostring() calls in alert_message |
| 7 | Session and square-off are in IST | Entry window and flat-by time computed with "Asia/Kolkata" | Clock block |
| 8 | Size and risk per trade are explicit | qty in the payload is a lot multiple; stop distance times quantity is a number you accept | Sizing block, order card |
| 9 | Paper trade first | Cards confirmed on the paper route, fills and slippage visible in the journal | Paper route, journal |
| 10 | Journal reviewed after a week | Expiries, skips, rejections and slippage reviewed against the backtest | /dashboard/journal |
The rest of this page walks through each row.
1. Compile on v6
Pine v6 changed several defaults that quietly alter a strategy's behaviour: implicit bool conversion is gone, and and or evaluate lazily, and timeframe strings such as "D" need a multiplier. TradingView publishes the full list in its migration guide. A v5 script that still runs is not a passed check; convert it, fix what the compiler flags, and re-run the backtest. If the trade list changed, find out why before moving on. The Studio writes v6 from the start, and this page covers the breaking items one by one.
2. Confirmed closes, not ticks
A strategy recalculates on every realtime update when calc_on_every_tick is true, which means an entry can appear mid-bar and disappear before the close. Historical bars never behave that way, so the backtest and the live chart stop describing the same thing. Set it false, set process_orders_on_close = true, and put barstate.isconfirmed in the entry condition.
//@version=6strategy("ORB 15m", overlay = true, calc_on_every_tick = false, process_orders_on_close = true, commission_type = strategy.commission.cash_per_order, commission_value = 350, slippage = 2)
longSig = barstate.isconfirmed and close > orHigh + bufferThe house rule adds ₹350 per order and two ticks of slippage to every backtest. Neither number is a forecast; they are a stress test so a strategy that only works at zero cost fails in the editor rather than in an account.
3. Prove it does not repaint
Repainting has four common causes, and this page covers them. The one that survives most reviews is request.security() with barmerge.lookahead_on on an incomplete higher-timeframe bar, which lets a 15-minute script see today's daily close at 09:30. Use a [1] offset with lookahead_on, or completed prior-period values with lookahead_off and the one-period lag documented.
The test is mechanical. Leave the strategy on a live chart for a few sessions and export the trade list. Then reload the chart so every bar is historical and export again. The two lists should match trade for trade. TradingView's repainting guide explains what each mismatch usually means.
4. Alert frequency
For alert() calls the frequency is the freq argument in code, and a strategy without calc_on_every_tick fires at bar close whatever you pass. For alertcondition() alerts it is the dialog's Once Per Bar Close setting. "Every time" can post the same order several times while the bar is still forming. For alertcondition() the choice lives in the dialog, not in the script, so it is easy to forget when recreating an alert. The alert() versus alertcondition() page covers how alert_message rides on strategy.entry().
5 and 6. A payload that parses
The webhook receiver only sees the body TradingView posts. If it is valid JSON the request arrives with an application/json header; anything else is sent as text/plain, per TradingView's webhook documentation. Sarathi accepts both, but a body that was meant to be JSON and is not will be rejected with a 400 that echoes what was received.
Numbers are the usual culprit. str.format('{0}', x) groups thousands by default and emits 57,530; str.tostring(x) can carry floating-point noise. Give every number an explicit pattern: {0,number,#.##} or str.tostring(x, "#.##"). The webhook alerts page has the worked example.
The body the receiver expects to see:
{ "sym": "BANKNIFTY", "side": "BUY", "type": "ORB", "price": 57530, "sl": 57400, "qty": 30, "time": "2026-08-27T09:30:00+0530"}Two more traps. A stop computed from na becomes the string NaN, which JSON does not allow; guard the division that produced it. And an exit order with no alert_message posts the unexpanded placeholder {{strategy.order.alert_message}}; Sarathi logs that as ignorable and does not raise a card. The full field list, aliases and error codes are on the webhook page and under /developers.
7. Session and square-off in IST
Without a timezone argument, hour(), minute() and time() use syminfo.timezone, the exchange timezone. For NSE and MCX that is already IST, but pass "Asia/Kolkata" explicitly so the script still reads correctly on a non-Indian symbol or a copied chart. Express both the last-entry cut-off and the flat-by time in minutes since midnight.
hh = hour(time, "Asia/Kolkata")mm = minute(time, "Asia/Kolkata")tMins = hh * 60 + mmcanEnter = tMins < 14 * 60 + 30 // no new entries after 14:30isEOD = tMins >= 15 * 60 + 15 // flat by 15:15The NSE F&O page has the session strings for NSE and MCX and the reasoning behind a 14:30 cut-off on a 15:30 close.
8. Size and risk per trade
The order card shows entry, stop, quantity, risk in rupees and notional. Those numbers come from the payload, so the payload has to carry a quantity that is a whole number of lots for the instrument, and a stop that is on the correct side of the entry. Work out the rupee risk on the card before the first live session: stop distance in points times quantity. If that figure surprises you, fix the script, not the tap.
Sarathi adds one more knob at decision time. Confirm carries ½, 1× or 2× of the payload quantity, rounded to a whole number of lots for the instrument and never below one lot, so a ½ tap on a one-lot signal places one lot. The Telegram page has the full wording.
9. Paper trade first
The paper route is a broker adapter that fills at the price hint, records the fill and the slippage, and never touches an exchange. It is never metered. Run the strategy on paper until every branch has fired at least once: long, short, stop, target, square-off, and a card you deliberately let expire. Each of these lands in the journal with its route, side, quantity, entry, fill and IST timestamp, so you can compare against the backtest line by line. The paper route page lists what it does and does not simulate.
10. Read the journal after a week
After five sessions, filter the journal by strategy and count four things.
| Count | What it tells you |
|---|---|
| Expired cards | Alerts fired when you could not respond. Either move the cut-off or accept the miss rate. |
| Skipped cards | Signals you chose not to take. If most are skips, the script and your judgement disagree; decide which is right. |
| Rejected fills | Quantity, symbol or session errors that a live broker would also refuse. |
| Slippage vs signal | Fill minus price hint, in points. Compare against the two ticks the backtest charged. |
A strategy that passes all ten rows is not guaranteed to make money. It is guaranteed to post what you think it posts, when you think it posts it, at the size you intended, and that is what this checklist is for.
Try it in Sarathi
The Studio writes Pine v6 with the house header from row 2 already in place. Point the alert at your webhook, leave the account on the paper route, and every card that arrives in Telegram and on the web dashboard waits for your Confirm or Skip. Nothing is placed until you tap.
Questions
Run it with calc_on_every_tick off, gate entries on barstate.isconfirmed, avoid lookahead on higher-timeframe requests, and compare the historical trade list against the trades the live chart produced over a few sessions. If the two lists differ, something repaints.
Once per bar close. A strategy that executes on confirmed closes produces one order event per bar, so the alert should fire once per bar close too. Other frequencies can post the same order several times.
Usually the body is not what you think it is. A number formatted with a thousands separator or an unquoted NaN breaks JSON. Copy the raw body from the TradingView alert log and paste it through a JSON validator.
There is no fixed number. A useful floor is enough sessions to see every branch of the strategy fire at least once: a long, a short, a stop, a target, a square-off and an expired card.
Related
- How TradingView webhook alerts workWhat TradingView posts when a webhook alert fires: placeholders, JSON rules, the 3 second timeout, secrets in the URL, and the failures that break a bridge.
- Repainting, lookahead and calc_on_every_tick explainedWhy a Pine strategy trades differently live than in the backtest: lookahead, request.security offsets, calc_on_every_tick, barstate.isconfirmed, how to test.
- alert() vs alertcondition(): which one fires your webhookThe four combinations of alert(), alertcondition(), strategy and indicator in Pine Script, what each can put in a webhook body, and which frequency to choose.
- NSE F&O in Pine: sessions, lot sizes and expiriesIST session guards, last-entry cut-offs, NIFTY, BANKNIFTY and SENSEX expiry days, current lot sizes with sources, and MCX hours for GOLDM and SILVERM.
- Paper broker: how Sarathi simulates fillsWhat the paper route fills, what it skips, how the journal records a paper fill, and how to move to a live broker once an adapter ships.
- Telegram order cardsWhat a Sarathi order card looks like in Telegram, what the four buttons do, how linking and unlinking work, what is never sent, and how the web mirrors it.