I am trying to optimise an SMA period within a for loop such that there is at least one cross between the low series and the SMA and the high series and a multiplier of the SMA. To do this, I use a for loop over candidate period values and for each candidate period value, I check whether the crosses mentioned earlier exist.
I notice some very strange behaviour which leads to garbage results.
Here's a sample code. Please try it on the daily BITSTAMP:BTCUSD chart so that the results you get are consistent with mine.
//@version=5
indicator(title="test", shorttitle="test", overlay=true)
// functions
boolCross(series1, series2) =>
not na(ta.valuewhen(ta.cross(series1, series2), series1, 0))
// initialize
debugText = ""
// demo
var int periodToUse = 0
for thisPeriod = 4999 to 1 by 200
periodToUse := thisPeriod
boolUpperBandTouch = false
boolLowerBandTouch = false
sma = ta.sma(close, thisPeriod)
if boolCross(high, sma * 5)
boolUpperBandTouch := true
if boolCross(low, sma)
boolLowerBandTouch := true
if boolUpperBandTouch and boolLowerBandTouch
break
debugText += "Value of periodToUse: " + str.tostring(periodToUse) + "\n"
debugText += "Is periodToUse == 4999? " + str.tostring(periodToUse == 4999) + "\n"
plot(ta.sma(close, periodToUse), color = color.red, linewidth = 3)
plot(ta.sma(close, 4999), color = color.blue, linewidth = 3)
// display debug table
var debugTable = table.new(position = position.bottom_right, columns = 1, rows = 1, bgcolor = color.yellow, border_width = 1)
debugText += "End\n"
table.cell(debugTable, column = 0, row = 0, text = debugText, text_color = color.black, bgcolor = color.white)
As you can see, I have added a debug box to do some sanity checks. The for loop ends at the first iteration because apparently there are crosses for a period of 4999. I also check that the value returned == 4999. I then plot the SMA (red colour) band with periodToUse and I also plot another SMA (blue colour) band where I manually set the period to 4999. Obviously, I expect that the two SMAs should overlap. However, this is not the case.
As can be seen, the red SMA weirdly begins shortly after the first-ever candle (although, the period should be 4999), then has an abrupt move down and then it stops. As for the blue SMA, it never appears because a period of 4999 is too high (this is the correct and expected behaviour).
What am I doing wrong?
If I leave the for loop empty (i.e., exclude all the cross-checking logic), it works as expected:
//@
version=5
indicator(title="test", shorttitle="test", overlay=true)
// functions
boolCross(series1, series2) =>
not na(ta.valuewhen(ta.cross(series1, series2), series1, 0))
// initialize
debugText = ""
// demo
var int periodToUse = 0
for thisPeriod = 4999 to 1 by 200
periodToUse := thisPeriod
debugText += "Value of periodToUse: " + str.tostring(periodToUse) + "\n"
debugText += "Is periodToUse == 199? " + str.tostring(periodToUse == 199) + "\n"
plot(ta.sma(close, periodToUse), color = color.red, linewidth = 3)
plot(ta.sma(close, periodToUse) * 5, color = color.red, linewidth = 3)
plot(ta.sma(close, 199), color = color.blue, linewidth = 3)
plot(ta.sma(close, 199) * 5, color = color.blue, linewidth = 3)
// display debug table
var debugTable = table.new(position = position.bottom_right, columns = 1, rows = 1, bgcolor = color.yellow, border_width = 1)
debugText += "End\n"
table.cell(debugTable, column = 0, row = 0, text = debugText, text_color = color.black, bgcolor = color.white)
Only the blue band is visible because it overlaps the red one as expected.
Edit: in response to @John Baron's request for more information:
First do this on the daily BITSTAMP:BTCUSD chart:
plot(ta.sma(close, 1400), color = color.blue, linewidth = 3)
plot(ta.sma(close, 1400) * 5, color = color.blue, linewidth = 3)
You'll see this. This is our reference SMA:
Now replace that code with:
//@version=5
indicator(title="test", shorttitle="test", overlay=true)
// functions
boolCross(series1, series2) =>
ta.cum(ta.cross(series1, series2) ? 1 : 0) > 0
// initialize
debugText = ""
// main
var periodToUse = 0
for thisPeriod = 1400 to 1 by 200
periodToUse := thisPeriod
sma = ta.sma(close, thisPeriod)
boolUpperBandTouch = boolCross(high, sma * 5)
boolLowerBandTouch = boolCross(low, sma)
if boolUpperBandTouch and boolLowerBandTouch
break
debugText += "Value of periodToUse: " + str.tostring(periodToUse) + "\n"
debugText += "Is periodToUse == 1400? " + str.tostring(periodToUse == 1400) + "\n"
plot(ta.sma(close, periodToUse), color = color.red, linewidth = 3) // <===== plots garbage
plot(ta.sma(close, periodToUse) * 5, color = color.red, linewidth = 3) // <===== plots garbage
// display debug table
var debugTable = table.new(position = position.bottom_right, columns = 1, rows = 1, bgcolor = color.yellow, border_width = 1)
table.cell(debugTable, column = 0, row = 0, text = debugText, text_color = color.black, bgcolor = color.white)
You'll see in the debug box on the bottom right corner that the value of periodToUse was 1400 (the same value we used in the reference SMA above. You will also see that the red SMA plot (which is plotted using periodToUse (plot(ta.sma(close, periodToUse), color = color.red, linewidth = 3)) looks completely different in comparison to the reference SMA (blue) which we plotted manually. Why is this? They should both be identical because we are apparently using the same period value.



