ProRealCode - Trading & Coding with ProRealTime™
Hi PRC team, hope you guys are well. Thanks for whatever you have been doing wrt PRT/PRC. I’ve used Trend Line Regression indicator on TradingView (https://www.tradingview.com/script/tf2TTN6c/) and I think we PRT community will surely benefit from it. I appreciate is someone could convert it. As the source code is open, I am sharing here. It is combo of a shared library and the indicator code using that library.
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © dandrideng
//@version=5
// @description least_squares_regression: Least squares regression algorithm
library("least_squares_regression", overlay=true)
// @function basic_lsr: Basic least squares regression algorithm
// @param series int[] t: time scale value array corresponding to price
// @param series float[] p: price scale value array corresponding to time
// @param series int array_size: the length of regression array
// @returns reg_slop, reg_intercept, reg_level, reg_stdev
export basic_lsr(series int[] t, series float[] p, series int array_size) =>
p_t = array.new_float(array_size, 0)
t_2 = array.new_float(array_size, 0)
//init array
for i = 0 to array_size - 1
array.set(p_t, i, array.get(p, i) * array.get(t, i))
array.set(t_2, i, array.get(t, i) * array.get(t, i))
//get slop and intercept
sum_t = array.sum(t)
sum_p = array.sum(p)
sum_t_2 = array.sum(t_2)
sum_p_t = array.sum(p_t)
a = (array_size * sum_p_t - sum_p * sum_t) / (array_size * sum_t_2 - math.pow(sum_t, 2))
b = (sum_p - a * sum_t) / array_size
//get regression prediction value
_p = array.new_float(array_size, 0)
for i = 0 to array_size - 1
array.set(_p, i, a * array.get(t, i) + b)
//get regression level
float r1 = 0
float r2 = 0
p_avg = array.avg(p)
for i = 0 to array_size - 1
r1 += math.pow(array.get(_p, i) - p_avg, 2)
r2 += math.pow(array.get(p, i) - p_avg, 2)
r = -math.log10(1 - r1 / r2)
//get regression standard devition
_s = array.new_float(array_size, 0)
for i = 0 to array_size - 1
array.set(_s, i, array.get(p, i) - array.get(_p, i))
s = array.stdev(_s)
//return results
[a, b, r, s]
// @function top_trend_line_lsr: Trend line fitting based on least square algorithm
// @param series int[] t: time scale value array corresponding to price
// @param series float[] p: price scale value array corresponding to time
// @param series int array_size: the length of regression array
// @param string reg_type: regression type in 'top' and 'bottom'
// @param series int max_iter: maximum fitting iterations
// @param series int min_points: the threshold of regression point numbers
// @returns reg_slop, reg_intercept, reg_level, reg_stdev, reg_point_num
export trend_line_lsr(series int[] t, series float[] p, series int array_size, string reg_type, series int max_iter, series int min_points) =>
[a, b, r, s] = basic_lsr(t, p, array_size)
x1 = array.get(t, 0)
x2 = array.get(t, array_size - 1)
n = array_size //Function arguments cannot be mutable, what the fuck!
for i = 0 to max_iter - 1
//exit conditions
if n < min_points
break
//init new tick and price array
_t = array.new_int(n, 0)
_p = array.new_float(n, 0)
_n = 0
//fine the ground truth values that bigger than predictions
for j = 0 to n - 1
if reg_type == 'top'
if (a * array.get(t, j) + b) < array.get(p, j)
array.set(_t, _n, array.get(t, j))
array.set(_p, _n, array.get(p, j))
_n += 1
else if reg_type == 'bottom'
if (a * array.get(t, j) + b) > array.get(p, j)
array.set(_t, _n, array.get(t, j))
array.set(_p, _n, array.get(p, j))
_n += 1
else
break
//exit if new array size is less than threshold
if _n < min_points
break
//override result if r of new array is bigger than last array
[_a, _b, _r, _s] = basic_lsr(_t, _p, _n)
if _r > r
x1 := array.get(_t, 0)
x2 := array.get(_t, _n - 1)
a := _a
b := _b
r := _r
s := _s
n := _n
//after for loop
[x1, x2, a, b, r, s, n]
Now below is indicator, above was using the lib.
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © dandrideng
//@version=5
indicator(title="Trend Line Regression", shorttitle="TLR", overlay=true, max_bars_back=800, max_lines_count=400, max_labels_count=400)
import dandrideng/least_squares_regression/1 as lsr
//trend line regression
lookback_left = input.int(defval=5, title="Pivot Lookback Left", group="Trend Line Regression")
lookback_right = input.int(defval=5, title="Pivot Lookback Right", group="Trend Line Regression")
reg_forward = input.int(defval=20, title="Max Lookback Forward", group="Trend Line Regression")
min_length = input.int(defval=100, title="Min Regression Length", maxval=500, group="Trend Line Regression")
max_length = input.int(defval=200, title="Max Regression Length", maxval=500, group="Trend Line Regression")
length_step = input.int(defval=100, title="Regression Length Steps", group="Trend Line Regression")
max_iteration = input.int(defval=4, title="Max Iterations of Regression", group="Trend Line Regression")
max_points = input.int(defval=30, title="Max Point Numbers of Trend Line", group="Trend Line Regression")
min_points = input.int(defval=3, title="Min Point Numbers of Trend Line", group="Trend Line Regression")
min_reg_level = input.float(defval=4, title="Min Regression Level of Trend Line", group="Trend Line Regression")
std_offset = input.float(defval=0.5, title="Multiply Regression Std", group="Trend Line Regression")
top_line_color = input.color(defval=color.red, title="Color of Top Trend Line", group="Trend Line Regression")
bottom_line_color = input.color(defval=color.green, title="Color of Bottom Trend Line", group="Trend Line Regression")
extend_lines = input.bool(defval=true, title="Extend Lines", group="Trend Line Regression") ? extend.right : extend.none
draw_pivot = input.bool(defval=false, title="Draw Piovt High/Low", group="Trend Line Regression")
show_labels = input.bool(defval=false, title="Show Labels", group="Trend Line Regression")
pivot_high = ta.pivothigh(high, lookback_left, lookback_right)
pivot_low = ta.pivotlow(low, lookback_left, lookback_right)
plot(draw_pivot ? pivot_high : na, offset=-lookback_left)
plot(draw_pivot ? pivot_low : na, offset=-lookback_left)
//check regression (functional)
check_trend_line(start, end, type, a, b) =>
res = true
for i = start + 1 to end - 1
yi = a * i + b
yi_1 = a * (i - 1) + b
if type == "top" and (close[i] > yi and close[i - 1] > yi_1)
res := false
break
else if type == "bottom" and (close[i] < yi and close[i - 1] < yi_1)
res := false
break
res
//draw trend line regressions (functional)
draw_trend_line(forward, length, type) =>
pivot_src = type == "top" ? pivot_high : pivot_low
tick = array.new_int(max_points, 0)
price = array.new_float(max_points, 0)
num = 0
for i = 0 to length - 1
if not na(pivot_src[i + forward]) and num < max_points
array.set(tick, num, i + lookback_left + forward)
array.set(price, num, pivot_src[i + forward])
num := num + 1
if num > 0
[x2, x1, a, b, r, s, n] = lsr.trend_line_lsr(tick, price, num, type, max_iteration, min_points)
y1 = x1 * a + b
y2 = x2 * a + b
o = s * std_offset
if n > min_points and r > min_reg_level and check_trend_line(x1, x2, type, a, b)
var line mid_line = na
mid_line := line.new(x1=bar_index-x1, y1=y1, x2=bar_index-x2, y2=y2)
line.set_width(mid_line, 1)
line.set_color(mid_line, color.new(type == "top" ? top_line_color : bottom_line_color, 25))
line.set_extend(mid_line, extend_lines)
line.set_style(mid_line, line.style_dashed)
var line top_line = na
top_line := line.new(x1=bar_index-x1, y1=y1+o, x2=bar_index-x2, y2=y2+o)
line.set_width(top_line, 1)
line.set_color(top_line, color.new(type == "top" ? top_line_color : bottom_line_color, 25))
line.set_extend(top_line, extend_lines)
var line bottom_line = na
bottom_line := line.new(x1=bar_index-x1, y1=y1-o, x2=bar_index-x2, y2=y2-o)
line.set_width(bottom_line, 1)
line.set_color(bottom_line, color.new(type == "top" ? top_line_color : bottom_line_color, 25))
line.set_extend(bottom_line, extend_lines)
linefill.new(mid_line, top_line, color=color.new(type == "top" ? top_line_color : bottom_line_color, 90))
linefill.new(mid_line, bottom_line, color=color.new(type == "top" ? top_line_color : bottom_line_color, 90))
if show_labels
var label reg_label = na
reg_label := label.new(x=bar_index-x2, y=type == "top" ? y2+o : y2-o, textcolor=color.white)
label.set_color(reg_label, color.new(type == "top" ? top_line_color : bottom_line_color, 30))
label.set_text(reg_label, "Level: " + str.tostring(r, "#.###") + "\nPoints: " + str.tostring(n, "#"))
label.set_style(reg_label, type == "top" ? label.style_label_down : label.style_label_up)
//delete all lines
all_lines = line.all
if array.size(all_lines) > 0
for i = 0 to array.size(all_lines) - 1
line.delete(array.get(all_lines, i))
//delete all labels
all_labels = label.all
if array.size(all_labels) > 0
for i = 0 to array.size(all_labels) - 1
label.delete(array.get(all_labels, i))
//trend line
for l = min_length to max_length by length_step
draw_trend_line(reg_forward, l, "top")
draw_trend_line(reg_forward, l, "bottom")
//end of file
Here is a possible translation:
// -------------------------------------
// PRC_Trend Line Regression
// version = 0
// 03.03.2026
// Iván González @ www.prorealcode.com
// Sharing ProRealTime knowledge
// -------------------------------------
defparam drawonlastbaronly = true
// -------------------------------------
// === PARAMETERS ===
// -------------------------------------
prdR = 5 // Pivot Lookback Right
prdL = prdR // Pivot Lookback Left
forward = 20 // Max Lookback Forward / Extension
minRegLen = 100 // Min Regression Length
maxRegLen = 200 // Max Regression Length
regSteps = 100 // Regression Length Steps
maxIter = 4 // Max Iterations of Regression
maxPts = 30 // Max Point Numbers of Trend Line
minPts = 3 // Min Point Numbers of Trend Line
minLevel = 1 // Min Regression Level (original=4)
stdMult = 0.5 // Multiply Regression Std
// -------------------------------------
// === STEP 1: DETECT PIVOTS ===
// -------------------------------------
once phCnt = 0
once plCnt = 0
if barindex >= prdL + prdR then
isPH = 1
for k = 0 to prdL + prdR do
if k <> prdL then
if high[prdR] < high[prdR - prdL + k] then
isPH = 0
endif
endif
next
if isPH then
$phP[phCnt] = high[prdR]
$phB[phCnt] = barindex - prdR
phCnt = phCnt + 1
endif
isPL = 1
for k = 0 to prdL + prdR do
if k <> prdL then
if low[prdR] > low[prdR - prdL + k] then
isPL = 0
endif
endif
next
if isPL then
$plP[plCnt] = low[prdR]
$plB[plCnt] = barindex - prdR
plCnt = plCnt + 1
endif
endif
// --------------------------------------------------
// === STEP 2: CALCULATE + DRAW (last bar only) ===
// --------------------------------------------------
if islastbarupdate then
numSteps = round((maxRegLen - minRegLen) / max(1, regSteps))
for stepIdx = 0 to numSteps do
tryLen = minRegLen + stepIdx * regSteps
// ============================================
// TOP TREND LINE (pivot highs)
// ============================================
nTop = 0
for i = 0 to phCnt - 1 do
detOff = barindex - ($phB[i] + prdR)
if detOff >= forward and detOff <= forward + tryLen - 1 and nTop < maxPts then
$tW[nTop] = detOff + prdL
$pW[nTop] = $phP[i]
nTop = nTop + 1
endif
next
if nTop > minPts then
sT = 0
sP = 0
sT2 = 0
sPT = 0
for i = 0 to nTop - 1 do
sT = sT + $tW[i]
sP = sP + $pW[i]
sT2 = sT2 + $tW[i] * $tW[i]
sPT = sPT + $pW[i] * $tW[i]
next
dd = nTop * sT2 - sT * sT
if dd <> 0 then
tSlp = (nTop * sPT - sP * sT) / dd
tInt = (sP - tSlp * sT) / nTop
pAv = sP / nTop
s1 = 0
s2v = 0
sDf = 0
for i = 0 to nTop - 1 do
pp = tSlp * $tW[i] + tInt
s1 = s1 + SQUARE(pp - pAv)
s2v = s2v + SQUARE($pW[i] - pAv)
sDf = sDf + SQUARE($pW[i] - pp)
next
tStd = SQRT(sDf / max(1, nTop))
itr = 0
if s2v > 0 then
rr = s1 / s2v
if rr > 0 and rr < 1 then
itr = -LOG(1 - rr) / LOG(10)
elsif rr >= 1 then
itr = 999
endif
endif
// Iterative TOP fitting
for i = 0 to nTop - 1 do
$tI[i] = $tW[i]
$pI[i] = $pW[i]
next
nI = nTop
cSlp = tSlp
cInt = tInt
cR = itr
for iter = 0 to maxIter - 1 do
if nI <= minPts then
break
endif
nF = 0
for j = 0 to nI - 1 do
pp = cSlp * $tI[j] + cInt
if $pI[j] > pp then
$tF[nF] = $tI[j]
$pF[nF] = $pI[j]
nF = nF + 1
endif
next
if nF <= minPts then
break
endif
sT = 0
sP = 0
sT2 = 0
sPT = 0
for i = 0 to nF - 1 do
sT = sT + $tF[i]
sP = sP + $pF[i]
sT2 = sT2 + $tF[i] * $tF[i]
sPT = sPT + $pF[i] * $tF[i]
next
dd = nF * sT2 - sT * sT
if dd = 0 then
break
endif
nSlp = (nF * sPT - sP * sT) / dd
nInt = (sP - nSlp * sT) / nF
pAv = sP / nF
s1 = 0
s2v = 0
sDf = 0
for i = 0 to nF - 1 do
pp = nSlp * $tF[i] + nInt
s1 = s1 + SQUARE(pp - pAv)
s2v = s2v + SQUARE($pF[i] - pAv)
sDf = sDf + SQUARE($pF[i] - pp)
next
nR = 0
if s2v > 0 then
rr = s1 / s2v
if rr > 0 and rr < 1 then
nR = -LOG(1 - rr) / LOG(10)
elsif rr >= 1 then
nR = 999
endif
endif
if nR > cR then
tSlp = nSlp
tInt = nInt
itr = nR
tStd = SQRT(sDf / max(1, nF))
cSlp = nSlp
cInt = nInt
cR = nR
nI = nF
for k = 0 to nF - 1 do
$tI[k] = $tF[k]
$pI[k] = $pF[k]
next
else
break
endif
next
// DRAW TOP if valid
if nI > minPts and itr > minLevel then
txLeft = $tI[0]
oSt = tStd * stdMult
yL = tSlp * txLeft + tInt
yExt = tSlp * (-forward) + tInt
drawsegment(barindex - txLeft, yL, barindex + forward, yExt) coloured(220, 60, 60) style(dottedline, 1)
drawsegment(barindex - txLeft, yL + oSt, barindex + forward, yExt + oSt) coloured(220, 60, 60) style(line, 1)
drawsegment(barindex - txLeft, yL - oSt, barindex + forward, yExt - oSt) coloured(220, 60, 60) style(line, 1)
endif
endif
endif
// ============================================
// BOTTOM TREND LINE (pivot lows)
// ============================================
nBot = 0
for i = 0 to plCnt - 1 do
detOff = barindex - ($plB[i] + prdR)
if detOff >= forward and detOff <= forward + tryLen - 1 and nBot < maxPts then
$tW[nBot] = detOff + prdL
$pW[nBot] = $plP[i]
nBot = nBot + 1
endif
next
if nBot > minPts then
sT = 0
sP = 0
sT2 = 0
sPT = 0
for i = 0 to nBot - 1 do
sT = sT + $tW[i]
sP = sP + $pW[i]
sT2 = sT2 + $tW[i] * $tW[i]
sPT = sPT + $pW[i] * $tW[i]
next
dd = nBot * sT2 - sT * sT
if dd <> 0 then
bSlp = (nBot * sPT - sP * sT) / dd
bInt = (sP - bSlp * sT) / nBot
pAv = sP / nBot
s1 = 0
s2v = 0
sDf = 0
for i = 0 to nBot - 1 do
pp = bSlp * $tW[i] + bInt
s1 = s1 + SQUARE(pp - pAv)
s2v = s2v + SQUARE($pW[i] - pAv)
sDf = sDf + SQUARE($pW[i] - pp)
next
bStd = SQRT(sDf / max(1, nBot))
bR = 0
if s2v > 0 then
rr = s1 / s2v
if rr > 0 and rr < 1 then
bR = -LOG(1 - rr) / LOG(10)
elsif rr >= 1 then
bR = 999
endif
endif
// Iterative BOTTOM fitting
for i = 0 to nBot - 1 do
$tI[i] = $tW[i]
$pI[i] = $pW[i]
next
nI = nBot
cSlp = bSlp
cInt = bInt
cR = bR
for iter = 0 to maxIter - 1 do
if nI <= minPts then
break
endif
nF = 0
for j = 0 to nI - 1 do
pp = cSlp * $tI[j] + cInt
if $pI[j] < pp then
$tF[nF] = $tI[j]
$pF[nF] = $pI[j]
nF = nF + 1
endif
next
if nF <= minPts then
break
endif
sT = 0
sP = 0
sT2 = 0
sPT = 0
for i = 0 to nF - 1 do
sT = sT + $tF[i]
sP = sP + $pF[i]
sT2 = sT2 + $tF[i] * $tF[i]
sPT = sPT + $pF[i] * $tF[i]
next
dd = nF * sT2 - sT * sT
if dd = 0 then
break
endif
nSlp = (nF * sPT - sP * sT) / dd
nInt = (sP - nSlp * sT) / nF
pAv = sP / nF
s1 = 0
s2v = 0
sDf = 0
for i = 0 to nF - 1 do
pp = nSlp * $tF[i] + nInt
s1 = s1 + SQUARE(pp - pAv)
s2v = s2v + SQUARE($pF[i] - pAv)
sDf = sDf + SQUARE($pF[i] - pp)
next
nR = 0
if s2v > 0 then
rr = s1 / s2v
if rr > 0 and rr < 1 then
nR = -LOG(1 - rr) / LOG(10)
elsif rr >= 1 then
nR = 999
endif
endif
if nR > cR then
bSlp = nSlp
bInt = nInt
bR = nR
bStd = SQRT(sDf / max(1, nF))
cSlp = nSlp
cInt = nInt
cR = nR
nI = nF
for k = 0 to nF - 1 do
$tI[k] = $tF[k]
$pI[k] = $pF[k]
next
else
break
endif
next
// DRAW BOTTOM if valid
if nI > minPts and bR > minLevel then
bxLeft = $tI[0]
oSt = bStd * stdMult
yL = bSlp * bxLeft + bInt
yExt = bSlp * (-forward) + bInt
drawsegment(barindex - bxLeft, yL, barindex + forward, yExt) coloured(46, 180, 80) style(dottedline, 1)
drawsegment(barindex - bxLeft, yL + oSt, barindex + forward, yExt + oSt) coloured(46, 180, 80) style(line, 1)
drawsegment(barindex - bxLeft, yL - oSt, barindex + forward, yExt - oSt) coloured(46, 180, 80) style(line, 1)
endif
endif
endif
next // stepIdx
endif
return
I see attached, green and red trendlines both under and over the same bars … is this how the Indicator is supposed to look or do I need more coffee!!?? 😀
Re my post above (now after caffeine-fix!) I guess the red and green show support and resistance channel / trendlines.
Another oddity 🙂 … each time a new bar forms, an audible Alert is triggered, but an Alert is not listed under ‘Alert Status’.
Is the Alert embedded in the code somehow??
Anybody know how to stop the Alert … it’s getting on my nerves! 🙂
Aha, it’s not when used as an Indicator.
It’s when the code is on backtest as an Auto-Algo that an Alert sounds! Well weird, I’ve never had this before!
For info:
I can now see multiple red and green trendlines / channels all overlapping etc as per attached.
Thanks for the feedback GraHal. The key parameter here is minLevel .It controls the minimum R² level required to accept a trend line. With 1 it is too permissive and you get many overlapping lines. The original value in TradingView is 4, but in PRT it can be too restrictive and may not draw anything on many charts. I recommend trying values between 2 and 4 depending on your preference. The higher the value, the fewer lines but more significant.
This topic contains 13 replies,
has 2 voices, and was last updated by
Iván González
23 minutes ago.
| Forum: | TradingView to ProRealTime Translation Center Forum |
| Started: | 10/30/2023 |
| Status: | Active |
| Attachments: | 4 files |
The information collected on this form is stored in a computer file by ProRealCode to create and access your ProRealCode profile. This data is kept in a secure database for the duration of the member's membership. They will be kept as long as you use our services and will be automatically deleted after 3 years of inactivity. Your personal data is used to create your private profile on ProRealCode. This data is maintained by SAS ProRealCode, 407 rue Freycinet, 59151 Arleux, France. If you subscribe to our newsletters, your email address is provided to our service provider "MailChimp" located in the United States, with whom we have signed a confidentiality agreement. This company is also compliant with the EU/Swiss Privacy Shield, and the GDPR. For any request for correction or deletion concerning your data, you can directly contact the ProRealCode team by email at privacy@prorealcode.com If you would like to lodge a complaint regarding the use of your personal data, you can contact your data protection supervisory authority.