The script
The average close since the last EMA cross, computed twice: with a loop that reads back through history, and with running totals that need none. Paste it into a new indicator in the Pine Editor, then save and add it to the chart.
//@version=6
indicator("Average close since the last cross", overlay = true)
maxLook = input.int(1000, "Longest lookback for the loop", minval = 10, maxval = 4900)
fast = ta.ema(close, 20)
slow = ta.ema(close, 50)
bool crossed = ta.cross(fast, slow)
int since = ta.barssince(crossed)
// Method 1: loop back over the bars since the cross, reading close[i]
float loopAvg = na
if not na(since) and since <= maxLook
float total = 0.0
for i = 0 to since
total += close[i]
loopAvg := total / (since + 1)
// The offsets above can reach 4900 bars in a long trend: keep that much close history from the start
max_bars_back(close, 5000)
// Method 2: the same average from running totals, with no history at all
var float runSum = 0.0
var int runCount = 0
if crossed
runSum := 0.0
runCount := 0
runSum += close
runCount += 1
float runAvg = na(since) ? na : runSum / runCount
plot(loopAvg, "Average since the cross (loop)", color.orange, 3)
plot(runAvg, "Average since the cross (var)", color.blue, 1)
plotshape(crossed, "Cross", shape.circle, location.abovebar, color.gray, size = size.tiny)How it works
- Where the problem comes from.
close[i]withiup tosinceis an offset decided at run time. Pine sizes the history it keeps forclosefrom what it sees on the first bars; if a trend later lasts longer than that, the script stops with The requested historical offset is beyond the historical buffer's limit, often only on live bars or in Bar Replay. max_bars_back(close, 5000)reserves 5,000 bars ofclosehistory from the first bar. The call can sit anywhere in the script; the number must be a constant. The input caps the loop at 4,900 so the offset always fits.- Method 2 keeps a running sum and count in
varvariables, resets them on the cross and adds the current close on every bar. The result is the same average (the two lines overlap), with no history read and one addition per bar instead of a loop. - Before the first cross
sinceisna, and both averages are hidden.
Pitfalls
- It works on history, then fails live. Buffers are sized while the script loads historical bars and aren't resized afterwards. An offset larger than any seen during loading, which typically shows up on a live bar, stops the script. Size the buffer for the largest offset the script can ask for.
- Sizing the wrong series. The buffer belongs to the series you index. If the loop reads
src[i]wheresrccomes from an input, callmax_bars_back(src, 5000), notmax_bars_back(close, 5000). - max_bars_back = 5000 in indicator(). The declaration's parameter resizes the history of every series in the script. It's simpler but slower and heavier than one
max_bars_back()call for the series that needs it; very large buffers add to Memory limits exceeded. - A hard ceiling. Most series can't be buffered beyond 5,000 bars. For anything longer, accumulate with
varas in method 2, or store selected values in an array. - Loops that grow with the offset. Reading back through
sincebars on every bar makes the work grow with the length of the trend, and on long charts it can reach Loop is too long. The running totals don't have that problem.
Variations
Other running values since the event. The same idea gives the highest high since the cross without ta.highest(high, since + 1) and its growing lookback:
// Highest high since the cross, also without any lookback
var float hiSince = na
hiSince := crossed ? high : math.max(nz(hiSince, high), high)
plot(hiSince, "Highest high since the cross", color.teal, style = plot.style_stepline)
The value at the event. When you only need a value from the bar of the event (the close at the cross, not every close since), ta.valuewhen(crossed, close, 0) does it without any offset; see the valuewhen and barssince example.
Questions
What does max_bars_back do in Pine Script?
It sets how many past bars of a series Pine keeps, so that references like close[i] can reach that far back. max_bars_back(close, 1000) reserves 1,000 bars of close history from the start of the script.
What is the maximum max_bars_back value?
Most series can be buffered up to 5,000 bars. If you need more, keep running values with var or store the values you need in an array instead of reading history.
Why does my script work on history but fail in real time?
Pine sized the history buffer from the offsets it saw while loading historical bars. A larger offset that only appears later, on a live bar or in Bar Replay, falls outside the buffer. Set it explicitly with max_bars_back().
Related pages
Every script on this page was checked with Edgoro Pine Check (Pine Script v6 rules). Pine Check is a static checker, not TradingView's compiler: TradingView compiles the script when you save it in the Pine Editor. The scripts are examples to learn from, not trading systems. Trading involves substantial risk of loss and is not suitable for every investor. Edgoro is a software tool, not a broker or financial adviser: nothing it produces is investment advice, and past or backtested performance does not guarantee future results.