IC Markets

The Kalman Filter in Forex Scalping

Optimize MetaTrader 4, MetaTrader 5, cTrader, and TradingView for speed. Discuss Level II Market Depth (DOM), custom hotkeys, and volume indicators.
Post Reply
PTScalper
Site Admin
Posts: 210
Joined: Mon Jul 20, 2026 1:28 pm

The Kalman Filter in Forex Scalping

Post by PTScalper »

Hi scalpers,

i prepared for you another interesting filter for your forex scalping.
Its called Kalman filter.

In forex scalping, every pip counts, and the battle between market noise and indicator lag is relentless. Traditional tools like the Simple Moving Average (SMA) or Exponential Moving Average (EMA) suffer from a fundamental flaw on lower timeframes: to reduce the erratic noise of M1 or M5 charts, you must increase the lookback period, which inevitably introduces lag. By the time a standard moving average confirms a shift, a scalper’s optimal entry window has often already closed.This is where the Kalman Filter Moving Average fundamentally shifts the paradigm. Originally developed in 1960 for aerospace navigation to track moving objects through noisy radar data, it approaches forex prices not as a static historical average, but as a dynamic state estimation problem. It operates in a continuous two-step recursive loop: prediction and correction. First, the algorithm predicts the next price based on current momentum. When the actual price tick arrives, it measures the deviation or "error." Instead of treating all price action equally, the Kalman Filter dynamically adjusts its own sensitivity. If the market is ranging and noisy (high measurement uncertainty), the filter "trusts" its previous trend state, staying smooth and keeping you out of choppy, false breakouts. When momentum surges and a clear trend emerges, it immediately accelerates its response, snapping tight to the price action with minimal lag.For algorithmic and discretionary scalpers, this provides a mathematically superior way to separate true directional intent from random tick fluctuations. When integrated into Expert Advisors, it allows for tighter stop-losses, cleaner breakout entries, and faster exits. It is an ideal mathematical engine for a modern scalping toolkit, outperforming static averages by adapting to volatility in real time.Before diving into the code, you can use this interactive tool to visualize how adjusting the Kalman filter's sensitivity parameters allows it to cut through noise faster than a standard lagging SMA.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 210
Joined: Mon Jul 20, 2026 1:28 pm

Re: The Kalman Filter in Forex Scalping

Post by PTScalper »

Here it is implementation for MT4 traders:

MT4 Indicator Code (MQL4)
Here is a clean, compilable MQL4 implementation of the Kalman Filter.

Note on architecture: Many poorly coded MT4 filters suffer from state-corruption (repainting) because they use global variables that break when multiple ticks hit the same bar. This code uses a dual-buffer system—one for the visual line and a hidden one for the Error Covariance—ensuring the mathematical state is preserved perfectly on every tick.

Code: Select all

//+------------------------------------------------------------------+
//|                                                Kalman_Filter.mq4 |
//|                                      Generated for Forex Scalping|
//+------------------------------------------------------------------+
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_color1 clrDarkOrange
#property indicator_width1 2

//--- input parameters
extern double ProcessNoise = 0.001;     // Q: Uncertainty in the model (Speed of adaptation)
extern double MeasurementNoise = 0.1;   // R: Trust in incoming data (Smoothing)

//--- indicator buffers
double KalmanBuffer[];
double CovarianceBuffer[]; // Hidden buffer to prevent tick-repainting

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   // Visible Kalman Line
   SetIndexStyle(0, DRAW_LINE);
   SetIndexBuffer(0, KalmanBuffer);
   SetIndexLabel(0, "Kalman Filter");
   
   // Hidden Covariance State
   SetIndexStyle(1, DRAW_NONE);
   SetIndexBuffer(1, CovarianceBuffer);
   
   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[])
  {
   int limit;
   
   // Not enough bars on chart
   if(rates_total < 2) return(0);
   
   // First run initialization
   if(prev_calculated == 0)
     {
      limit = rates_total - 2;
      KalmanBuffer[rates_total - 1] = close[rates_total - 1];
      CovarianceBuffer[rates_total - 1] = 1.0;
     }
   else
     {
      // Process only new bars/ticks
      limit = rates_total - prev_calculated;
     }

   // Process from oldest uncalculated bar down to the newest tick (index 0)
   for(int i = limit; i >= 0; i--)
     {
      // Retrieve state from the previous historical bar
      double prevState = KalmanBuffer[i+1];
      double prevCov = CovarianceBuffer[i+1];
      
      // --- 1. Predict Step ---
      // Error covariance increases by process noise (Q)
      double p_predict = prevCov + ProcessNoise;
      
      // --- 2. Update Step ---
      // Calculate Kalman Gain (K)
      double kalmanGain = p_predict / (p_predict + MeasurementNoise);
      
      // Update state estimate with the new measurement
      KalmanBuffer[i] = prevState + kalmanGain * (close[i] - prevState);
      
      // Update error covariance for the next tick/bar
      CovarianceBuffer[i] = (1.0 - kalmanGain) * p_predict;
     }
     
   return(rates_total);
  }
//+------------------------------------------------------------------+
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 210
Joined: Mon Jul 20, 2026 1:28 pm

Re: The Kalman Filter in Forex Scalping

Post by PTScalper »

Here is the converted Kalman Filter Moving Average indicator natively optimized for MetaTrader 5 (MQL5).

When trading on true ECN environments like IC Markets, execution speed and tick processing efficiency are critical. MQL5 handles data arrays differently than MQL4 (indexing from left-to-right, where 0 is the oldest historical bar instead of the newest). This rewritten code leverages native MQL5 indexing, avoiding the overhead of ArraySetAsSeries() to ensure the absolute fastest calculation times on every single raw tick.

Code: Select all

//+------------------------------------------------------------------+
//|                                                Kalman_Filter.mq5 |
//|                                      Generated for Forex Scalping|
//|                                     Optimized for ECN/IC Markets |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots   1

//--- plot settings for Kalman Filter
#property indicator_label1  "Kalman Filter"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrDarkOrange
#property indicator_style1  STYLE_SOLID
#property indicator_width1  2

//--- input parameters
input double ProcessNoise = 0.001;     // Q: Uncertainty in the model (Speed of adaptation)
input double MeasurementNoise = 0.1;   // R: Trust in incoming data (Smoothing)

//--- indicator buffers
double KalmanBuffer[];
double CovarianceBuffer[]; // Hidden buffer for state preservation

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   // Bind visible line to buffer 0
   SetIndexBuffer(0, KalmanBuffer, INDICATOR_DATA);
   
   // Bind hidden covariance state to buffer 1 (Calculations only, not drawn)
   SetIndexBuffer(1, CovarianceBuffer, INDICATOR_CALCULATIONS);
   
   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[])
  {
   // Wait until we have enough data
   if(rates_total < 2) 
      return(0);
   
   int start_index;
   
   // First run initialization
   if(prev_calculated == 0)
     {
      // Index 0 is the oldest bar in history in native MQL5
      start_index = 1;
      KalmanBuffer[0] = close[0];
      CovarianceBuffer[0] = 1.0;
     }
   else
     {
      // On subsequent ticks, start calculating from the last known unclosed bar
      // Subtracting 1 ensures the current active tick is recalculated properly
      start_index = prev_calculated - 1;
     }

   // Process array from oldest to newest (native MQL5 direction)
   for(int i = start_index; i < rates_total; i++)
     {
      // Retrieve state from the previous bar (i-1)
      double prevState = KalmanBuffer[i-1];
      double prevCov = CovarianceBuffer[i-1];
      
      // --- 1. Predict Step ---
      // Error covariance increases by process noise (Q)
      double p_predict = prevCov + ProcessNoise;
      
      // --- 2. Update Step ---
      // Calculate Kalman Gain (K)
      double kalmanGain = p_predict / (p_predict + MeasurementNoise);
      
      // Update state estimate with the new measurement
      KalmanBuffer[i] = prevState + kalmanGain * (close[i] - prevState);
      
      // Update error covariance for the next loop iteration
      CovarianceBuffer[i] = (1.0 - kalmanGain) * p_predict;
     }
     
   // Return the rates_total to become prev_calculated on the next tick
   return(rates_total);
  }
//+------------------------------------------------------------------+
Key Differences for MT5 Deployment:
INDICATOR_CALCULATIONS Flag: In MT5, hidden arrays (like the Covariance buffer) must be explicitly flagged as calculation buffers so the terminal doesn't try to draw them.

Left-to-Right Indexing: Loop iterations start at prev_calculated - 1 and run up to rates_total. This prevents the indicator from recalculating the entire chart history every time IC Markets pushes a micro-pip change, ensuring zero terminal lag.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 210
Joined: Mon Jul 20, 2026 1:28 pm

Re: The Kalman Filter in Forex Scalping

Post by PTScalper »

Here is the Kalman Filter rewritten in C# for the cTrader Automate (cAlgo) environment. Like the MetaTrader versions, it uses a hidden internal data series to store the mathematical state, ensuring the indicator does not repaint or corrupt its calculations when flooded with high-frequency IC Markets tick data.

cTrader Indicator Code (C#)

Code: Select all

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

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class KalmanFilterMA : Indicator
    {
        // --- Input Parameters ---
        [Parameter("Process Noise (Q)", DefaultValue = 0.001, MinValue = 0.00001, Step = 0.001)]
        public double ProcessNoise { get; set; }

        [Parameter("Measurement Noise (R)", DefaultValue = 0.1, MinValue = 0.01, Step = 0.01)]
        public double MeasurementNoise { get; set; }

        // --- Visible Chart Output ---
        [Output("Kalman Filter", LineColor = "DarkOrange", Thickness = 2)]
        public IndicatorDataSeries KalmanBuffer { get; set; }

        // --- Hidden Internal State ---
        private IndicatorDataSeries CovarianceBuffer;

        protected override void Initialize()
        {
            // Initialize the hidden data series for storing the covariance state
            CovarianceBuffer = CreateDataSeries();
        }

        public override void Calculate(int index)
        {
            // Handle the very first historical bar
            if (index == 0)
            {
                KalmanBuffer[index] = Bars.ClosePrices[index];
                CovarianceBuffer[index] = 1.0;
                return;
            }

            // Retrieve mathematical state from the previous, fully closed bar (index - 1)
            // This prevents tick-data corruption during the formation of the current live bar
            double prevState = KalmanBuffer[index - 1];
            double prevCov = CovarianceBuffer[index - 1];

            // --- 1. Predict Step ---
            // The model's uncertainty increases slightly based on the Process Noise
            double p_predict = prevCov + ProcessNoise;

            // --- 2. Update Step ---
            // Calculate Kalman Gain (K) to decide how much to trust the new price tick
            double kalmanGain = p_predict / (p_predict + MeasurementNoise);

            // Update the filter's state with the current price
            KalmanBuffer[index] = prevState + kalmanGain * (Bars.ClosePrices[index] - prevState);

            // Save the updated error covariance for the next tick
            CovarianceBuffer[index] = (1.0 - kalmanGain) * p_predict;
        }
    }
}
How to Install it in cTrader:

1.) Open cTrader and go to the Automate tab on the left menu.

2.) Click the New button under the Indicators section.

3.) Replace the default template code with the code above.

4.) Click the Build icon (or press F6) at the top of the editor.

5.) The "KalmanFilterMA" will now be available in your custom indicators list on any cTrader chart.

Hope it will be usefull for you, thank you, take a care.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Post Reply