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