Pine Script Current Price Intrabar: Live Close and Entries
The pine script current price intrabar is just the built-in close on the realtime bar, so no extra indicator is needed. It only becomes final at bar close, so strategies need specific settings and order types to act earlier.
- On the realtime bar, close is the latest tick price; on historical bars it is the final close, and close[0] is identical to close.
- By default a strategy calculates once per bar close and market orders fill at the next bar's open, which is why entries look late.
- calc_on_every_tick=true only changes realtime behavior, so a historical backtest cannot prove how a tick-based strategy will act live.
- To approximate a fill at the crossing price in a backtest, use stop or limit orders at the crossover level (for example the moving average) rather than market orders.
- Intrabar signals repaint: use barstate.isconfirmed to filter them, or varip to latch them, and set alert frequency to match.
Is close the Pine Script current price intrabar on the realtime bar?
Yes. In Pine Script, `close` is not a separate indicator or a delayed value. On the last (realtime) bar it holds the most recent tick price and changes every time the script executes. On every historical bar it holds that bar's final close.
That is also why `close[0]` is simply `close`. The history-referencing operator with index 0 refers to the current bar, so it never differs. `close[1]` is the previous bar's final close.
The confusion comes from the backtest. Historical bars only have open, high, low and close, so the script runs once per bar, and the result looks as if everything happens at bar close. The same code on the realtime bar can run many times, and `close` moves between those runs.
Why do strategy entries fire at bar close or the next open?
By default a strategy calculates once per bar, after the bar closes. If it calls `strategy.entry()` with a market order at that moment, the broker emulator has no price left in the current bar to use, so the order fills at the next bar's open.
A crossover detected with `ta.crossover(close, ma)` on a historical bar therefore means: the bar closed above the average, and the fill happens one bar later. The entry price is the next open, not the level where the lines crossed.
This is an execution-model behavior, not a bug. Every technique below either changes when the script runs, when the emulator fills, or what type of order is used.
Which setting or technique gives intrabar entries?
Each option solves a different part of the problem. The key column is what happens on historical bars, because that is what the backtest shows.
| Technique | Historical bars | Realtime bar | Main limitation |
|---|---|---|---|
| Default (no options) | Runs at bar close; market order fills at next open | Same: runs at close, fills at next open | Entries always one bar after the signal |
| calc_on_every_tick=true | No effect; still once per bar | Script re-runs on every tick; market orders can fill intrabar | Backtest and live diverge; signals can repaint |
| process_orders_on_close=true | Fills at the signal bar's close price | Order is sent after the close, so real fill can differ | Still a close-based signal, not an intrabar fill |
| use_bar_magnifier=true | Uses lower-timeframe bars to decide fills of pending orders | No change to when the script runs | Needs Premium or higher plan; limited lower-timeframe history |
| strategy.entry with stop= or limit= | Fills when the bar's range reaches the level (or at the open if it gaps past) | Fills when price touches the level | Level is computed from the previous bar, so it is an approximation |
| request.security_lower_tf() | Gives an array of lower-timeframe values per chart bar | Array grows as intrabars form | Intrabar count caps and the lower-timeframe history is shorter |
What is a minimal working Pine v6 example?
This strategy plots the live price line, detects a crossover and enters on the realtime tick. The `varip` latch stops it from re-sending the entry on every tick of the same bar.
Note that `var` is not enough for that latch. Both `var` and normal variables are rolled back to their last committed value before each realtime tick, while `varip` keeps changes made on earlier ticks of the same bar.
//@version=6
strategy("Live crossover demo", overlay=true, calc_on_every_tick=true,
default_qty_type=strategy.percent_of_equity, default_qty_value=10)
len = input.int(20, "MA length", minval=1)
ma = ta.sma(close, len)
plot(close, "Live price", color=color.gray)
plot(ma, "MA", color=color.orange)
crossUp = ta.crossover(close, ma)
varip bool firedThisBar = false
if barstate.isnew
firedThisBar := false
if crossUp and not firedThisBar and strategy.position_size <= 0
strategy.entry("Long", strategy.long)
firedThisBar := true
if ta.crossunder(close, ma) and barstate.isconfirmed
strategy.close("Long")How do I detect a crossover intrabar without repainting?
On a realtime bar `ta.crossover(close, ma)` can be true at one tick and false at the next, because `close` and the average both move. If the entry was already sent, the order stays, but the chart signal vanishes at close. That is repainting.
Pick one policy and apply it deliberately:
- Decide whether an intrabar signal is acceptable. If not, gate every signal with `barstate.isconfirmed`, which is true only on the final execution of a bar.
- If it is acceptable, latch it with `varip` (as above) so one touch cannot trigger repeated orders.
- Use `barstate.isrealtime` to separate live-only logic, such as logging or labels, from logic that must also run on history.
- Use `barstate.isnew` to reset latches at the first tick of each bar.
- Compare against `ma[1]` or another prior-bar value when you want a fixed level that does not drift during the bar.
How can stop orders and lower-timeframe data approximate the crossing price?
A buy stop at the average is the closest backtest model of "enter when price crosses up". If price is below the average, place `strategy.entry("Long", strategy.long, stop=ma)`. The emulator fills it as soon as the bar's range reaches the level, or at the open if the bar gaps over it.
Re-issue the order every bar so the level follows the average, and cancel it when the condition no longer holds. The level is the value known at the previous close, so it differs slightly from the exact crossing point inside the next bar.
The exit is a cross below the average, not a state check: because the stop entry fills at the average itself, a plain `close < ma` test would be true on the next bar and close the trade immediately, whereas `ta.crossunder(close, ma)` fires only when price actually moves from above the average to below it.
//@version=6
strategy("Stop at MA", overlay=true, use_bar_magnifier=true)
ma = ta.sma(close, 20)
plot(ma)
if close < ma and strategy.position_size == 0
strategy.entry("Long", strategy.long, stop=ma)
else
strategy.cancel("Long")
if ta.crossunder(close, ma) and strategy.position_size > 0
strategy.close("Long")
// ---- separate indicator: find the first 1-minute close above last bar's MA ----
//@version=6
indicator("Intrabar cross finder", overlay=true)
ma = ta.sma(close, 20)
float[] ltf = request.security_lower_tf(syminfo.tickerid, "1", close)
level = nz(ma[1], ma)
int idx = -1
if ltf.size() > 0 and close[1] <= level
for i = 0 to ltf.size() - 1
if ltf.get(i) > level
idx := i
break
plotshape(idx >= 0, "Crossed intrabar", shape.triangleup, location.belowbar)Why do backtest and live results differ, and what about alerts?
Bars contain only four prices, so the emulator must assume how price travelled. It uses a heuristic: if the high is closer to the open than the low is, it assumes open, high, low, close; otherwise open, low, high, close. A stop and a target inside the same bar are therefore resolved by assumption, not by real tick order.
`use_bar_magnifier=true` reduces that guesswork by replaying lower-timeframe bars when deciding fills. It requires a Premium or higher plan, and lower-timeframe history is shorter than chart history, so the magnified period may cover only part of the backtest. It does not make the script itself calculate intrabar.
`process_orders_on_close=true` is often mistaken for an intrabar fix. It fills at the signal bar's close price in the backtest, which removes the one-bar delay, but the signal still needed the full bar. Live, the price when the order actually reaches a broker will differ from that close.
For alerts, the frequency option decides whether an intrabar signal is ever seen. "Once Per Bar" fires on the first tick where the condition is true; "Once Per Bar Close" waits for the bar to finish; in `alert()` these are `alert.freq_once_per_bar` and `alert.freq_once_per_bar_close`. Strategy order-fill alerts follow the calculation mode, so they only fire intrabar with `calc_on_every_tick=true`.
Common mistakes to avoid: expecting `close[0]` to differ from `close`; using `lookahead=barmerge.lookahead_on` in `request.security` without offsetting the series (for example `close[1]`), which leaks future values into history; and treating a clean historical backtest as proof of realtime tick behavior. The Pine Script User Manual's execution model page covers the rollback rules in more depth.
Common questions
Does calc_on_every_tick change my backtest results?
No, it has no effect on historical bars, which are always calculated once at their close. It only changes how the script runs on the realtime bar, so the live chart can behave differently from the backtest you tuned.
Can I enter exactly at the moving-average price?
In a backtest, a stop or limit order set to the average is the closest approximation, and the emulator fills at that level unless the bar gaps through it. The average itself moves during the bar, so the level you use is the previous bar's value and the fill is approximate.
Why does my alert only fire after the bar closes?
The alert is probably set to "Once Per Bar Close", or your strategy runs without calc_on_every_tick, so no condition exists before the close. Switch the alert to "Once Per Bar" and make sure the script evaluates on ticks, accepting that the signal may later disappear.
Does use_bar_magnifier work on a free account?
No, it needs a Premium or higher plan. Even then it depends on available lower-timeframe history, so older parts of a long backtest may fall back to normal bar-based fills.
What is the difference between var and varip for intrabar logic?
var keeps a value across bars but is rolled back to its last committed state before each realtime tick. varip is not rolled back, so it can remember what happened on earlier ticks of the same bar, which makes it suitable for one-shot latches.