[Free Source Code] Multi‑TF Linear Regression HUD (Canvas) – Trend Strength, σ Deviation, Candle Count Dashboard

 

Overview

I’m sharing a free indicator I built: a Multi‑Timeframe Linear Regression HUD rendered with Canvas, designed to show trend strength, deviation from regression, and recent candle bias — all in one compact dashboard.

Useful for discretionary traders who want a quick “market condition snapshot” across multiple timeframes.

Features

  • 5 Timeframes: M1 / M5 / M15 / M30 / H1

  • 3 Linear Regression Periods: configurable (default 20 / 50 / 100)

  • σ‑Deviation Position (%): shows how far the current price is from LR (normalized by σ × deviation factor)

  • Slope Direction: ↑ for positive slope, ↓ for negative

  • Candle Count: Up/Down count for the last N candles

  • Canvas HUD: clean, compact, always-on-screen display

  • Auto‑refresh: updates on every tick + timer

Screenshot

scshot

Source Code (Full MQ5)

Feel free to modify, reuse, or integrate into your own tools.

//+------------------------------------------------------------------+
//|                               TrendlineHD_Hybrid_Wide_V1.mq5    |
//|                                  Copyright 2026, Trading Tools  |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, Trading Tools"
#property version   "1.00"
#property indicator_chart_window
#property indicator_plots 0

#include <Canvas\Canvas.mqh>

//--- Input parameters
input int      InpPeriod1Len = 20;   // Linear Regression Period 1
input int      InpPeriod2Len = 50;   // Linear Regression Period 2
input int      InpPeriod3Len = 100;  // Linear Regression Period 3
input int      InpCountLen   = 10;   // Candle count period (Up/Down)
input double   InpDev        = 2.0;  // Deviation multiplier
input int      InpX          = 800;  // Initial X position
input int      InpY          = 100;  // Initial Y position

//--- Internal settings
CCanvas   m_canvas;
string    m_name = "LR_HUD_Canvas_V2";
int       m_width  = 280; 
int       m_height = 125; 
int       m_row_h  = 18;

string m_tf_names[5] = {"M1","M5","M15","M30","H1"};
ENUM_TIMEFRAMES m_tfs[5] = {PERIOD_M1, PERIOD_M5, PERIOD_M15, PERIOD_M30, PERIOD_H1};
int m_periods[3];

//+------------------------------------------------------------------+
int OnInit()
{
   m_periods[0] = InpPeriod1Len;
   m_periods[1] = InpPeriod2Len;
   m_periods[2] = InpPeriod3Len;

   // Create Canvas HUD
   if(!m_canvas.CreateBitmapLabel(m_name, InpX, InpY, m_width, m_height, COLOR_FORMAT_ARGB_NORMALIZE))
      return(INIT_FAILED);

   string obj_name = m_canvas.ChartObjectName();
   ObjectSetInteger(0, obj_name, OBJPROP_SELECTABLE, true);
   ObjectSetInteger(0, obj_name, OBJPROP_CORNER, CORNER_LEFT_UPPER);

   DrawHUD();
   EventSetTimer(1);
   return(INIT_SUCCEEDED);
}

void OnDeinit(const int reason)
{
   EventKillTimer();
   m_canvas.Destroy();
}

int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[],
                const double &open[], const double &high[], const double &low[],
                const double &close[], const long &tick_volume[], const long &volume[],
                const int &spread[])
{
   DrawHUD();
   return(rates_total);
}

void OnTimer()
{
   DrawHUD();
}

//--- Main drawing function
void DrawHUD()
{
   m_canvas.Erase(ColorToARGB(C'20,20,20', 220));
   m_canvas.Rectangle(0, 0, m_width-1, m_height-1, ColorToARGB(clrDimGray));

   int x_base = 45; 
   int col_w  = 58; 
   int y = 8;

   m_canvas.FontSet("Consolas", -90, FW_BOLD);
   
   // Header: LR periods and candle count
   for(int p=0; p<3; p++)
      m_canvas.TextOut(x_base + (p*col_w) + 35, y, "P:"+IntegerToString(m_periods[p]), ColorToARGB(clrGray), TA_RIGHT);
   
   m_canvas.TextOut(x_base + (3*col_w) + 55, y, "Count("+IntegerToString(InpCountLen)+")", ColorToARGB(clrGray), TA_RIGHT);

   y += m_row_h;

   // Loop through timeframes
   for(int t=0; t<5; t++)
   {
      m_canvas.TextOut(8, y, m_tf_names[t], ColorToARGB(clrWhite));

      MqlRates rates[];
      ArraySetAsSeries(rates, true);

      // Fetch required number of bars
      if(CopyRates(_Symbol, m_tfs[t], 0, InpPeriod3Len, rates) >= InpPeriod3Len)
      {
         // Linear Regression calculations for each period
         for(int p=0; p<3; p++)
         {
            int period = m_periods[p];
            double sumX=0, sumY=0, sumXY=0, sumX2=0;
            
            // Linear regression (i=0 is the latest bar)
            for(int i=0; i<period; i++)
            {
               double xx = (period - 1) - i; // Time axis (positive direction)
               double yy = rates[i].close;
               sumX  += xx;
               sumY  += yy;
               sumXY += xx * yy;
               sumX2 += xx * xx;
            }
            
            double denom = (period * sumX2 - sumX * sumX);
            if(denom == 0) continue;

            double slope = (period * sumXY - sumX * sumY) / denom;
            double intercept = (sumY - slope * sumX) / period;
            double lr_curr = intercept + slope * (period - 1);

            // Standard deviation
            double sumRes=0;
            for(int j=0; j<period; j++)
            {
               double fit = intercept + slope * ((period - 1) - j);
               double res = rates[j].close - fit;
               sumRes += res * res;
            }
            double sigma = MathSqrt(sumRes / period);

            // Position relative to LR (in %)
            double pos_pct = (sigma > 0) ? (rates[0].close - lr_curr) / (sigma * InpDev) * 100.0 : 0;

            uint aCol = (slope > 0) ? ColorToARGB(clrLime) : ColorToARGB(clrRed);
            uint nCol = (pos_pct >= 100) ? ColorToARGB(clrYellow) : (pos_pct <= -100 ? ColorToARGB(clrAqua) : ColorToARGB(clrWhite));
            string arr = (slope > 0) ? "↑" : "↓";

            m_canvas.TextOut(x_base + (p*col_w) + 35, y, DoubleToString(pos_pct, 0), nCol, TA_RIGHT);
            m_canvas.TextOut(x_base + (p*col_w) + 38, y, arr, aCol);
         }

         // Candle count (Up/Down)
         int up=0, dn=0;
         for(int i=0; i<InpCountLen; i++)
         {
            if(rates[i].close > rates[i].open) up++;
            else if(rates[i].close < rates[i].open) dn++;
         }

         string cntStr = IntegerToString(up) + "u:" + IntegerToString(dn) + "d";
         uint cCol = (up > dn) ? ColorToARGB(clrLime) : (dn > up ? ColorToARGB(clrRed) : ColorToARGB(clrWhite));

         m_canvas.TextOut(x_base + (3*col_w) + 55, y, cntStr, cCol, TA_RIGHT);
      }

      y += m_row_h;
   }

   m_canvas.Update();
}

Notes

  • Works on any symbol

  • No chart objects except the Canvas label

  • Lightweight and fast


License

Free to use, modify, and redistribute. No restrictions.

Enjoy!

If this helps your workflow or you create a modified version, I’d love to see it.