Page 1 of 1

The Quantum Kalman-Hilbert Filter (The Most Complex Math Ever Applied

Posted: Tue Aug 11, 2026 12:01 pm
by FTtrader
Hey everyone!

If there’s one thing we know at forex-scalping.com, it’s that traditional moving averages are broken. By the time your SMA or EMA crosses, the move is already half over. RSI keeps you trapped in "overbought" zones during massive trends, and MACD just lags you to death.

For the past few months, I've been digging through institutional quantitative papers, trying to find an indicator that adapts to price before the move accelerates. I wanted something that doesn't just average the past, but mathematically attempts to predict the next tick while actively filtering out market noise.

I am excited to release something I’m calling the Quantum Adaptive Kalman-Hilbert Filter (QAKHF). I genuinely believe this might be the most mathematically complicated indicator ever written for the MT4 platform.

Here is the breakdown of how it works and the open-source code so you can run it yourself.

The Math: Aerospace Meets Digital Signal Processing
To eliminate lag while keeping the line smooth, this indicator merges two highly advanced mathematical concepts:

The Kalman Filter [4]: Originally developed in the 1960s by Rudolf Kálmán and used by NASA to calculate the trajectory of spacecraft, a Kalman Filter uses a two-step "predict and update" loop. It literally predicts where the price should be on the next tick, measures the actual price, and corrects its trajectory. It gives you a smooth line with practically zero lag [4].

The Ehlers Hilbert Transform [1]: Developed by signal-processing legend John Ehlers, this math decomposes market cycles into their complex number components: the In-Phase and Quadrature components [1]. It identifies the exact phase of the current market cycle.

What I did: I wrote an algorithm that calculates the instantaneous phase of the market using the Hilbert Transform [1]. The indicator then takes that cycle data and feeds it into the Kalman Filter [4] as a Dynamic Entropy K-Factor.

The Result? When the market is chopping sideways, the filter mathematically increases its noise reduction. The second the market breaks into a trend, the cycle phase shifts, and the filter aggressively snaps to the price action.

How to Trade It
Because this is a scalping community, I optimized the default variables for the M1 and M5 timeframes.

Aqua Line (Velocity > 0): The algorithmic trajectory is upward. Look for long entries on pullbacks.

Magenta Line (Velocity < 0): The algorithmic trajectory is downward. Look for short entries on retracements.

Best Setup: Wait for the Asian session chop to end. The moment London or New York opens, wait for the first color change on the QAKHF. Enter in the direction of the color change, placing your stop loss exactly 1 pip above/below the previous swing high/low.

The MQL4 Source Code
Instructions: Open MetaEditor in your MT4 terminal, create a new Custom Indicator, name it Quantum_Kalman_Hilbert, paste the code below over everything, and hit Compile.

Code snippet

Code: Select all

//+------------------------------------------------------------------+
//|                                  Quantum_Kalman_Hilbert.mq4      |
//|                              Copyright 2026, Forex-Scalping.com  |
//|                                     https://forex-scalping.com   |
//+------------------------------------------------------------------+
#property copyright "Forex-Scalping.com"
#property link      "https://forex-scalping.com"
#property version   "1.00"
#property strict
#property indicator_chart_window
#property indicator_buffers 4
#property indicator_color1 clrAqua
#property indicator_color2 clrMagenta
#property indicator_width1 2
#property indicator_width2 2

//--- Inputs
input double BaseK = 1.0;         // Kalman Base Filter Multiplier
input double Sharpness = 1.0;     // Extrapolation Sharpness
input int    HilbertPeriod = 7;   // Hilbert Transform Cycle Period

//--- Buffers
double UpBuffer[];
double DnBuffer[];
double inPhase[];
double quad[];

//--- Global Variables
double pred, velo, smooth;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   //--- Indicator buffers mapping
   SetIndexBuffer(0, UpBuffer);
   SetIndexBuffer(1, DnBuffer);
   SetIndexBuffer(2, inPhase);
   SetIndexBuffer(3, quad);
   
   //--- Visual settings
   SetIndexStyle(0, DRAW_LINE);
   SetIndexStyle(1, DRAW_LINE);
   SetIndexStyle(2, DRAW_NONE); // Hidden calculation buffer
   SetIndexStyle(3, DRAW_NONE); // Hidden calculation buffer
   
   SetIndexEmptyValue(0, 0.0);
   SetIndexEmptyValue(1, 0.0);
   
   IndicatorShortName("Quantum Kalman-Hilbert (" + DoubleToString(BaseK, 1) + ")");
   
   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[])
  {
   // Require enough bars to calculate the cycle
   if (rates_total < HilbertPeriod + 10) return(0);
   
   int limit = rates_total - prev_calculated;
   
   // Initialization on first run
   if (prev_calculated == 0) 
     {
      limit = rates_total - HilbertPeriod - 2;
      pred = close[limit];
      velo = 0.0;
     }

   for (int i = limit; i >= 0; i--) 
     {
      double price = (high[i] + low[i]) / 2.0;
      
      // Ehlers Hilbert Transform Phase decomposition
      inPhase[i] = price - close[i + HilbertPeriod/2];
      quad[i]    = price - close[i + HilbertPeriod];
      
      // Calculate Instantaneous Phase
      double phase = 0.0;
      if (inPhase[i] != 0.0) 
        {
         phase = MathArctan(quad[i] / inPhase[i]);
        }
        
      // Dynamic Filter Matrix (Kalman K-Factor modulated by Cycle Phase)
      double dynamicK = BaseK + MathAbs(MathSin(phase)); 
      
      // Kalman Filtering Prediction & Update Loop
      double k_scaled = (dynamicK / 10000.0) * 2.0;
      smooth = pred + (price - pred) * MathSqrt(k_scaled) * Sharpness;
      velo = velo + ((dynamicK / 10000.0) * (price - pred));
      pred = smooth + velo;
      
      double kf = pred;
      
      // Velocity-based dynamic coloring
      if (velo > 0.0) 
        {
         UpBuffer[i] = kf;
         DnBuffer[i] = EMPTY_VALUE;
         
         // Bridge the gap for a continuous visual line
         if (i < rates_total - 1 && DnBuffer[i+1] != EMPTY_VALUE) 
           {
            UpBuffer[i+1] = DnBuffer[i+1];
           }
        } 
      else 
        {
         DnBuffer[i] = kf;
         UpBuffer[i] = EMPTY_VALUE;
         
         // Bridge the gap for a continuous visual line
         if (i < rates_total - 1 && UpBuffer[i+1] != EMPTY_VALUE) 
           {
            DnBuffer[i+1] = UpBuffer[i+1];
           }
        }
     }
     
   return(rates_total);
  }
//+------------------------------------------------------------------+
A Word of Warning
Even with aerospace-grade math [4], there is no such thing as a 100% win-rate Holy Grail. This indicator is incredibly responsive, but it is a tool, not an automated ATM machine. Do not run this blindly. Combine the color shifts with pure price action, support/resistance, and proper risk management.

Load it up on your demo accounts, slap it on the EUR/USD M1 chart, and let me know what you guys think of the zero-lag dynamic coloring. Happy scalping!

Re: The Quantum Kalman-Hilbert Filter (The Most Complex Math Ever Applied

Posted: Tue Aug 11, 2026 12:03 pm
by FTtrader
And i prepared code for MT5 as well :-)

When moving from MT4 to MT5, the core math stays exactly the same, but MetaTrader 5 handles data arrays and plotting differently. I've updated the script to reflect MT5's strict architecture:

Time Series Indexing: By default, MT5 indexes arrays backward compared to MT4 (oldest to newest instead of newest to oldest). I added ArraySetAsSeries(..., true) to force MT5 to read the price data the same way MT4 does, keeping our mathematical loop intact.

Buffer Separation: MT5 requires us to explicitly tell it which buffers are meant for the chart (INDICATOR_DATA) and which are just for behind-the-scenes math (INDICATOR_CALCULATIONS).

Plot Directives: Added #property indicator_plots 2 and strictly defined the plot labels so it reads cleanly in your MT5 Data Window.

The MQL5 Source Code
Instructions: Open MetaEditor in your MT5 terminal, create a new Custom Indicator, name it Quantum_Kalman_Hilbert, paste the code below, and hit Compile.

Code: Select all

//+------------------------------------------------------------------+
//|                                  Quantum_Kalman_Hilbert.mq5      |
//|                              Copyright 2026, Forex-Scalping.com  |
//|                                     https://forex-scalping.com   |
//+------------------------------------------------------------------+
#property copyright "Forex-Scalping.com"
#property link      "https://forex-scalping.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 4
#property indicator_plots   2

//--- Plot UpBuffer (Aqua)
#property indicator_label1  "QAKHF Up"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrAqua
#property indicator_style1  STYLE_SOLID
#property indicator_width1  2

//--- Plot DnBuffer (Magenta)
#property indicator_label2  "QAKHF Down"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrMagenta
#property indicator_style2  STYLE_SOLID
#property indicator_width2  2

//--- Inputs
input double BaseK = 1.0;         // Kalman Base Filter Multiplier
input double Sharpness = 1.0;     // Extrapolation Sharpness
input int    HilbertPeriod = 7;   // Hilbert Transform Cycle Period

//--- Buffers
double UpBuffer[];
double DnBuffer[];
double inPhase[];
double quad[];

//--- Global Variables
double pred, velo, smooth;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   //--- Indicator buffers mapping
   SetIndexBuffer(0, UpBuffer, INDICATOR_DATA);
   SetIndexBuffer(1, DnBuffer, INDICATOR_DATA);
   SetIndexBuffer(2, inPhase, INDICATOR_CALCULATIONS);
   SetIndexBuffer(3, quad, INDICATOR_CALCULATIONS);
   
   //--- Set buffers as timeseries (index 0 is the current active bar)
   ArraySetAsSeries(UpBuffer, true);
   ArraySetAsSeries(DnBuffer, true);
   ArraySetAsSeries(inPhase, true);
   ArraySetAsSeries(quad, true);
   
   //--- Set empty values so the color shifts disconnect appropriately
   PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, 0.0);
   PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, 0.0);
   
   IndicatorSetString(INDICATOR_SHORTNAME, "Quantum Kalman-Hilbert (" + DoubleToString(BaseK, 1) + ")");
   
   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[])
  {
   // Require enough bars to calculate the Hilbert cycle
   if (rates_total < HilbertPeriod + 10) return(0);
   
   //--- Set price arrays as timeseries to match MT4 structure
   ArraySetAsSeries(high, true);
   ArraySetAsSeries(low, true);
   ArraySetAsSeries(close, true);
   
   int limit = rates_total - prev_calculated;
   
   // Initialization on first run
   if (prev_calculated == 0) 
     {
      limit = rates_total - HilbertPeriod - 2;
      pred = close[limit];
      velo = 0.0;
     }

   // Main calculation loop
   for (int i = limit; i >= 0; i--) 
     {
      double price = (high[i] + low[i]) / 2.0;
      
      // Ehlers Hilbert Transform Phase decomposition
      inPhase[i] = price - close[i + HilbertPeriod/2];
      quad[i]    = price - close[i + HilbertPeriod];
      
      // Calculate Instantaneous Phase
      double phase = 0.0;
      if (inPhase[i] != 0.0) 
        {
         phase = MathArctan(quad[i] / inPhase[i]);
        }
        
      // Dynamic Filter Matrix (Kalman K-Factor modulated by Cycle Phase)
      double dynamicK = BaseK + MathAbs(MathSin(phase)); 
      
      // Kalman Filtering Prediction & Update Loop
      double k_scaled = (dynamicK / 10000.0) * 2.0;
      smooth = pred + (price - pred) * MathSqrt(k_scaled) * Sharpness;
      velo = velo + ((dynamicK / 10000.0) * (price - pred));
      pred = smooth + velo;
      
      double kf = pred;
      
      // Velocity-based dynamic coloring
      if (velo > 0.0) 
        {
         UpBuffer[i] = kf;
         DnBuffer[i] = 0.0;
         
         // Bridge the gap for a continuous visual line
         if (i < rates_total - 1 && DnBuffer[i+1] != 0.0) 
           {
            UpBuffer[i+1] = DnBuffer[i+1];
           }
        } 
      else 
        {
         DnBuffer[i] = kf;
         UpBuffer[i] = 0.0;
         
         // Bridge the gap for a continuous visual line
         if (i < rates_total - 1 && UpBuffer[i+1] != 0.0) 
           {
            DnBuffer[i+1] = UpBuffer[i+1];
           }
        }
     }
     
   return(rates_total);
  }
//+------------------------------------------------------------------+
Drop this into your MT5 terminal and let me know if it visually lines up with what you're seeing on the MT4 side!

Re: The Quantum Kalman-Hilbert Filter (The Most Complex Math Ever Applied

Posted: Tue Aug 11, 2026 12:04 pm
by FTtrader
And do not worry, i did not forget for Ctraders :-)

Unlike MT4/MT5, cTrader's Calculate method processes bars one by one (index) from left to right, and it recalculates the current open bar on every tick. To prevent the math from distorting during live ticks, I converted the global variables for prediction and velocity into IndicatorDataSeries arrays. This ensures the filter calculates tick-by-tick correctly without corrupting the historical data.

The cTrader (C#) Source Code
Instructions: Open cTrader, navigate to the Automate tab, click New Indicator, name it QuantumKalmanHilbert, paste the code below over the default template, and click the Build icon (or press Ctrl+B).

Code: Select all

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

namespace cAlgo.Indicators
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class QuantumKalmanHilbert : Indicator
    {
        [Parameter("Kalman Base Multiplier", DefaultValue = 1.0, MinValue = 0.1)]
        public double BaseK { get; set; }

        [Parameter("Extrapolation Sharpness", DefaultValue = 1.0, MinValue = 0.1)]
        public double Sharpness { get; set; }

        [Parameter("Hilbert Period", DefaultValue = 7, MinValue = 2)]
        public int HilbertPeriod { get; set; }

        [Output("QAKHF Up", LineColor = "Aqua", PlotType = PlotType.Line, Thickness = 2)]
        public IndicatorDataSeries UpBuffer { get; set; }

        [Output("QAKHF Down", LineColor = "Magenta", PlotType = PlotType.Line, Thickness = 2)]
        public IndicatorDataSeries DnBuffer { get; set; }

        // Hidden calculation series
        private IndicatorDataSeries inPhase;
        private IndicatorDataSeries quad;
        private IndicatorDataSeries predSeries;
        private IndicatorDataSeries veloSeries;

        protected override void Initialize()
        {
            // Initialize hidden buffers for internal math
            inPhase = CreateDataSeries();
            quad = CreateDataSeries();
            predSeries = CreateDataSeries();
            veloSeries = CreateDataSeries();
        }

        public override void Calculate(int index)
        {
            // Require enough historical bars to compute the Hilbert cycle
            if (index < HilbertPeriod + 10)
            {
                // Set the baseline prediction on the final setup bar
                if (index == HilbertPeriod + 9)
                {
                    predSeries[index] = Bars.ClosePrices[index];
                    veloSeries[index] = 0.0;
                }
                return;
            }

            double price = (Bars.HighPrices[index] + Bars.LowPrices[index]) / 2.0;

            // Ehlers Hilbert Transform Phase decomposition
            inPhase[index] = price - Bars.ClosePrices[index - (HilbertPeriod / 2)];
            quad[index] = price - Bars.ClosePrices[index - HilbertPeriod];

            // Calculate Instantaneous Phase
            double phase = 0.0;
            if (inPhase[index] != 0.0)
            {
                phase = Math.Atan(quad[index] / inPhase[index]);
            }

            // Dynamic Filter Matrix (Kalman K-Factor modulated by Cycle Phase)
            double dynamicK = BaseK + Math.Abs(Math.Sin(phase));

            // Fetch previous bar's state variables to prevent tick-level recalculation distortion
            double prevPred = double.IsNaN(predSeries[index - 1]) ? Bars.ClosePrices[index - 1] : predSeries[index - 1];
            double prevVelo = double.IsNaN(veloSeries[index - 1]) ? 0.0 : veloSeries[index - 1];

            // Kalman Filtering Prediction & Update Loop
            double k_scaled = (dynamicK / 10000.0) * 2.0;
            double smooth = prevPred + (price - prevPred) * Math.Sqrt(k_scaled) * Sharpness;
            
            veloSeries[index] = prevVelo + ((dynamicK / 10000.0) * (price - prevPred));
            predSeries[index] = smooth + veloSeries[index];

            double kf = predSeries[index];

            // Velocity-based dynamic coloring
            if (veloSeries[index] > 0.0)
            {
                UpBuffer[index] = kf;
                DnBuffer[index] = double.NaN;

                // Bridge the visual gap when colors change
                if (!double.IsNaN(DnBuffer[index - 1]))
                {
                    UpBuffer[index - 1] = DnBuffer[index - 1];
                }
            }
            else
            {
                DnBuffer[index] = kf;
                UpBuffer[index] = double.NaN;

                // Bridge the visual gap when colors change
                if (!double.IsNaN(UpBuffer[index - 1]))
                {
                    DnBuffer[index - 1] = UpBuffer[index - 1];
                }
            }
        }
    }
}

Re: The Quantum Kalman-Hilbert Filter (The Most Complex Math Ever Applied

Posted: Tue Aug 11, 2026 12:05 pm
by FTtrader
Plus i have created pine code for trading view lovers :-)

Because TradingView handles dynamic color transitions natively on a single plot line, we don't need to split the buffer into two separate series (Up/Down) or write buffer-bridging logic like in MetaTrader or cTrader. Pine Script renders color changes smoothly on the fly.

The Pine Script (v5) Code
Instructions: Open TradingView, open the Pine Editor tab at the bottom, paste the code below over the default script, and click Add to Chart.

Code: Select all

//@version=5
indicator("Quantum Adaptive Kalman-Hilbert Filter", shorttitle="QAKHF", overlay=true)

// --- Inputs
baseK         = input.float(1.0, title="Kalman Base Multiplier", minval=0.1, step=0.1)
sharpness     = input.float(1.0, title="Extrapolation Sharpness", minval=0.1, step=0.1)
hilbertPeriod = input.int(7, title="Hilbert Period", minval=2)

// --- Price Definition
price = hl2

// --- Ehlers Hilbert Transform Phase Decomposition
inPhase = price - close[math.floor(hilbertPeriod / 2)]
quad    = price - close[hilbertPeriod]

// --- Calculate Instantaneous Phase
phase = inPhase != 0.0 ? math.atan(quad / inPhase) : 0.0

// --- Dynamic Filter Matrix (Kalman K-Factor Modulated by Cycle Phase)
dynamicK = baseK + math.abs(math.sin(phase))

// --- State Variables
var float pred = na
var float velo = 0.0

// Handle initial seed values for historical start
prevPred = na(pred[1]) ? close : pred[1]
prevVelo = na(velo[1]) ? 0.0 : velo[1]

// --- Kalman Filtering Prediction & Update Loop
k_scaled = (dynamicK / 10000.0) * 2.0
smooth   = prevPred + (price - prevPred) * math.sqrt(k_scaled) * sharpness

velo := prevVelo + ((dynamicK / 10000.0) * (price - prevPred))
pred := smooth + velo

// --- Dynamic Line Color
filterColor = velo > 0.0 ? color.aqua : color.magenta

// --- Plotting
plot(pred, title="QAKHF Line", color=filterColor, linewidth=2)

Re: The Quantum Kalman-Hilbert Filter (The Most Complex Math Ever Applied

Posted: Tue Aug 11, 2026 12:06 pm
by FTtrader
I hope, that it will be usefull for you :-)

Please let me know, if you like it, or if you want to upgrade something.
Take a care, have a good trades.