Can someone help me understand the current pine script behavior with my custom indicator? I declare what I believe is a normal timeseries global variable "a" to store the closing price. Yet if I try to access this value from a user-defined function, past values are not correct if the user-defined function is not called on every single bar. THe value of the built-in "close" variable works correctly though. How can I declare a variable to behave like the built-in ones? (i.e. to reliably return past values even if the user-defined function is executed inside a conditional statement)
Here is my code:
//@version=6
indicator("My script")
plot(close)
float a = close
f() =>
log.info("f: barIndex={0}, a[0]={1}, close[0]={2}, a[1]={3}, close[1]={4}", bar_index, a[0], close[0], a[1], close[1])
g() =>
log.info("g: barIndex={0}, a[0]={1}, close[0]={2}, a[1]={3}, close[1]={4}", bar_index, a[0], close[0], a[1], close[1])
f()
if bar_index % 2 == 0
g()
here is the outcome:
[2025-01-30T21:00:00.000-05:00]: f: barIndex=23,682, a[0]=2,848.4, close[0]=2,848.4, a[1]=2,849.3, close[1]=2,849.3 [2025-01-30T21:00:00.000-05:00]: g: barIndex=23,682, a[0]=2,848.4, close[0]=2,848.4, a[1]=2,852.6, close[1]=2,849.3 [2025-01-30T22:00:00.000-05:00]: f: barIndex=23,683, a[0]=2,851.2, close[0]=2,851.2, a[1]=2,848.4, close[1]=2,848.4 [2025-01-30T23:00:00.000-05:00]: f: barIndex=23,684, a[0]=2,848.9, close[0]=2,848.9, a[1]=2,851.2, close[1]=2,851.2 [2025-01-30T23:00:00.000-05:00]: g: barIndex=23,684, a[0]=2,848.9, close[0]=2,848.9, a[1]=2,848.4, close[1]=2,851.2 [2025-01-31T00:00:00.000-05:00]: f: barIndex=23,685, a[0]=2,847.1, close[0]=2,847.1, a[1]=2,848.9, close[1]=2,848.9 [2025-01-31T01:00:00.000-05:00]: f: barIndex=23,686, a[0]=2,845.8, close[0]=2,845.8, a[1]=2,847.1, close[1]=2,847.1 [2025-01-31T01:00:00.000-05:00]: g: barIndex=23,686, a[0]=2,845.8, close[0]=2,845.8, a[1]=2,848.9, close[1]=2,847.1 [2025-01-31T02:00:00.000-05:00]: f: barIndex=23,687, a[0]=2,849.8, close[0]=2,849.8, a[1]=2,845.8, close[1]=2,845.8 [2025-01-31T03:00:00.000-05:00]: f: barIndex=23,688, a[0]=2,844.9, close[0]=2,844.9, a[1]=2,849.8, close[1]=2,849.8 [2025-01-31T03:00:00.000-05:00]: g: barIndex=23,688, a[0]=2,844.9, close[0]=2,844.9, a[1]=2,845.8, close[1]=2,849.8
I would expect a[1] to be the same as close[1] in both f() and g() calls since variable "a" is a global variable (and not a local one).
Can someone help me understand the current pine script behavior with my custom indicator? I declare what I believe is a normal timeseries global variable "a" to store the closing price. Yet if I try to access this value from a user-defined function, past values are not correct if the user-defined function is not called on every single bar. THe value of the built-in "close" variable works correctly though. How can I declare a variable to behave like the built-in ones? (i.e. to reliably return past values even if the user-defined function is executed inside a conditional statement)
Here is my code:
//@version=6
indicator("My script")
plot(close)
float a = close
f() =>
log.info("f: barIndex={0}, a[0]={1}, close[0]={2}, a[1]={3}, close[1]={4}", bar_index, a[0], close[0], a[1], close[1])
g() =>
log.info("g: barIndex={0}, a[0]={1}, close[0]={2}, a[1]={3}, close[1]={4}", bar_index, a[0], close[0], a[1], close[1])
f()
if bar_index % 2 == 0
g()
here is the outcome:
[2025-01-30T21:00:00.000-05:00]: f: barIndex=23,682, a[0]=2,848.4, close[0]=2,848.4, a[1]=2,849.3, close[1]=2,849.3 [2025-01-30T21:00:00.000-05:00]: g: barIndex=23,682, a[0]=2,848.4, close[0]=2,848.4, a[1]=2,852.6, close[1]=2,849.3 [2025-01-30T22:00:00.000-05:00]: f: barIndex=23,683, a[0]=2,851.2, close[0]=2,851.2, a[1]=2,848.4, close[1]=2,848.4 [2025-01-30T23:00:00.000-05:00]: f: barIndex=23,684, a[0]=2,848.9, close[0]=2,848.9, a[1]=2,851.2, close[1]=2,851.2 [2025-01-30T23:00:00.000-05:00]: g: barIndex=23,684, a[0]=2,848.9, close[0]=2,848.9, a[1]=2,848.4, close[1]=2,851.2 [2025-01-31T00:00:00.000-05:00]: f: barIndex=23,685, a[0]=2,847.1, close[0]=2,847.1, a[1]=2,848.9, close[1]=2,848.9 [2025-01-31T01:00:00.000-05:00]: f: barIndex=23,686, a[0]=2,845.8, close[0]=2,845.8, a[1]=2,847.1, close[1]=2,847.1 [2025-01-31T01:00:00.000-05:00]: g: barIndex=23,686, a[0]=2,845.8, close[0]=2,845.8, a[1]=2,848.9, close[1]=2,847.1 [2025-01-31T02:00:00.000-05:00]: f: barIndex=23,687, a[0]=2,849.8, close[0]=2,849.8, a[1]=2,845.8, close[1]=2,845.8 [2025-01-31T03:00:00.000-05:00]: f: barIndex=23,688, a[0]=2,844.9, close[0]=2,844.9, a[1]=2,849.8, close[1]=2,849.8 [2025-01-31T03:00:00.000-05:00]: g: barIndex=23,688, a[0]=2,844.9, close[0]=2,844.9, a[1]=2,845.8, close[1]=2,849.8
I would expect a[1] to be the same as close[1] in both f() and g() calls since variable "a" is a global variable (and not a local one).
Interesting question, did some research on it. The way how PineScipt handles historical data can introduce weird results, as you have experienced. The solution lies within the execution model of PineScript.
As the docs says:
The result of function calls on successive bars leaves a succession of values in a time series that scripts can reference using the [] history-referencing operator.
This means, that if you execute g() on every second bar, it will record half the amount of historical data then f(), since it executes half the time. More on that here. With the built-in variables (like close, open, ohlc4, etc) this is not a problem, since they are implemented in a way, such a problems cannot arise.
Luckily, there is a workaround. You have to evaluate a[1] globally, then use that value locally. Just like this:
//@version=6
indicator("My script")
plot(close)
float a = close
aBefore = a[1]
f() =>
log.info("f: barIndex={0}, a[0]={1}, close[0]={2}, a[1]={3}, close[1]={4}", bar_index, a[0], close[0], a[1], close[1])
g() =>
log.info("g: barIndex={0}, a[0]={1}, close[0]={2}, a[1]={3}, close[1]={4}", bar_index, a[0], close[0], aBefore, close[1])
f()
if bar_index % 2 == 0
g()
Notice the aBefore = a[1]
line. This will be calculated on every bar, and you can use the value in your function - g() -. A similar problem is presented on the linked docs site.