Page 1 of 1

How can I use the linear regression as a filter in my own strategy?

Posted: Wed Feb 16, 2022 11:09 am
by EveryDayBetter
Hello. How can I code that my indicator only give a signal, when the price is under the regression line (green line in the middle)? Do you have any idea?

https://bilderupload.org/bild/534488729 ... 009167-111
Image

Re: How can I use the linear regression as a filter in my own strategy?

Posted: Thu Feb 17, 2022 9:42 am
by processingclouds
It would be helpful , if you have the indicator code to draw the line already and than we can guide you on how to implement it as a strategy.

Re: How can I use the linear regression as a filter in my own strategy?

Posted: Thu Feb 17, 2022 9:20 pm
by EveryDayBetter
Thank you for your help. The strategy should also give buy signals, when the price is in the lower deviation and the Pearson's R (between 0 and 1) is over 0,8 ;)

I would like to combine it with a simple moving average strategy as a filter.

Code: Select all

//@version=5
indicator("Moving Average Crosses", overlay=true)

// Get MAs

sma1 = ta.sma(close, 21)
sma2 = ta.sma(close, 50)

// Get crosses
maCrossOver = ta.crossover(sma1, sma2)
maCrossUnder = ta.crossunder(sma1, sma2)

// Draw MAs
plot(sma1, color=color.green)
plot(sma2, color=color.red)

// Draw Crosses
bgcolor(maCrossOver ? color.green : na)
bgcolor(maCrossUnder ? color.red : na)

And here comes the script for the linear regression from tradingview:

Code: Select all

//@version=5
indicator("Linear Regression Channel", shorttitle="LinReg", overlay=true)

lengthInput = input.int(252, title="Length", minval = 1, maxval = 5000)
sourceInput = input.source(close, title="Source")

group1 = "Channel Settings"
useUpperDevInput = input.bool(true, title="Upper Deviation", inline = "Upper Deviation", group = group1)
upperMultInput = input.float(2.0, title="", inline = "Upper Deviation", group = group1)
useLowerDevInput = input.bool(true, title="Lower Deviation", inline = "Lower Deviation", group = group1)
lowerMultInput = input.float(2.0, title="", inline = "Lower Deviation", group = group1)

group2 = "Display Settings"
showPearsonInput = input.bool(true, "Show Pearson's R", group = group2)
extendLeftInput = input.bool(false, "Extend Lines Left", group = group2)
extendRightInput = input.bool(true, "Extend Lines Right", group = group2)
extendStyle = switch
    extendLeftInput and extendRightInput => extend.both
    extendLeftInput => extend.left
    extendRightInput => extend.right
    => extend.none

group3 = "Color Settings"
colorUpper = input.color(color.new(color.blue, 85), "", inline = group3, group = group3)
colorLower = input.color(color.new(color.red, 85), "", inline = group3, group = group3)

calcSlope(source, length) =>
    max_bars_back(source, 5000)
    if not barstate.islast or length <= 1
        [float(na), float(na), float(na)]
    else
        sumX = 0.0
        sumY = 0.0
        sumXSqr = 0.0
        sumXY = 0.0
        for i = 0 to length - 1 by 1
            val = source[i]
            per = i + 1.0
            sumX += per
            sumY += val
            sumXSqr += per * per
            sumXY += val * per
        slope = (length * sumXY - sumX * sumY) / (length * sumXSqr - sumX * sumX)
        average = sumY / length
        intercept = average - slope * sumX / length + slope
        [slope, average, intercept]
        
[s, a, i] = calcSlope(sourceInput, lengthInput)
startPrice = i + s * (lengthInput - 1)
endPrice = i
var line baseLine = na
if na(baseLine) and not na(startPrice)
    baseLine := line.new(bar_index - lengthInput + 1, startPrice, bar_index, endPrice, width=1, extend=extendStyle, color=color.new(colorLower, 0))
else
    line.set_xy1(baseLine, bar_index - lengthInput + 1, startPrice)
    line.set_xy2(baseLine, bar_index, endPrice)
    na
    
calcDev(source, length, slope, average, intercept) =>
    upDev = 0.0
    dnDev = 0.0
    stdDevAcc = 0.0
    dsxx = 0.0
    dsyy = 0.0
    dsxy = 0.0
    periods = length - 1
    daY = intercept + slope * periods / 2
    val = intercept
    for j = 0 to periods by 1
        price = high[j] - val
        if price > upDev
            upDev := price
        price := val - low[j]
        if price > dnDev
            dnDev := price
        price := source[j]
        dxt = price - average
        dyt = val - daY
        price -= val
        stdDevAcc += price * price
        dsxx += dxt * dxt
        dsyy += dyt * dyt
        dsxy += dxt * dyt
        val += slope
    stdDev = math.sqrt(stdDevAcc / (periods == 0 ? 1 : periods))
    pearsonR = dsxx == 0 or dsyy == 0 ? 0 : dsxy / math.sqrt(dsxx * dsyy)
    [stdDev, pearsonR, upDev, dnDev]
    
[stdDev, pearsonR, upDev, dnDev] = calcDev(sourceInput, lengthInput, s, a, i)
upperStartPrice = startPrice + (useUpperDevInput ? upperMultInput * stdDev : upDev)
upperEndPrice = endPrice + (useUpperDevInput ? upperMultInput * stdDev : upDev)
var line upper = na
lowerStartPrice = startPrice + (useLowerDevInput ? -lowerMultInput * stdDev : -dnDev)
lowerEndPrice = endPrice + (useLowerDevInput ? -lowerMultInput * stdDev : -dnDev)
var line lower = na
if na(upper) and not na(upperStartPrice)
    upper := line.new(bar_index - lengthInput + 1, upperStartPrice, bar_index, upperEndPrice, width=1, extend=extendStyle, color=color.new(colorUpper, 0))
else
    line.set_xy1(upper, bar_index - lengthInput + 1, upperStartPrice)
    line.set_xy2(upper, bar_index, upperEndPrice)
    na
if na(lower) and not na(lowerStartPrice)
    lower := line.new(bar_index - lengthInput + 1, lowerStartPrice, bar_index, lowerEndPrice, width=1, extend=extendStyle, color=color.new(colorUpper, 0))
else
    line.set_xy1(lower, bar_index - lengthInput + 1, lowerStartPrice)
    line.set_xy2(lower, bar_index, lowerEndPrice)
    na
linefill.new(upper, baseLine, color = colorUpper)
linefill.new(baseLine, lower, color = colorLower)
    
// Pearson's R
var label r = na
label.delete(r[1])
if showPearsonInput and not na(pearsonR)
    r := label.new(bar_index - lengthInput + 1, lowerStartPrice, str.tostring(pearsonR, "#.################"), color = color.new(color.white, 100), textcolor=color.new(colorUpper, 0), size=size.normal, style=label.style_label_up)

Re: How can I use the linear regression as a filter in my own strategy?

Posted: Sat Feb 19, 2022 3:03 am
by processingclouds
I have combined your two code above, and added code to get the median point and at the end added a boolean isLong to check if it meets : >0.7 Pearson's Value, and close < median line (center line in linear regression) ,

Note: I have commented out close > sma1 and close >sma2, you can add filters as you like

Code: Select all

//@version=5
indicator("Linear Regression Channel", shorttitle="LinReg", overlay=true)

lengthInput = input.int(252, title="Length", minval = 1, maxval = 5000)
sourceInput = input.source(close, title="Source")

group1 = "Channel Settings"
useUpperDevInput = input.bool(true, title="Upper Deviation", inline = "Upper Deviation", group = group1)
upperMultInput = input.float(2.0, title="", inline = "Upper Deviation", group = group1)
useLowerDevInput = input.bool(true, title="Lower Deviation", inline = "Lower Deviation", group = group1)
lowerMultInput = input.float(2.0, title="", inline = "Lower Deviation", group = group1)

group2 = "Display Settings"
showPearsonInput = input.bool(true, "Show Pearson's R", group = group2)
extendLeftInput = input.bool(false, "Extend Lines Left", group = group2)
extendRightInput = input.bool(true, "Extend Lines Right", group = group2)
extendStyle = switch
    extendLeftInput and extendRightInput => extend.both
    extendLeftInput => extend.left
    extendRightInput => extend.right
    => extend.none

group3 = "Color Settings"
colorUpper = input.color(color.new(color.blue, 85), "", inline = group3, group = group3)
colorLower = input.color(color.new(color.red, 85), "", inline = group3, group = group3)

calcSlope(source, length) =>
    max_bars_back(source, 5000)
    if not barstate.islast or length <= 1
        [float(na), float(na), float(na)]
    else
        sumX = 0.0
        sumY = 0.0
        sumXSqr = 0.0
        sumXY = 0.0
        for i = 0 to length - 1 by 1
            val = source[i]
            per = i + 1.0
            sumX += per
            sumY += val
            sumXSqr += per * per
            sumXY += val * per
        slope = (length * sumXY - sumX * sumY) / (length * sumXSqr - sumX * sumX)
        average = sumY / length
        intercept = average - slope * sumX / length + slope
        [slope, average, intercept]
        
[s, a, i] = calcSlope(sourceInput, lengthInput)
startPrice = i + s * (lengthInput - 1)
endPrice = i
var bool createdMedian = false
var line baseLine = na
if na(baseLine) and not na(startPrice)
    baseLine := line.new(bar_index - lengthInput + 1, startPrice, bar_index, endPrice, width=1, extend=extendStyle, color=color.new(colorLower, 0))
    createdMedian := true
else
    line.set_xy1(baseLine, bar_index - lengthInput + 1, startPrice)
    line.set_xy2(baseLine, bar_index, endPrice)
    na
    
calcDev(source, length, slope, average, intercept) =>
    upDev = 0.0
    dnDev = 0.0
    stdDevAcc = 0.0
    dsxx = 0.0
    dsyy = 0.0
    dsxy = 0.0
    periods = length - 1
    daY = intercept + slope * periods / 2
    val = intercept
    for j = 0 to periods by 1
        price = high[j] - val
        if price > upDev
            upDev := price
        price := val - low[j]
        if price > dnDev
            dnDev := price
        price := source[j]
        dxt = price - average
        dyt = val - daY
        price -= val
        stdDevAcc += price * price
        dsxx += dxt * dxt
        dsyy += dyt * dyt
        dsxy += dxt * dyt
        val += slope
    stdDev = math.sqrt(stdDevAcc / (periods == 0 ? 1 : periods))
    pearsonR = dsxx == 0 or dsyy == 0 ? 0 : dsxy / math.sqrt(dsxx * dsyy)
    [stdDev, pearsonR, upDev, dnDev]
    
[stdDev, pearsonR, upDev, dnDev] = calcDev(sourceInput, lengthInput, s, a, i)
upperStartPrice = startPrice + (useUpperDevInput ? upperMultInput * stdDev : upDev)
upperEndPrice = endPrice + (useUpperDevInput ? upperMultInput * stdDev : upDev)
var line upper = na
lowerStartPrice = startPrice + (useLowerDevInput ? -lowerMultInput * stdDev : -dnDev)
lowerEndPrice = endPrice + (useLowerDevInput ? -lowerMultInput * stdDev : -dnDev)
var line lower = na
if na(upper) and not na(upperStartPrice)
    upper := line.new(bar_index - lengthInput + 1, upperStartPrice, bar_index, upperEndPrice, width=1, extend=extendStyle, color=color.new(colorUpper, 0))
else
    line.set_xy1(upper, bar_index - lengthInput + 1, upperStartPrice)
    line.set_xy2(upper, bar_index, upperEndPrice)
    na
if na(lower) and not na(lowerStartPrice)
    lower := line.new(bar_index - lengthInput + 1, lowerStartPrice, bar_index, lowerEndPrice, width=1, extend=extendStyle, color=color.new(colorUpper, 0))
else
    line.set_xy1(lower, bar_index - lengthInput + 1, lowerStartPrice)
    line.set_xy2(lower, bar_index, lowerEndPrice)
    na
linefill.new(upper, baseLine, color = colorUpper)
linefill.new(baseLine, lower, color = colorLower)
    
// Pearson's R
var label r = na
label.delete(r[1])
if showPearsonInput and not na(pearsonR)
    r := label.new(bar_index - lengthInput + 1, lowerStartPrice, str.tostring(pearsonR, "#.################"), color = color.new(color.white, 100), textcolor=color.new(colorUpper, 0), size=size.normal, style=label.style_label_up)
    
sma1 = ta.sma(close, 21)
sma2 = ta.sma(close, 50)
plot (sma1)
plot (sma2)
pointOfMedian = s * ta.barssince(createdMedian) + i
isLong = pearsonR >= 0.7 and close < pointOfMedian // and close > sma1 and close > sma2

if isLong
    y = label.new(bar_index,low,"LONG",color=color.green, style=label.style_label_up, textcolor=color.black)
    label.delete(y[1])

Re: How can I use the linear regression as a filter in my own strategy?

Posted: Sat Feb 19, 2022 3:54 pm
by EveryDayBetter
Thank you very much, it looks pretty good. I have 2 questions.

I've got the error message:

Code: Select all

The variable 'y' is declared in local scope, which may not be executed at every update. So, obtaining its historical values may lead to unexpected results.
for the line

Code: Select all

label.delete(y[1])
What can I do to avoid unexpected result in historical values?

Is there a special reasion that you have choosen 0.7 for the Pearson's Value or can I change it to 0.8?

Re: How can I use the linear regression as a filter in my own strategy?

Posted: Sat Feb 19, 2022 4:49 pm
by processingclouds
Change the last lines of code as follows:

Code: Select all

var label y = na
if isLong
    y := label.new(bar_index,low,"LONG",color=color.green, style=label.style_label_up, textcolor=color.black)
    label.delete(y[1])
We added definition of variable y in parent scope and than changed the declaration to := from =

This will fix the scope warning messages.


There is no special reason, its easier to test for me at 0.7 as my chart was showing 0.7835 value, so if i used 0.7 to check to make sure LONG shows up.

Re: How can I use the linear regression as a filter in my own strategy?

Posted: Sat Feb 19, 2022 5:10 pm
by EveryDayBetter
Thank you, there is no warning message anymore ;)