Regression - Excel Linest.
upper chart for anomaly

declare lower;
# ─────────────────────────────────────────────
# │ MarketFragments.com | DNA & Market │
# │ info@marketfragments.com │
# │ www.marketfragments.com │
# | marketfragments going live by 9/15/2025
# ─────────────────────────────────────────────
# Time →
# │
# █ █ █│ █
# █ █ █ │ █ █
# █ █ █ │ █ █ █ ╭─╮
# █ █ █ │ █ █ █ █ ╭─╯ ╰─╮
# █ █ █ │ █ █ █ █ █ █ ╭─╯ ╰─╮
# █ █ █ │ █ █ █ █ █ █ █ █ ╭─╯ ╰─╮
# █ █ █ │ █ █ █ █ █ █ █ █ █ █╭─╯ ╰─╮
# █ █ █ │ █ █ █ █ █ █ █ █ ╰─╮ ╭─╯
# █ █ █ │ █ █ █ █ █ █ ╰─╮ ╭─╯
# █ █ █ │ █ █ █ █ ╰─╮ ╭─╯
# █ █ █ │ █ █ ╰─╮ ╭─╯
# █ █ █ │ █ ╰─────╯
# ──────┴──────────────────────────────────────────────────────────────
# T1 T2 T3 T4 T5 T6
#DATE: 8/28/2025
#Author mcdon030
# LINEST-like Multivariable Regression in ThinkScript with Accuracy Count
# Improved version with true Multiple Linear Regression using Gaussian Elimination for exact coefficients (no approximation)
# === Inputs ===
input length = 66; # Regression period -> Optimized for ES 5 minute
input slippage = 0.005; # Allowable slippage percentage
# === Data Definitions (Independent Variables) ===
def c = close; # Dependent variable (Y)
def o = open; # Independent variable 1 (X1)
def h = high; # Independent variable 2 (X2)
def l = low; # Independent variable 3 (X3)
def v = volume; # Independent variable 4 (X4)
# add the rest for total of 7
def vwp =vwap[1]; # Independent variable 5 (X5) previous bar
def tr =trueRange(h,c,l); # Independent variable 5 (X5) previous bar
def bn = BarNumber();
def nan = Double.NaN;
def lbar = HighestAll(if IsNaN(close) then 0 else bn);
# === Ensure Calculations Start After Sufficient Bars ===
def startCalc = bn > length + 1;
# === Sum Calculations ===
# Note: Sums are over past closed bars: Y (close) from 1 to length ago, X (OHLV) from 2 to length+1 ago
# This fits close_t ~ OHLV_{t-1} on historical data, then predicts close_{t+1} ~ OHLV_t (current)
# Number of samples: n = length
def SumC =CompoundValue(1, if startCalc then fold i1 = 1 to length + 1 with sC do sC + GetValue(c, i1) else nan,0); # Sum Y
# Independent variables' sums (SumX lagged)
def SumO =CompoundValue(1, if startCalc then fold i2 = 1 to length + 1 with sO do sO + GetValue(o, i2 + 1) else nan,0);
def SumH =CompoundValue(1, if startCalc then fold i3 = 1 to length + 1 with sH do sH + GetValue(h, i3 + 1) else nan,0);
def SumL =CompoundValue(1, if startCalc then fold i4 = 1 to length + 1 with sL do sL + GetValue(l, i4 + 1) else nan,0);
def SumV =CompoundValue(1, if startCalc then fold i5 = 1 to length + 1 with sV do sV + GetValue(v, i5 + 1) else nan,0);
# add the rest for total of 7
def SumVwp =CompoundValue(1, if startCalc then fold i6a = 1 to length + 1 with sVwp do sVwp + GetValue(vwp, i6a + 1) else nan,0);
# Sum of squares for independent variables (lagged)
def SumOO =CompoundValue(1, if startCalc then fold i6 = 1 to length + 1 with sOO do sOO + Sqr(GetValue(o, i6 + 1)) else nan,0);
def SumHH =CompoundValue(1, if startCalc then fold i7 = 1 to length + 1 with sHH do sHH + Sqr(GetValue(h, i7 + 1)) else nan,0);
def SumLL =CompoundValue(1, if startCalc then fold i8 = 1 to length + 1 with sLL do sLL + Sqr(GetValue(l, i8 + 1)) else nan,0);
def SumVV =CompoundValue(1, if startCalc then fold i9 = 1 to length + 1 with sVV do sVV + Sqr(GetValue(v, i9 + 1)) else nan,0);
# add the rest for total of 7
def SumVVWAP =CompoundValue(1, if startCalc then fold i20a = 1 to length + 1 with sVVWAP do sVVWAP + Sqr(GetValue(vwp, i20a + 1)) else nan,0);
# Cross-products (Y with lagged X)
def SumOC =CompoundValue(1, if startCalc then fold i10 = 1 to length + 1 with sOC do sOC + GetValue(o, i10 + 1) * GetValue(c, i10) else nan,0);
def SumHC =CompoundValue(1, if startCalc then fold i11 = 1 to length + 1 with sHC do sHC + GetValue(h, i11 + 1) * GetValue(c, i11) else nan,0);
def SumLC =CompoundValue(1, if startCalc then fold i12 = 1 to length + 1 with sLC do sLC + GetValue(l, i12 + 1) * GetValue(c, i12) else nan,0);
def SumVC =CompoundValue(1, if startCalc then fold i13 = 1 to length + 1 with sVC do sVC + GetValue(v, i13 + 1) * GetValue(c, i13) else nan,0);
def SumVWAPC =CompoundValue(1, if startCalc then fold i14a = 1 to length + 1 with sVWAPC do sVWAPC + GetValue(v, i14a + 1) * GetValue(c, i14a) else nan,0);
# Cross-products between independent variables (lagged X)
def SumOH =CompoundValue(1, if startCalc then fold i14 = 1 to length + 1 with sOH do sOH + GetValue(o, i14 + 1) * GetValue(h, i14 + 1) else nan,0);
def SumOL = CompoundValue(1,if startCalc then fold i15 = 1 to length + 1 with sOL do sOL + GetValue(o, i15 + 1) * GetValue(l, i15 + 1) else nan,0);
def SumOV =CompoundValue(1, if startCalc then fold i16 = 1 to length + 1 with sOV do sOV + GetValue(o, i16 + 1) * GetValue(v, i16 + 1) else nan,0);
def SumHL =CompoundValue(1, if startCalc then fold i17 = 1 to length + 1 with sHL do sHL + GetValue(h, i17 + 1) * GetValue(l, i17 + 1) else nan,0);
def SumHV =CompoundValue(1, if startCalc then fold i18 = 1 to length + 1 with sHV do sHV + GetValue(h, i18 + 1) * GetValue(v, i18 + 1) else nan,0);
def SumLV =CompoundValue(1, if startCalc then fold i19 = 1 to length + 1 with sLV do sLV + GetValue(l, i19 + 1) * GetValue(v, i19 + 1) else nan,0);
# add the rest for total of 7
def SumVWAPV =CompoundValue(1, if startCalc then fold i20b= 1 to length + 1 with sLVWAP do sLVWAP + GetValue(l, i20b + 1) * GetValue(v, i20b + 1) else nan,0);
# === Regression Coefficients using Gaussian Elimination for exact MLR ===
# Matrix A = X^T X (5x5), b = X^T Y (5x1)
def n_val = length; # n
def a11 = n_val;
def a12 = SumO;
def a13 = SumH;
def a14 = SumL;
def a15 = SumV;
def a21 = SumO;
def a22 = SumOO;
def a23 = SumOH;
def a24 = SumOL;
def a25 = SumOV;
def a31 = SumH;
def a32 = SumOH;
def a33 = SumHH;
def a34 = SumHL;
def a35 = SumHV;
def a41 = SumL;
def a42 = SumOL;
def a43 = SumHL;
def a44 = SumLL;
def a45 = SumLV;
def a51 = SumV;
def a52 = SumOV;
def a53 = SumHV;
def a54 = SumLV;
def a55 = SumVV;
def bb1 = SumC;
def bb2 = SumOC;
def bb3 = SumHC;
def bb4 = SumLC;
def bb5 = SumVC;
# Gaussian Elimination (forward elimination)
# Step 1: Eliminate column 1
def m21 = if startCalc and a11 != 0 then a21 / a11 else NaN;
def m31 = if startCalc and a11 != 0 then a31 / a11 else NaN;
def m41 = if startCalc and a11 != 0 then a41 / a11 else NaN;
def m51 = if startCalc and a11 != 0 then a51 / a11 else NaN;
def a22_2 = a22 - m21 * a12;
def a23_2 = a23 - m21 * a13;
def a24_2 = a24 - m21 * a14;
def a25_2 = a25 - m21 * a15;
def bb2_2 = bb2 - m21 * bb1;
def a32_2 = a32 - m31 * a12;
def a33_2 = a33 - m31 * a13;
def a34_2 = a34 - m31 * a14;
def a35_2 = a35 - m31 * a15;
def bb3_2 = bb3 - m31 * bb1;
def a42_2 = a42 - m41 * a12;
def a43_2 = a43 - m41 * a13;
def a44_2 = a44 - m41 * a14;
def a45_2 = a45 - m41 * a15;
def bb4_2 = bb4 - m41 * bb1;
def a52_2 = a52 - m51 * a12;
def a53_2 = a53 - m51 * a13;
def a54_2 = a54 - m51 * a14;
def a55_2 = a55 - m51 * a15;
def bb5_2 = bb5 - m51 * bb1;
# Step 2: Eliminate column 2
def m32 = if startCalc and a22_2 != 0 then a32_2 / a22_2 else NaN;
def m42 = if startCalc and a22_2 != 0 then a42_2 / a22_2 else NaN;
def m52 = if startCalc and a22_2 != 0 then a52_2 / a22_2 else NaN;
def a33_3 = a33_2 - m32 * a23_2;
def a34_3 = a34_2 - m32 * a24_2;
def a35_3 = a35_2 - m32 * a25_2;
def bb3_3 = bb3_2 - m32 * bb2_2;
def a43_3 = a43_2 - m42 * a23_2;
def a44_3 = a44_2 - m42 * a24_2;
def a45_3 = a45_2 - m42 * a25_2;
def bb4_3 = bb4_2 - m42 * bb2_2;
def a53_3 = a53_2 - m52 * a23_2;
def a54_3 = a54_2 - m52 * a24_2;
def a55_3 = a55_2 - m52 * a25_2;
def bb5_3 = bb5_2 - m52 * bb2_2;
# Step 3: Eliminate column 3
def m43 = if startCalc and a33_3 != 0 then a43_3 / a33_3 else NaN;
def m53 = if startCalc and a33_3 != 0 then a53_3 / a33_3 else NaN;
def a44_4 = a44_3 - m43 * a34_3;
def a45_4 = a45_3 - m43 * a35_3;
def bb4_4 = bb4_3 - m43 * bb3_3;
def a54_4 = a54_3 - m53 * a34_3;
def a55_4 = a55_3 - m53 * a35_3;
def bb5_4 = bb5_3 - m53 * bb3_3;
# Step 4: Eliminate column 4
def m54 = if startCalc and a44_4 != 0 then a54_4 / a44_4 else NaN;
def a55_5 = a55_4 - m54 * a45_4;
def bb5_5 = bb5_4 - m54 * bb4_4;
# Back Substitution
def BetaV = if startCalc and a55_5 != 0 then bb5_5 / a55_5 else NaN; # Beta for V
def bb4_final = bb4_4 - a45_4 * BetaV;
def BetaL = if startCalc and a44_4 != 0 then bb4_final / a44_4 else NaN; # Beta for L
def bb3_final = bb3_3 - a34_3 * BetaL - a35_3 * BetaV;
def BetaH = if startCalc and a33_3 != 0 then bb3_final / a33_3 else NaN; # Beta for H
def bb2_final = bb2_2 - a23_2 * BetaH - a24_2 * BetaL - a25_2 * BetaV;
def BetaO = if startCalc and a22_2 != 0 then bb2_final / a22_2 else NaN; # Beta for O
def bb1_final = bb1 - a12 * BetaO - a13 * BetaH - a14 * BetaL - a15 * BetaV;
def Intercept = if startCalc and a11 != 0 then bb1_final / a11 else NaN; # Intercept
# === Prediction for Next Close ===
def prediction = if startCalc then Intercept + BetaO * o + BetaH * h + BetaL * l + BetaV * v else NaN;
# === Standard Deviation Bands ===
def UpperBand = prediction * (1 + slippage);
def LowerBand = prediction * (1 - slippage);
# === Accuracy Testing ===
def actualNextClose = GetValue(c, -1);
def actualNextClose2 = GetValue(c, -2);
def actualNextClose3 = GetValue(c, -3);
def actualNextClose5 = GetValue(c, -5);
def predictionError = AbsValue(prediction - actualNextClose) / actualNextClose;
def predictionError2 = AbsValue(prediction - actualNextClose2) / actualNextClose2;
def predictionError3 = AbsValue(prediction - actualNextClose3) / actualNextClose3;
def predictionError5 = AbsValue(prediction - actualNextClose5) / actualNextClose5;
def isAccurate = if predictionError <= slippage then 1 else nan;
def isAccurate2 = if predictionError2 <= slippage then 1 else nan;
def isAccurate3 = if predictionError3 <= slippage then 1 else nan;
def isAccurate5 = if predictionError5 <= slippage then 1 else nan;
# === Accuracy Count ===
def AccurateCount = CompoundValue(1, if !IsNaN(isAccurate) then AccurateCount[1] + 1 else AccurateCount[1], 0);
def AccurateCount2 = CompoundValue(1, if !IsNaN(isAccurate2) then AccurateCount2[1] + 1 else AccurateCount2[1], 0);
def AccurateCount3 = CompoundValue(1, if !IsNaN(isAccurate3) then AccurateCount3[1] + 1 else AccurateCount3[1], 0);
def AccurateCount5 = CompoundValue(1, if !IsNaN(isAccurate5) then AccurateCount5[1] + 1 else AccurateCount5[1], 0);
def percentAccurate = AccurateCount / (bn - length - 1);
def percentAccurate2 = AccurateCount2 / (bn - length - 1);
def percentAccurate3 = AccurateCount3 / (bn - length - 1);
def percentAccurate5 = AccurateCount5 / (bn - length - 1);
# === R-squared Calculation (In-Sample on Training Data) ===
def meanClose = if startCalc then SumC / length else NaN;
def SSR = if startCalc then fold i20 = 1 to length + 1 with ssra do ssra + Sqr(GetValue(c, i20) - (Intercept + BetaO * GetValue(o, i20 + 1) + BetaH * GetValue(h, i20 + 1) + BetaL * GetValue(l, i20 + 1) + BetaV * GetValue(v, i20 + 1))) else NaN;
def SST = if startCalc then fold i21 = 1 to length + 1 with ssta do ssta + Sqr(GetValue(c, i21) - meanClose) else NaN;
def Rsquared = if startCalc and SST != 0 then 1 - (SSR / SST) else NaN;
# - Trade Signals
def signal1 = if prediction < LowerBand[1] then 1 else if prediction > UpperBand[1] then -1 else 0;
def signal = if prediction > close * (1 + slippage) then 1 else if prediction < close * (1 - slippage) then -1 else 0;
# === Visualization ===
plot PredictedClose = if startCalc then prediction else NaN;
PredictedClose.AssignValueColor(if prediction < LowerBand[1] then Color.RED else if prediction > UpperBand[1] then Color.GREEN else Color.CYAN);
plot previousPrediction =prediction[1];
previousPrediction.AssignValueColor(if signal[1]==1 then Color.green else if signal[1]==-1 then Color.red else Color.yellow);
addCloud(previousPrediction ,PredictedClose ,color.red,color.green);
plot Accurate = if isAccurate then prediction else NaN;
Accurate.SetDefaultColor(GetColor(3));
Accurate.SetLineWeight(2);
plot UpperBandPlot =double.nan;# UpperBand[1];
UpperBandPlot.SetDefaultColor(GetColor(5));
plot LowerBandPlot =double.nan;# LowerBand[1];
LowerBandPlot.SetDefaultColor(GetColor(6));
# Clouds for deviations
def top = if prediction > UpperBand[1] then UpperBand[1] else NaN;
def topp = if prediction > UpperBand[1] then prediction else NaN;
def bot = if prediction < LowerBand[1] then LowerBand[1] else NaN;
def botp = if prediction < LowerBand[1] then prediction else NaN;
AddCloud(topp, top, Color.GREEN, Color.GREEN); # Green for above upper
AddCloud(bot, botp, Color.RED, Color.RED); # Red for below lower
# Add Labels for Regression Coefficients
AddLabel(startCalc, "Intercept: " + Round(Intercept, 4), Color.GRAY);
AddLabel(startCalc, "BetaO (Open): " + Round(BetaO, 4), Color.GRAY);
AddLabel(startCalc, "BetaH (High): " + Round(BetaH, 4), Color.GRAY);
AddLabel(startCalc, "BetaL (Low): " + Round(BetaL, 4), Color.GRAY);
AddLabel(startCalc, "BetaV (Volume): " + Round(BetaV, 4), Color.GRAY);
# Add Labels for Prediction Accuracy
AddLabel(startCalc, "R-Squared: " + AsPercent(Rsquared), if Rsquared > 0.6 then Color.GREEN else Color.RED);
#AddLabel(startCalc, "Prediction Accuracy: " + (if isAccurate then "Accurate" else "Not Accurate"),
# if isAccurate then Color.GREEN else Color.RED);
# Add Accuracy Count Labels (fixed typos and descriptions)
AddLabel(startCalc, "Total Accurate Bars (1 Bar): " + AccurateCount, Color.CYAN);
AddLabel(startCalc, "1 Bar % Accurate: " + AsPercent(percentAccurate), Color.CYAN);
AddLabel(startCalc, "2 Bar % Accurate: " + AsPercent(percentAccurate2), Color.CYAN);
AddLabel(startCalc, "3 Bar % Accurate: " + AsPercent(percentAccurate3), Color.CYAN);
AddLabel(startCalc, "5 Bar % Accurate: " + AsPercent(percentAccurate5), Color.CYAN);
# add possible trade direcition
AddChartBubble(signal !=0,PredictedClose, "sig",if signal[1]==1 then Color.green else if signal[1]==-1 then Color.red else Color.CYAN);
AddChartBubble(bn == lbar, PredictedClose, "Predicted Close: " + Round(prediction, 2) + "\nBias: " + (if prediction > close * (1 + slippage) then "Bullish" else if prediction < close * (1 - slippage) then "Bearish" else "Neutral"), if prediction > close * (1 + slippage) then Color.GREEN else if prediction < close * (1 - slippage) then Color.RED else Color.GRAY);
AddLabel(1, "Predicted Close: " + Round(prediction, 2) + " \nBias: " + (if prediction > close * (1 + slippage) then "Bullish" else if prediction < close * (1 - slippage) then "Bearish" else "Neutral") , if prediction > close * (1 + slippage) then Color.GREEN else if prediction < close * (1 - slippage) then Color.RED else Color.GRAY);
declare upper;
# ─────────────────────────────────────────────
# │ MarketFragments.com | DNA & Market │
# │ info@marketfragments.com │
# │ www.marketfragments.com │
# | marketfragments going live by 9/15/2025
# ─────────────────────────────────────────────
# Time →
# │
# █ █ █│ █
# █ █ █ │ █ █
# █ █ █ │ █ █ █ ╭─╮
# █ █ █ │ █ █ █ █ ╭─╯ ╰─╮
# █ █ █ │ █ █ █ █ █ █ ╭─╯ ╰─╮
# █ █ █ │ █ █ █ █ █ █ █ █ ╭─╯ ╰─╮
# █ █ █ │ █ █ █ █ █ █ █ █ █ █╭─╯ ╰─╮
# █ █ █ │ █ █ █ █ █ █ █ █ ╰─╮ ╭─╯
# █ █ █ │ █ █ █ █ █ █ ╰─╮ ╭─╯
# █ █ █ │ █ █ █ █ ╰─╮ ╭─╯
# █ █ █ │ █ █ ╰─╮ ╭─╯
# █ █ █ │ █ ╰─────╯
# ──────┴──────────────────────────────────────────────────────────────
# T1 T2 T3 T4 T5 T6
#DATE: 8/28/2025
#Author mcdon030
# LINEST-like Multivariable Regression in ThinkScript with Accuracy Count
# Improved version with true Multiple Linear Regression using Gaussian Elimination for exact coefficients (no approximation)
# Note: upper chart area is for anamoly detection
# === Inputs ===
input length = 66; # Regression period -> Optimized for ES 5 minute
input slippage = 0.005; # Allowable slippage percentage
# === Data Definitions (Independent Variables) ===
def c = close; # Dependent variable (Y)
def o = open; # Independent variable 1 (X1)
def h = high; # Independent variable 2 (X2)
def l = low; # Independent variable 3 (X3)
def v = volume; # Independent variable 4 (X4)
def vwp =vwap; # Independent variable 5 (X5)
def bn = BarNumber();
def nan = Double.NaN;
def lbar = HighestAll(if IsNaN(close) then 0 else bn);
# === Ensure Calculations Start After Sufficient Bars ===
def startCalc = bn > length + 1;
# === Sum Calculations ===
# Note: Sums are over past closed bars: Y (close) from 1 to length ago, X (OHLV) from 2 to length+1 ago
# This fits close_t ~ OHLV_{t-1} on historical data, then predicts close_{t+1} ~ OHLV_t (current)
# Number of samples: n = length
def SumC =CompoundValue(1, if startCalc then fold i1 = 1 to length + 1 with sC do sC + GetValue(c, i1) else nan,0); # Sum Y
# Independent variables' sums (SumX lagged)
def SumO =CompoundValue(1, if startCalc then fold i2 = 1 to length + 1 with sO do sO + GetValue(o, i2 + 1) else nan,0);
def SumH =CompoundValue(1, if startCalc then fold i3 = 1 to length + 1 with sH do sH + GetValue(h, i3 + 1) else nan,0);
def SumL =CompoundValue(1, if startCalc then fold i4 = 1 to length + 1 with sL do sL + GetValue(l, i4 + 1) else nan,0);
def SumV =CompoundValue(1, if startCalc then fold i5 = 1 to length + 1 with sV do sV + GetValue(v, i5 + 1) else nan,0);
# add the rest for total of 7
def SumVwp =CompoundValue(1, if startCalc then fold i6a = 1 to length + 1 with sVwp do sVwp + GetValue(vwp, i6a + 1) else nan,0);
# Sum of squares for independent variables (lagged)
def SumOO =CompoundValue(1, if startCalc then fold i6 = 1 to length + 1 with sOO do sOO + Sqr(GetValue(o, i6 + 1)) else nan,0);
def SumHH =CompoundValue(1, if startCalc then fold i7 = 1 to length + 1 with sHH do sHH + Sqr(GetValue(h, i7 + 1)) else nan,0);
def SumLL =CompoundValue(1, if startCalc then fold i8 = 1 to length + 1 with sLL do sLL + Sqr(GetValue(l, i8 + 1)) else nan,0);
def SumVV =CompoundValue(1, if startCalc then fold i9 = 1 to length + 1 with sVV do sVV + Sqr(GetValue(v, i9 + 1)) else nan,0);
# add the rest for total of 7
def SumVVWAP =CompoundValue(1, if startCalc then fold i20a = 1 to length + 1 with sVVWAP do sVVWAP + Sqr(GetValue(vwp, i20a + 1)) else nan,0);
# Cross-products (Y with lagged X)
def SumOC =CompoundValue(1, if startCalc then fold i10 = 1 to length + 1 with sOC do sOC + GetValue(o, i10 + 1) * GetValue(c, i10) else nan,0);
def SumHC =CompoundValue(1, if startCalc then fold i11 = 1 to length + 1 with sHC do sHC + GetValue(h, i11 + 1) * GetValue(c, i11) else nan,0);
def SumLC =CompoundValue(1, if startCalc then fold i12 = 1 to length + 1 with sLC do sLC + GetValue(l, i12 + 1) * GetValue(c, i12) else nan,0);
def SumVC =CompoundValue(1, if startCalc then fold i13 = 1 to length + 1 with sVC do sVC + GetValue(v, i13 + 1) * GetValue(c, i13) else nan,0);
def SumVWAPC =CompoundValue(1, if startCalc then fold i14a = 1 to length + 1 with sVWAPC do sVWAPC + GetValue(v, i14a + 1) * GetValue(c, i14a) else nan,0);
# Cross-products between independent variables (lagged X)
def SumOH =CompoundValue(1, if startCalc then fold i14 = 1 to length + 1 with sOH do sOH + GetValue(o, i14 + 1) * GetValue(h, i14 + 1) else nan,0);
def SumOL = CompoundValue(1,if startCalc then fold i15 = 1 to length + 1 with sOL do sOL + GetValue(o, i15 + 1) * GetValue(l, i15 + 1) else nan,0);
def SumOV =CompoundValue(1, if startCalc then fold i16 = 1 to length + 1 with sOV do sOV + GetValue(o, i16 + 1) * GetValue(v, i16 + 1) else nan,0);
def SumHL =CompoundValue(1, if startCalc then fold i17 = 1 to length + 1 with sHL do sHL + GetValue(h, i17 + 1) * GetValue(l, i17 + 1) else nan,0);
def SumHV =CompoundValue(1, if startCalc then fold i18 = 1 to length + 1 with sHV do sHV + GetValue(h, i18 + 1) * GetValue(v, i18 + 1) else nan,0);
def SumLV =CompoundValue(1, if startCalc then fold i19 = 1 to length + 1 with sLV do sLV + GetValue(l, i19 + 1) * GetValue(v, i19 + 1) else nan,0);
# === Regression Coefficients using Gaussian Elimination for exact MLR ===
# Matrix A = X^T X (5x5), b = X^T Y (5x1)
def n_val = length; # n
def a11 = n_val;
def a12 = SumO;
def a13 = SumH;
def a14 = SumL;
def a15 = SumV;
def a21 = SumO;
def a22 = SumOO;
def a23 = SumOH;
def a24 = SumOL;
def a25 = SumOV;
def a31 = SumH;
def a32 = SumOH;
def a33 = SumHH;
def a34 = SumHL;
def a35 = SumHV;
def a41 = SumL;
def a42 = SumOL;
def a43 = SumHL;
def a44 = SumLL;
def a45 = SumLV;
def a51 = SumV;
def a52 = SumOV;
def a53 = SumHV;
def a54 = SumLV;
def a55 = SumVV;
def bb1 = SumC;
def bb2 = SumOC;
def bb3 = SumHC;
def bb4 = SumLC;
def bb5 = SumVC;
# Gaussian Elimination (forward elimination)
# Step 1: Eliminate column 1
def m21 = if startCalc and a11 != 0 then a21 / a11 else nan;
def m31 = if startCalc and a11 != 0 then a31 / a11 else nan;
def m41 = if startCalc and a11 != 0 then a41 / a11 else nan;
def m51 = if startCalc and a11 != 0 then a51 / a11 else nan;
def a22_2 = a22 - m21 * a12;
def a23_2 = a23 - m21 * a13;
def a24_2 = a24 - m21 * a14;
def a25_2 = a25 - m21 * a15;
def bb2_2 = bb2 - m21 * bb1;
def a32_2 = a32 - m31 * a12;
def a33_2 = a33 - m31 * a13;
def a34_2 = a34 - m31 * a14;
def a35_2 = a35 - m31 * a15;
def bb3_2 = bb3 - m31 * bb1;
def a42_2 = a42 - m41 * a12;
def a43_2 = a43 - m41 * a13;
def a44_2 = a44 - m41 * a14;
def a45_2 = a45 - m41 * a15;
def bb4_2 = bb4 - m41 * bb1;
def a52_2 = a52 - m51 * a12;
def a53_2 = a53 - m51 * a13;
def a54_2 = a54 - m51 * a14;
def a55_2 = a55 - m51 * a15;
def bb5_2 = bb5 - m51 * bb1;
# Step 2: Eliminate column 2
def m32 = if startCalc and a22_2 != 0 then a32_2 / a22_2 else nan;
def m42 = if startCalc and a22_2 != 0 then a42_2 / a22_2 else nan;
def m52 = if startCalc and a22_2 != 0 then a52_2 / a22_2 else nan;
def a33_3 = a33_2 - m32 * a23_2;
def a34_3 = a34_2 - m32 * a24_2;
def a35_3 = a35_2 - m32 * a25_2;
def bb3_3 = bb3_2 - m32 * bb2_2;
def a43_3 = a43_2 - m42 * a23_2;
def a44_3 = a44_2 - m42 * a24_2;
def a45_3 = a45_2 - m42 * a25_2;
def bb4_3 = bb4_2 - m42 * bb2_2;
def a53_3 = a53_2 - m52 * a23_2;
def a54_3 = a54_2 - m52 * a24_2;
def a55_3 = a55_2 - m52 * a25_2;
def bb5_3 = bb5_2 - m52 * bb2_2;
# Step 3: Eliminate column 3
def m43 = if startCalc and a33_3 != 0 then a43_3 / a33_3 else nan;
def m53 = if startCalc and a33_3 != 0 then a53_3 / a33_3 else nan;
def a44_4 = a44_3 - m43 * a34_3;
def a45_4 = a45_3 - m43 * a35_3;
def bb4_4 = bb4_3 - m43 * bb3_3;
def a54_4 = a54_3 - m53 * a34_3;
def a55_4 = a55_3 - m53 * a35_3;
def bb5_4 = bb5_3 - m53 * bb3_3;
# Step 4: Eliminate column 4
def m54 = if startCalc and a44_4 != 0 then a54_4 / a44_4 else nan;
def a55_5 = a55_4 - m54 * a45_4;
def bb5_5 = bb5_4 - m54 * bb4_4;
# Back Substitution
def BetaV = if startCalc and a55_5 != 0 then bb5_5 / a55_5 else nan; # Beta for V
def bb4_final = bb4_4 - a45_4 * BetaV;
def BetaL = if startCalc and a44_4 != 0 then bb4_final / a44_4 else nan; # Beta for L
def bb3_final = bb3_3 - a34_3 * BetaL - a35_3 * BetaV;
def BetaH = if startCalc and a33_3 != 0 then bb3_final / a33_3 else nan; # Beta for H
def bb2_final = bb2_2 - a23_2 * BetaH - a24_2 * BetaL - a25_2 * BetaV;
def BetaO = if startCalc and a22_2 != 0 then bb2_final / a22_2 else nan; # Beta for O
def bb1_final = bb1 - a12 * BetaO - a13 * BetaH - a14 * BetaL - a15 * BetaV;
def Intercept = if startCalc and a11 != 0 then bb1_final / a11 else nan; # Intercept
# === Prediction for Next Close ===
def prediction = if startCalc then Intercept + BetaO * o + BetaH * h + BetaL * l + BetaV * v else nan;
# === Standard Deviation Bands ===
def UpperBand = prediction * (1 + slippage);
def LowerBand = prediction * (1 - slippage);
# === Accuracy Testing ===
def actualNextClose = GetValue(c, -1);
def actualNextClose2 = GetValue(c, -2);
def actualNextClose3 = GetValue(c, -3);
def actualNextClose5 = GetValue(c, -5);
def predictionError = AbsValue(prediction - actualNextClose) / actualNextClose;
def predictionError2 = AbsValue(prediction - actualNextClose2) / actualNextClose2;
def predictionError3 = AbsValue(prediction - actualNextClose3) / actualNextClose3;
def predictionError5 = AbsValue(prediction - actualNextClose5) / actualNextClose5;
def isAccurate = if predictionError <= slippage then 1 else nan;
def isAccurate2 = if predictionError2 <= slippage then 1 else nan;
def isAccurate3 = if predictionError3 <= slippage then 1 else nan;
def isAccurate5 = if predictionError5 <= slippage then 1 else nan;
# === Accuracy Count ===
def AccurateCount = CompoundValue(1, if !IsNaN(isAccurate) then AccurateCount[1] + 1 else AccurateCount[1], 0);
def AccurateCount2 = CompoundValue(1, if !IsNaN(isAccurate2) then AccurateCount2[1] + 1 else AccurateCount2[1], 0);
def AccurateCount3 = CompoundValue(1, if !IsNaN(isAccurate3) then AccurateCount3[1] + 1 else AccurateCount3[1], 0);
def AccurateCount5 = CompoundValue(1, if !IsNaN(isAccurate5) then AccurateCount5[1] + 1 else AccurateCount5[1], 0);
def percentAccurate = AccurateCount / (bn - length - 1);
def percentAccurate2 = AccurateCount2 / (bn - length - 1);
def percentAccurate3 = AccurateCount3 / (bn - length - 1);
def percentAccurate5 = AccurateCount5 / (bn - length - 1);
# === R-squared Calculation (In-Sample on Training Data) ===
def meanClose = if startCalc then SumC / length else nan;
def SSR = if startCalc then fold i20 = 1 to length + 1 with ssra do ssra + Sqr(GetValue(c, i20) - (Intercept + BetaO * GetValue(o, i20 + 1) + BetaH * GetValue(h, i20 + 1) + BetaL * GetValue(l, i20 + 1) + BetaV * GetValue(v, i20 + 1))) else nan;
def SST = if startCalc then fold i21 = 1 to length + 1 with ssta do ssta + Sqr(GetValue(c, i21) - meanClose) else nan;
def Rsquared = if startCalc and SST != 0 then 1 - (SSR / SST) else nan;
def signal1 = if prediction < LowerBand[1] then 1 else if prediction > UpperBand[1] then -1 else 0;
def signal2 = if prediction > close * (1 + slippage) then 1 else if prediction < close * (1 - slippage) then -1 else 0;
def signal = if signal1!=0 or signal2!=0 then 1 else nan;
def NRh =
if bn==1 then nan else
if !isnan(signal)
then max(o,c)
else NRh[1];
def NRl =
if bn==1 then nan else
if !isnan(signal)
then min(o,c)
else NRl[1];
plot hh = NRh;
hh.SetPaintingStrategy(PaintingStrategy.Horizontal);
hh.SetDefaultColor(Color.Red);
plot ll = NRl;
ll.SetPaintingStrategy(PaintingStrategy.Horizontal);
ll.SetDefaultColor(Color.Green);
# Add Labels for Regression Coefficients
AddLabel(startCalc, "Intercept: " + Round(Intercept, 4), Color.GRAY);
AddLabel(startCalc, "BetaO (Open): " + Round(BetaO, 4), Color.GRAY);
AddLabel(startCalc, "BetaH (High): " + Round(BetaH, 4), Color.GRAY);
AddLabel(startCalc, "BetaL (Low): " + Round(BetaL, 4), Color.GRAY);
AddLabel(startCalc, "BetaV (Volume): " + Round(BetaV, 4), Color.GRAY);
# Add Labels for Prediction Accuracy
AddLabel(startCalc, "R-Squared: " + AsPercent(Rsquared), if Rsquared > 0.6 then Color.GREEN else Color.RED);
#AddLabel(startCalc, "Prediction Accuracy: " + (if isAccurate then "Accurate" else "Not Accurate"),
# if isAccurate then Color.GREEN else Color.RED);
# Add Accuracy Count Labels (fixed typos and descriptions)
AddLabel(startCalc, "Total Accurate Bars (1 Bar): " + AccurateCount, Color.CYAN);
AddLabel(startCalc, "1 Bar % Accurate: " + AsPercent(percentAccurate), Color.CYAN);
AddLabel(startCalc, "2 Bar % Accurate: " + AsPercent(percentAccurate2), Color.CYAN);
AddLabel(startCalc, "3 Bar % Accurate: " + AsPercent(percentAccurate3), Color.CYAN);
AddLabel(startCalc, "5 Bar % Accurate: " + AsPercent(percentAccurate5), Color.CYAN);

