Code: Select all
//@version=5
indicator("Machine Learning Supertrend", overlay = true, timeframe = "", timeframe_gaps = true)
// Parameters
atrPeriod = input.int(25, "ATR Length", minval = 1)
factor = input.float(2.2, "Factor", minval = 0.01, step = 0.01)
sigma = 0.03
forecast = input.int(3, "Forecast Period", minval = 0) // Number of bars to forecast
// Source
src = input.source(close, 'Source')
// Kernel Function (Gaussian Process Regression)
rbf(x1, x2, l) => math.exp(-math.pow(x1 - x2, 2) / (2.0 * math.pow(l, 2)))
kernel_matrix(X1, X2, l) =>
km = matrix.new<float>(X1.size(), X2.size())
for i = 0 to X1.size() - 1
for j = 0 to X2.size() - 1
km.set(i, j, rbf(X1.get(i), X2.get(j), l))
km
// Initialize Gaussian Process Regression
var identity = matrix.new<int>(atrPeriod, atrPeriod, 0)
var array<float> K_row = na
if barstate.isfirst
xtrain = array.new<int>(0)
xtest = array.new<int>(0)
// Training data setup
for i = 0 to atrPeriod-1
for j = 0 to atrPeriod-1
identity.set(i, j, i == j ? 1 : 0)
xtrain.push(i)
// Test data (future prediction)
for i = 0 to atrPeriod-1 + forecast
xtest.push(i)
// Compute kernel matrices
s = identity.mult(sigma * sigma)
Ktrain = kernel_matrix(xtrain, xtrain, atrPeriod).sum(s)
K_inv = Ktrain.pinv()
K_star = kernel_matrix(xtrain, xtest, atrPeriod)
K_row := K_star.transpose().mult(K_inv).row(atrPeriod-1 + forecast)
// Machine Learning Moving Average
var float prev_supertrend = na
mean = ta.sma(src, atrPeriod)
// ML Prediction with Forecast
float out = na
if bar_index > atrPeriod
dotprod = 0.
for i = 0 to atrPeriod-1
dotprod += K_row.get(i) * (src[atrPeriod-1 - i] - mean)
out := dotprod + mean
// Use forecasted value
predicted_value = out[forecast]
// ML-based ATR estimation
mae = ta.sma(math.abs(src - predicted_value), atrPeriod) * factor
upper = predicted_value + mae
lower = predicted_value - mae
// Supertrend Calculation
float supertrend = na
if prev_supertrend == na
supertrend := close > lower ? lower : upper
else
supertrend := close > prev_supertrend ? lower : upper
// Ensure the trend follows the previous one if not broken
supertrend := na(supertrend) ? prev_supertrend : supertrend
prev_supertrend := supertrend
// Detect trend direction (1 = bullish, 0 = bearish)
trend_direction = supertrend == lower ? 1 : 0
// Plot Up & Down Trend Lines
upTrend = plot(trend_direction == 1 ? supertrend : na, "Up Trend", color = color.green, style = plot.style_linebr)
downTrend = plot(trend_direction == 0 ? supertrend : na, "Down Trend", color = color.red, style = plot.style_linebr)
// Middle of the candle (used for filling)
bodyMiddle = plot(barstate.isfirst ? na : (open + close) / 2, "Body Middle", display = display.none)
// Fill areas
fill(bodyMiddle, upTrend, color.new(color.green, 90), fillgaps = false)
fill(bodyMiddle, downTrend, color.new(color.red, 90), fillgaps = false)
// Alerts for trend change
alertcondition(trend_direction != trend_direction[1], title='Trend Change', message='Supertrend ML changed direction')