Page 1 of 1

GARCH Stochastic Volatility Forecaster for Scalping

Posted: Mon Aug 10, 2026 3:46 pm
by FTtrader
Hey everyone,
If you are scalping the lower timeframes (M1, M5) using traditional volatility indicators like ATR or Bollinger Bands, you've probably noticed a glaring flaw: they are entirely backward-looking. By the time your standard deviation indicator tells you the market is volatile, the move has already happened, and you are buying the absolute top of a breakout before it whipsaws.Institutional quants don't just measure historical volatility; they forecast it. One of the most robust ways to do this is using a GARCH (Generalized Autoregressive Conditional Heteroskedasticity) model. I’ve built a lightweight MT4 indicator that brings this stochastic volatility forecasting to our charts. Here is a breakdown of how it works, how to trade it, and the open-source MQL4 code so you can compile it yourself.

The Core Concept: Why GARCH?
Financial markets exhibit a phenomenon called volatility clustering — calm periods tend to be followed by calm periods, and violent price swings tend to trigger more violent price swings. The GARCH(1,1) model captures this perfectly. Instead of just taking a simple average of the last 14 candles like an ATR, GARCH calculates the conditional variance of the current candle based on three distinct factors:$$GARCH(1,1): \sigma_t^2 = \omega + \alpha \epsilon_{t-1}^2 + \beta \sigma_{t-1}^2$$$\omega$ (Omega): The baseline, long-term variance floor. $\alpha$ (Alpha): The "shock" sensitivity. This dictates how aggressively the model reacts to yesterday's price spike.$\beta$ (Beta): The volatility persistence. This dictates how long the "echo" of a volatile event lasts in the market.(Note: For the math to stay stable, Alpha + Beta must be less than 1).

How to Apply It in Scalping

Because GARCH is highly responsive to recent shocks while remembering historical persistence, it’s an incredible filter for scalpers: Filtering the "Dead Zone": Don't take breakout trades when the GARCH line is flat and resting at its baseline (Omega). The market lacks the underlying energy to sustain a move.Catching the Expansion: The golden setup is when price compresses into a tight range, but your GARCH line begins to tick upward sharply. This indicates a "shock" has entered the order flow, and volatility is expanding.Dynamic Position Sizing: This is the real secret. When the GARCH value is high, reduce your lot size. When the GARCH value is low, increase your lot size. This targets a constant risk profile across all trades, preventing high-volatility chop from blowing your daily drawdown limit.

The MT4 Code (MQL4)
Here is the source code. Open your MetaEditor, create a new Custom Indicator, paste this in, and compile.

Code: Select all

//+------------------------------------------------------------------+
//|                                        GARCH_Forecaster.mq4      |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "Open Source Trading Community"
#property link      ""
#property version   "1.00"
#property strict
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_color1 clrDodgerBlue
#property indicator_width1 2

//--- Inputs for GARCH(1,1) parameters
input double InpOmega = 0.000005; // Baseline Volatility (Omega)
input double InpAlpha = 0.08;     // Shock Reaction (Alpha)
input double InpBeta  = 0.90;     // Volatility Persistence (Beta)

//--- Indicator buffer
double GarchBuffer[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   SetIndexBuffer(0, GarchBuffer);
   SetIndexStyle(0, DRAW_LINE);
   IndicatorShortName("GARCH(1,1) ("+DoubleToStr(InpAlpha,2)+","+DoubleToStr(InpBeta,2)+")");
   
   if(InpAlpha + InpBeta >= 1.0)
      Print("Warning: Alpha + Beta should be < 1 for a stationary model.");
      
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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[])
  {
   if(rates_total < 2) return(0);

   int limit;
   // Determine how many bars need to be calculated
   if(prev_calculated == 0)
     {
      limit = rates_total - 2;
      GarchBuffer[rates_total-1] = 0.0; // Seed the oldest bar
     }
   else
     {
      limit = rates_total - prev_calculated;
     }

   // Standard MT4 loop (calculating from oldest to newest bar)
   for(int i = limit; i >= 0; i--)
     {
      // 1. Calculate the recent shock (percentage return)
      double ret = (close[i] - close[i+1]) / close[i+1];
      double shock2 = ret * ret; // epsilon squared
      
      // 2. Fetch the previous variance
      double prev_var = GarchBuffer[i+1] * GarchBuffer[i+1]; 
      
      // 3. Apply the GARCH(1,1) formula
      double current_var = InpOmega + (InpAlpha * shock2) + (InpBeta * prev_var);
      
      // 4. Store standard deviation (volatility) in the buffer for plotting
      GarchBuffer[i] = MathSqrt(current_var);
     }

   return(rates_total);
  }
//+------------------------------------------------------------------+
Parameter Tuning Tips
Out of the box, Alpha = 0.08 and Beta = 0.90 are highly standard parameters for equity and forex markets.

If you find the indicator is too noisy during M1 scalping, try increasing Beta (e.g., 0.94) and lowering Alpha (e.g., 0.04) to force the model to respect historical persistence more than sudden ticks.

If you want it to react lightning-fast to breakouts, do the reverse.

Drop it on your charts alongside your normal setup and watch how the curve anticipates the consolidation/expansion cycles. Let me know what you guys think or if you need help tweaking the logic!

Re: GARCH Stochastic Volatility Forecaster for Scalping

Posted: Mon Aug 10, 2026 3:47 pm
by FTtrader
Here is the translated MQL5 version of the GARCH(1,1) indicator for MetaTrader 5.

The biggest change behind the scenes is how MT5 handles time-series arrays. Unlike MT4, which counts backwards (where 0 is the current candle), MT5 arrays count forwards chronologically (where 0 is the oldest candle on your chart). This actually makes writing iterative formulas like GARCH much cleaner, as we can just loop forward through time.

The MT5 Code (MQL5)
Open your MetaEditor 5, create a new Custom Indicator, and paste this in:

Code: Select all

//+------------------------------------------------------------------+
//|                                        GARCH_Forecaster.mq5      |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "Open Source Trading Community"
#property link      ""
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots   1

//--- Plot setup
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrDodgerBlue
#property indicator_width1  2
#property indicator_label1  "GARCH(1,1)"

//--- Inputs for GARCH(1,1) parameters
input double InpOmega = 0.000005; // Baseline Volatility (Omega)
input double InpAlpha = 0.08;     // Shock Reaction (Alpha)
input double InpBeta  = 0.90;     // Volatility Persistence (Beta)

//--- Indicator buffer
double GarchBuffer[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   // Bind the array to the indicator buffer
   SetIndexBuffer(0, GarchBuffer, INDICATOR_DATA);
   
   // Set the short name for the Data Window and chart subwindow
   string short_name = "GARCH(1,1) (" + DoubleToString(InpAlpha, 2) + ", " + DoubleToString(InpBeta, 2) + ")";
   IndicatorSetString(INDICATOR_SHORTNAME, short_name);
   
   // Basic validation
   if(InpAlpha + InpBeta >= 1.0)
      Print("Warning: Alpha + Beta should be < 1 for a stationary model.");
      
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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[])
  {
   // Ensure we have enough bars to calculate
   if(rates_total < 2) return(0);

   int start_index;

   // Determine where to start the calculation loop
   if(prev_calculated == 0)
     {
      start_index = 1; // Start at index 1 because we need index 0 (the previous bar) to calculate the first return
      GarchBuffer[0] = 0.0; // Seed the oldest historical bar
     }
   else
     {
      // Go back one bar to ensure the current forming bar is constantly updated
      start_index = prev_calculated - 1; 
     }

   // MQL5 processes chronologically: 0 is the oldest bar, rates_total-1 is the newest
   for(int i = start_index; i < rates_total; i++)
     {
      // 1. Calculate the recent shock (percentage return from the previous candle)
      double ret = 0.0;
      if(close[i-1] != 0) // Prevent division by zero
        {
         ret = (close[i] - close[i-1]) / close[i-1];
        }
      double shock2 = ret * ret; // Epsilon squared
      
      // 2. Fetch the previous variance
      double prev_var = GarchBuffer[i-1] * GarchBuffer[i-1]; 
      
      // 3. Apply the GARCH(1,1) formula
      double current_var = InpOmega + (InpAlpha * shock2) + (InpBeta * prev_var);
      
      // 4. Store standard deviation (volatility) in the buffer for plotting
      GarchBuffer[i] = MathSqrt(current_var);
     }

   // Return rates_total so the platform knows exactly how many bars have been calculated
   return(rates_total);
  }
//+------------------------------------------------------------------+
Key Differences from the MT4 Version:
INDICATOR_DATA property: MT5 explicitly requires you to define what type of buffer you are mapping with SetIndexBuffer(0, GarchBuffer, INDICATOR_DATA).

Chronological Loop: Notice the loop now runs for(int i = start_index; i < rates_total; i++). We are reading left-to-right on the chart, taking the previous bar [i-1] to calculate the current state of bar .

Division by Zero Check: Added a strict check (if(close[i-1] != 0)) which is best practice in MT5 to prevent unexpected array errors on highly illiquid assets or bad broker data feeds.

Re: GARCH Stochastic Volatility Forecaster for Scalping

Posted: Mon Aug 10, 2026 3:49 pm
by FTtrader
And here it is for Ic traders in Ctrader:

Moving from MetaTrader to IC Markets' cTrader platform means we are making a massive leap in underlying technology. cTrader uses C# (via the cTrader Automate API), which is a fully object-oriented language.

Unlike MetaTrader where you have to manually write a for loop to iterate through every candle on the chart, cTrader's architecture handles the loop for you. The platform simply calls a Calculate(int index) method for every single bar from left to right. This makes mathematical formulas like GARCH much cleaner to write.

The cTrader Code (C#)
Open your cTrader platform, go to the Automate tab on the left menu, click New Indicator, and replace the default template with this code:

Code: Select all

using System;
using cAlgo.API;
using cAlgo.API.Internals;

namespace cAlgo
{
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class GARCH_Forecaster : Indicator
    {
        //--- Inputs for GARCH(1,1) parameters
        [Parameter("Baseline Volatility (Omega)", DefaultValue = 0.000005, MinValue = 0)]
        public double Omega { get; set; }

        [Parameter("Shock Reaction (Alpha)", DefaultValue = 0.08, MinValue = 0, MaxValue = 1)]
        public double Alpha { get; set; }

        [Parameter("Volatility Persistence (Beta)", DefaultValue = 0.90, MinValue = 0, MaxValue = 1)]
        public double Beta { get; set; }

        //--- Indicator Output Plot
        [Output("GARCH(1,1)", LineColor = "DodgerBlue", Thickness = 2)]
        public IndicatorDataSeries GarchBuffer { get; set; }

        protected override void Initialize()
        {
            // Basic validation printed to the cTrader Automate Log
            if (Alpha + Beta >= 1.0)
            {
                Print("Warning: Alpha + Beta should be < 1 for a stationary model.");
            }
        }

        public override void Calculate(int index)
        {
            // Seed the oldest bar on the chart with 0
            if (index < 1)
            {
                GarchBuffer[index] = 0.0;
                return;
            }

            // 1. Calculate the recent shock (percentage return from the previous candle)
            double ret = 0.0;
            if (Bars.ClosePrices[index - 1] != 0) // Prevent division by zero
            {
                ret = (Bars.ClosePrices[index] - Bars.ClosePrices[index - 1]) / Bars.ClosePrices[index - 1];
            }
            
            double shock2 = ret * ret; // Epsilon squared

            // 2. Fetch the previous variance
            // Since GarchBuffer holds the standard deviation, squaring it gives us the variance back
            double prev_var = GarchBuffer[index - 1] * GarchBuffer[index - 1];

            // 3. Apply the GARCH(1,1) formula
            double current_var = Omega + (Alpha * shock2) + (Beta * prev_var);

            // 4. Store standard deviation (volatility) in the buffer for plotting
            GarchBuffer[index] = Math.Sqrt(current_var);
        }
    }
}
How to Compile and Use:
Once you've pasted the code into the editor, click the Build button (the hammer icon at the top of the Automate window) or press Ctrl + B.

If the build is successful, you will see a green success message at the bottom left.

Go back to your trading chart, right-click, select Indicators -> Custom, and you will see GARCH_Forecaster in the list.

cTrader C# Advantages:
Notice how we used [Parameter] attributes at the top? cTrader automatically generates a beautiful user interface for your indicator settings based on these. I also added MinValue = 0 and MaxValue = 1 attributes to the Alpha and Beta parameters, so the cTrader UI will physically prevent you from accidentally typing in a negative number or a number greater than 1, keeping the GARCH math safe from breaking!

Re: GARCH Stochastic Volatility Forecaster for Scalping

Posted: Fri Aug 14, 2026 12:43 pm
by PTScalper
I remember, that i learned about Stochastic at University in Prague :D

But i will have to check it, it seems to me interesting.
We will see, may be i will use it.

Re: GARCH Stochastic Volatility Forecaster for Scalping

Posted: Mon Aug 17, 2026 3:00 pm
by FTtrader
Yeah, i think that it will be usefull for you :-)

I also plan to share some printscreens.