3

I am attempting to create a TradingView study that draws a line from a crossunder on the current bar to a crossunder on a previous bar, where the previous bar is less than a set maximum number of bars back.

I only want to draw lines with negative slopes (i.e. the previous crossunder happens at a higher value), and I also don't want multiple lines with the same starting point (no overlapping lines).

I am able to draw the lines correctly, but I don't know how to delete lines when they overlap (have the same starting point).

When drawing a new line which will overlap an older one, how do I get a reference to the older line so that I can delete it?

The following do not seem possible in pine script:

  • Iterating over previous values in line series to inspect their x,y values
  • Accessing line series by an index like bar_index
  • Accessing previous line value without also creating a new line
//@version=4
study(title='MACD trend')
src = input(close)
fast = input(12)
slow = input(26)
smooth = input(9)
numBarsBack = input(50)

fast_ma = wma(src, fast)
slow_ma = wma(src, slow)
macd = fast_ma-slow_ma
signal = wma(macd, smooth)
hist = macd - signal

if (crossunder(macd, signal))
// cross under happened on previous bar
    for i = 1 to numBarsBack
    // inspect previous bars up to 'numBarsBack'
        if (crossunder(macd,signal)[i])
            if (macd - macd[i] < 0)
            // located a previous cross under with a higher macd value
                l = line.new(bar_index[1], macd[1], bar_index[i+1], macd[i+1], width=1, color=color.red)
                // drew line from previous cross under to current cross under, 
                // offset x's by 1 bar since crossunder returns true based on previous bar's cross under
                for k = 1 to i
                // inspect previous bars up to the starting point of drawn line
                    if (crossunder(macd, signal)[k] and macd > macd[k])
                    // if the previous cross under value is less than the current one
                        line.delete(l[1])
                        // not sure what the 1 here indexes???

plot(title='MACD', series=macd,transp=0,linewidth=2, color=color.yellow)
plot(title='SIGNAL', series=signal,transp=0,linewidth=2, color=color.red)
ughpines
  • 68
  • 1
  • 5

1 Answers1

3

See comments in code. Made the lines thicker so they are easier to see and added debugging plots at the end of script.

The basic idea is to propagate the line id of the previously created line using the very handy var keyword when initializing the l variable. This way, before creating a new line, we fetch the y2 used to create the previous line so the line can be deleted if its y2 matches the one we are about to create (so was drawn from the same peak).

The crossunder peak detection uses Pine built-ins instead of a for loop. Code will run faster that way.

//@version=4
study(title='MACD trend2')
src = input(close)
fast = input(12)
slow = input(26)
smooth = input(9)
numBarsBack = input(50)

fast_ma = wma(src, fast)
slow_ma = wma(src, slow)
macd = fast_ma-slow_ma
signal = wma(macd, smooth)
hist = macd - signal

xDn = crossunder(macd, signal)
// Get macd at at highest xDn in last numBarsBack bars. If no Xdn found, set value to -10e10.
highestXDnMacd = highest(xDn ? macd : -10e10, numBarsBack)
// Get offset to that point.
highestXDnOffset = - highestbars(xDn ? macd : -10e10, numBarsBack)

// Detect if previous xDn meets all criteria.
lastXDnWasHigher = xDn and macd < highestXDnMacd
// Make l persistent, so that it always contains the line id of the last line created.
var line l = na
if lastXDnWasHigher
    // Retrieve y2 used to draw previous line.
    if line.get_y2(l) == highestXDnMacd
        // Last line drawn used same y2 as the one we are about to use; delete it.
        // No more than one line back can have same peak since previous ones have already been deleted.
        line.delete(l)
    // The line id we assign to l here will persist through future bars,
    // which is what will allow us to delete the corresponding line using the line.delete() above, if needed.
    l := line.new(bar_index[1], macd[1], bar_index - highestXDnOffset, macd[highestXDnOffset], width=3, color=color.black)

plot(title='MACD', series=macd,transp=0,linewidth=2, color=color.yellow)
plot(title='SIGNAL', series=signal,transp=0,linewidth=2, color=color.red)

// Debugging.
plot(highestXDnMacd != -10e10 ? highestXDnMacd : na, "highestXDnMacd", color.silver, 2, plot.style_circles)
plotchar(highestXDnOffset, "highestXDnOffset", "", location.top)    // For Data Window display.
bgcolor(lastXDnWasHigher ? color.green : xDn ? color.silver : na, 60)

enter image description here

PineCoders-LucF
  • 8,288
  • 2
  • 12
  • 21
  • Ah, this solves the issue for me, thanks for the tip! The "var line l" syntax is what I was missing, didn't know you could define a type for a variable without initializing it in pine script. – ughpines Jan 31 '20 at 14:37
  • Happy it was useful to you. `var` actually initializes the variable, but only on the first bar, which has the secondary effect of propagating its value across bars, without the need as in v3, to continuously fetch its value from the last bar when you didn't want to lose it. So while `var` behavior could be reproduced in v3, using it simplifies code, makes it easier to read because it explicitly declares our intention, and is marginally faster than initializing on each bar. – PineCoders-LucF Jan 31 '20 at 23:05