Page 1 of 1
Why Your Scalping MAs Lag: Introducing the Zero-Lag Adaptive Kalman Filter for M1 & Tick Charts
Posted: Sun Jul 26, 2026 4:02 pm
by PTScalper
Are you tired of getting whipped out of M1 scalps because your moving averages react two candles too late? The unavoidable curse of traditional retail technical analysis is the lag-versus-noise trade-off. If you smooth out erratic intrabar price spikes using standard EMAs or WMAs, you create fatal lag that ruins your risk-to-reward ratio. If you speed up your indicator periods to catch early moves, you get chopped to pieces by spread fluctuations and false breakouts during consolidation.To survive in ultra-short-term forex scalping, we have to abandon static retail averages and look at how high-frequency institutional desks process market data: Digital Signal Processing (DSP). Unlike standard arithmetic tools, an Adaptive Kalman Filter is a recursive Bayesian estimator. It does not just blindly average historical closing prices. Instead, it uses probability matrices to continuously predict where the price should be on the very next tick, and then instantly corrects that trajectory based on real-time measurement error.How the 2-State Engine Eliminates LagTo make this viable for live M1 and tick trading, we implemented a 2-State Constant Velocity (CV) model with Innovation Gating. Instead of tracking just one dimension, our mathematical engine tracks two state variables simultaneously:Estimated Price ($p_k$)Instantaneous Velocity / Momentum ($v_k$)Here is the mathematical secret to eliminating lag: When the market is drifting sideways in a tight range, the filter keeps its internal process noise low. It acts as a super-smoothed baseline that completely ignores sub-pip noise and spread widening. But the exact millisecond an aggressive institutional buyer steps in and spikes the price, the algorithm calculates the Mahalanobis distance (the normalized squared prediction error). If this prediction error breaches a 95% statistical confidence threshold, the filter recognizes a structural market breakout. It dynamically inflates its covariance matrix, forcing the Kalman Gain to jump immediately toward 1.0. In plain English: the indicator instantly "snaps" to the live breakout price on the very first tick without any trailing lag.How to Execute Scalping SetupsZero-Lag Momentum Entries: We do not trade traditional moving average crossovers. We monitor the Kalman Velocity parameter ($v_k$). When the filter line shifts from red (negative momentum) to lime green (positive momentum) during an active London or New York session, the trend has mathematically accelerated—triggering an immediate buy execution.Absorption & Exhaustion Traps: When price pushes hard away from the Kalman baseline but the Velocity parameter begins to flatten out while making a new high, you are witnessing liquidity absorption. Large limit orders are trapping aggressive retail buyers—prepare for an immediate mean-reversion short setup.The Ultimate Order Flow Filter: For maximum strike rate, combine this Kalman momentum line with sub-pip Order Flow Delta. Only take long scalps when Kalman velocity is positive and aggressive Ask volume dominates the tape.Whether you are developing EAs in MQL4, MQL5, or cTrader C#, upgrading from static moving averages to an adaptive Kalman mathematical core will completely transform your execution timing. Stop letting indicator lag eat your profit margins! Who else here is experimenting with DSP or adaptive algorithms in their scalping loops? Let’s discuss your parameter settings below!
Re: Why Your Scalping MAs Lag: Introducing the Zero-Lag Adaptive Kalman Filter for M1 & Tick Charts
Posted: Sun Jul 26, 2026 4:02 pm
by PTScalper
For IC trader:
Code: Select all
using System;
namespace cAlgo.API.Indicators
{
/// <summary>
/// Adaptivní 2-State Kalmanův Filtr pro High-Frequency Scalping.
/// Zpracovává cenu i momentum bez zpoždění pomocí adaptivní inflace kovariance.
/// </summary>
public sealed class ZeroLagAdaptiveKalman
{
// Stavové proměnné (State Vector x)
private double _p; // Odhadovaná cena (Price)
private double _v; // Odhadovaná rychlost / momentum (Velocity)
// Kovarianční matice chyby odhadu P (2x2 matice rozvinutá do skalárů)
private double _p00, _p01, _p10, _p11;
// Parametry šumu
private readonly double _q00; // Procesní šum ceny
private readonly double _q11; // Procesní šum rychlosti
private readonly double _r; // Šum měření (tržní šum / spread noise)
private readonly double _gammaThreshold; // Práh pro detekci průrazu (např. 3.84)
private bool _isInitialized;
/// <summary>
/// Inicializace jádra filtru.
/// </summary>
/// <param name="processNoisePrice">Variabilita ceny (např. 0.00001)</param>
/// <param name="processNoiseVelocity">Variabilita momenta (např. 0.000001)</param>
/// <param name="measurementNoise">Šum trhu (např. 0.001 nebo odvozeno z ATR)</param>
/// <param name="gammaThreshold">Práh Mahalanobisovy vzdálenosti pro adaptaci (standardně 3.84)</param>
public ZeroLagAdaptiveKalman(double processNoisePrice = 1e-5,
double processNoiseVelocity = 1e-6,
double measurementNoise = 1e-3,
double gammaThreshold = 3.84)
{
_q00 = processNoisePrice;
_q11 = processNoiseVelocity;
_r = measurementNoise;
_gammaThreshold = gammaThreshold;
_isInitialized = false;
}
/// <summary>
/// Zpracuje nový tick nebo uzavírací cenu a vrátí odhadovanou cenu bez lagu.
/// </summary>
public double Update(double measurement, out double currentVelocity)
{
if (!_isInitialized)
{
_p = measurement;
_v = 0.0;
_p00 = 1.0; _p01 = 0.0;
_p10 = 0.0; _p11 = 1.0;
_isInitialized = true;
currentVelocity = _v;
return _p;
}
// --- 1. PREDIKCE (Predict Step) ---
// x_pred = F * x => p_pred = p + v, v_pred = v
double pPred = _p + _v;
double vPred = _v;
// P_pred = F * P * F^T + Q
double p00Pred = _p00 + _p01 + _p10 + _p11 + _q00;
double p01Pred = _p01 + _p11;
double p10Pred = _p10 + _p11;
double p11Pred = _p11 + _q11;
// --- 2. ADAPTACE NA VOLATILITU (Innovation Gating) ---
double y = measurement - pPred; // Inovace (chyba predikce)
double s = p00Pred + _r; // Kovariance inovace
double epsilon = (y * y) / s; // Normalizovaná čtvercová chyba
// Pokud inovace překročí práh, trh proráží. Nafoukneme kovarianci!
if (epsilon > _gammaThreshold)
{
double inflation = Math.Sqrt(epsilon);
p00Pred *= inflation;
p01Pred *= inflation;
p10Pred *= inflation;
p11Pred *= inflation;
s = p00Pred + _r; // Přepočítání S po inflaci
}
// --- 3. KOREKCE (Update Step) ---
// Kalman Gain matice K = P_pred * H^T * S^{-1}
double k0 = p00Pred / s; // Zisk pro cenu
double k1 = p10Pred / s; // Zisk pro rychlost
// Aktualizace stavu x = x_pred + K * y
_p = pPred + (k0 * y);
_v = vPred + (k1 * y);
// Aktualizace kovariance P = (I - K * H) * P_pred
_p00 = (1.0 - k0) * p00Pred;
_p01 = (1.0 - k0) * p01Pred;
_p10 = p10Pred - (k1 * p00Pred);
_p11 = p11Pred - (k1 * p01Pred);
currentVelocity = _v;
return _p;
}
/// <summary>
/// Resetuje stav při změně instrumentu nebo odpojení.
/// </summary>
public void Reset() => _isInitialized = false;
}
}
Re: Why Your Scalping MAs Lag: Introducing the Zero-Lag Adaptive Kalman Filter for M1 & Tick Charts
Posted: Sun Jul 26, 2026 4:03 pm
by PTScalper
For MT5 (MQL5)
Code: Select all
//+------------------------------------------------------------------+
//| ZeroLagAdaptiveKalman.mqh |
//| High-Performance 2-State Kalman Filter Core |
//+------------------------------------------------------------------+
class CZeroLagAdaptiveKalman
{
private:
double m_p; // Odhad ceny
double m_v; // Odhad rychlosti / momenta
double m_p00, m_p01, m_p10, m_p11; // Kovarianční matice P
double m_q00; // Procesní šum ceny
double m_q11; // Procesní šum momenta
double m_r; // Šum měření
double m_gamma; // Práh adaptace
bool m_init;
public:
CZeroLagAdaptiveKalman(double qPrice=1e-5, double qVel=1e-6, double rNoise=1e-3, double gamma=3.84);
~CZeroLagAdaptiveKalman(void) {};
double Update(const double measurement, double &out_velocity);
void Reset(void) { m_init = false; }
};
//+------------------------------------------------------------------+
//| Konstruktor |
//+------------------------------------------------------------------+
CZeroLagAdaptiveKalman::CZeroLagAdaptiveKalman(double qPrice=1e-5, double qVel=1e-6, double rNoise=1e-3, double gamma=3.84)
: m_q00(qPrice),
m_q11(qVel),
m_r(rNoise),
m_gamma(gamma),
m_init(false)
{
}
//+------------------------------------------------------------------+
//| Hlavní výpočetní cyklus (volat na každém ticku nebo svíčce) |
//+------------------------------------------------------------------+
double CZeroLagAdaptiveKalman::Update(const double measurement, double &out_velocity)
{
if(!m_init)
{
m_p = measurement;
m_v = 0.0;
m_p00 = 1.0; m_p01 = 0.0;
m_p10 = 0.0; m_p11 = 1.0;
m_init = true;
out_velocity = m_v;
return m_p;
}
// 1. Predikce
double p_pred = m_p + m_v;
double v_pred = m_v;
double p00_pred = m_p00 + m_p01 + m_p10 + m_p11 + m_q00;
double p01_pred = m_p01 + m_p11;
double p10_pred = m_p10 + m_p11;
double p11_pred = m_p11 + m_q11;
// 2. Adaptace na průraz (Innovation Gating)
double y = measurement - p_pred;
double s = p00_pred + m_r;
double epsilon = (y * y) / s;
if(epsilon > m_gamma)
{
double inflation = MathSqrt(epsilon);
p00_pred *= inflation;
p01_pred *= inflation;
p10_pred *= inflation;
p11_pred *= inflation;
s = p00_pred + m_r;
}
// 3. Korekce
double k0 = p00_pred / s;
double k1 = p10_pred / s;
m_p = p_pred + (k0 * y);
m_v = v_pred + (k1 * y);
m_p00 = (1.0 - k0) * p00_pred;
m_p01 = (1.0 - k0) * p01_pred;
m_p10 = p10_pred - (k1 * p00_pred);
m_p11 = p11_pred - (k1 * p01_pred);
out_velocity = m_v;
return m_p;
}
Re: Why Your Scalping MAs Lag: Introducing the Zero-Lag Adaptive Kalman Filter for M1 & Tick Charts
Posted: Sun Jul 26, 2026 4:03 pm
by PTScalper
For MT4 (MQL4):
Code: Select all
//+------------------------------------------------------------------+
//| ZeroLagKalman_Scalper.mq4 |
//| Zero-Lag Adaptive Kalman Filter for MT4 |
//+------------------------------------------------------------------+
#property copyright "Free Open Source"
#property link ""
#property version "1.00"
#property strict
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_color1 clrLime
#property indicator_color2 clrRed
#property indicator_width1 2
#property indicator_width2 2
//--- Vstupní parametry filtru
input double InpQPrice = 0.00001; // Procesní šum ceny (Q Price)
input double InpQVel = 0.000001;// Procesní šum rychlosti (Q Velocity)
input double InpRNoise = 0.001; // Šum měření trhu (R Noise)
input double InpGamma = 3.84; // Práh adaptace pro průrazy (Gamma Threshold)
//--- Vykreslovací buffery (Trik pro barevnou čáru v MT4)
double KalmanBullBuffer[]; // Zelená čára (v > 0)
double KalmanBearBuffer[]; // Červená čára (v < 0)
//+------------------------------------------------------------------+
//| Matematické jádro: 2-State Constant Velocity Kalman Filter |
//+------------------------------------------------------------------+
class CZeroLagAdaptiveKalman
{
private:
double m_p; // Odhad ceny
double m_v; // Odhad rychlosti / momenta
double m_p00, m_p01, m_p10, m_p11; // Kovarianční matice P
double m_q00, m_q11, m_r, m_gamma;
bool m_init;
public:
CZeroLagAdaptiveKalman(double qPrice=1e-5, double qVel=1e-6, double rNoise=1e-3, double gamma=3.84);
~CZeroLagAdaptiveKalman(void) {};
double Update(const double measurement, double &out_velocity);
void Reset(void) { m_init = false; }
};
CZeroLagAdaptiveKalman::CZeroLagAdaptiveKalman(double qPrice=1e-5, double qVel=1e-6, double rNoise=1e-3, double gamma=3.84)
: m_q00(qPrice), m_q11(qVel), m_r(rNoise), m_gamma(gamma), m_init(false) {}
double CZeroLagAdaptiveKalman::Update(const double measurement, double &out_velocity)
{
if(!m_init)
{
m_p = measurement;
m_v = 0.0;
m_p00 = 1.0; m_p01 = 0.0;
m_p10 = 0.0; m_p11 = 1.0;
m_init = true;
out_velocity = m_v;
return m_p;
}
// 1. Predikce
double p_pred = m_p + m_v;
double v_pred = m_v;
double p00_pred = m_p00 + m_p01 + m_p10 + m_p11 + m_q00;
double p01_pred = m_p01 + m_p11;
double p10_pred = m_p10 + m_p11;
double p11_pred = m_p11 + m_q11;
// 2. Adaptace na průraz (Innovation Gating)
double y = measurement - p_pred;
double s = p00_pred + m_r;
double epsilon = (y * y) / s;
if(epsilon > m_gamma)
{
double inflation = MathSqrt(epsilon);
p00_pred *= inflation;
p01_pred *= inflation;
p10_pred *= inflation;
p11_pred *= inflation;
s = p00_pred + m_r;
}
// 3. Korekce
double k0 = p00_pred / s;
double k1 = p10_pred / s;
m_p = p_pred + (k0 * y);
m_v = v_pred + (k1 * y);
m_p00 = (1.0 - k0) * p00_pred;
m_p01 = (1.0 - k0) * p01_pred;
m_p10 = p10_pred - (k1 * p00_pred);
m_p11 = p11_pred - (k1 * p01_pred);
out_velocity = m_v;
return m_p;
}
//--- Globální instance filtru pro indikátor
CZeroLagAdaptiveKalman *g_kalman = NULL;
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
SetIndexBuffer(0, KalmanBullBuffer);
SetIndexStyle(0, DRAW_LINE);
SetIndexLabel(0, "Kalman Bullish (v > 0)");
SetIndexEmptyValue(0, EMPTY_VALUE);
SetIndexBuffer(1, KalmanBearBuffer);
SetIndexStyle(1, DRAW_LINE);
SetIndexLabel(1, "Kalman Bearish (v < 0)");
SetIndexEmptyValue(1, EMPTY_VALUE);
// Alokace nového objektu s uživatelskými parametry
if(g_kalman != NULL) delete g_kalman;
g_kalman = new CZeroLagAdaptiveKalman(InpQPrice, InpQVel, InpRNoise, InpGamma);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
if(g_kalman != NULL)
{
delete g_kalman;
g_kalman = NULL;
}
}
//+------------------------------------------------------------------+
//| 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 || g_kalman == NULL) return(0);
int limit = rates_total - prev_calculated;
// Pokud počítáme od začátku (nový graf nebo reset), resetujeme stav filtru
if(prev_calculated == 0)
{
limit = rates_total - 1;
g_kalman.Reset();
}
else if(limit > 0)
{
limit++; // Přepočítat i poslední známý bar pro kontinuitu
}
// V MT4 jsou pole standardně indexována od nejnovějšího [0] po nejstarší [rates_total-1].
// Pro rekurzivní Kalmanův filtr musíme postupovat chronologicky od nejstaršího (limit) k nejnovějšímu (0).
for(int i = limit; i >= 0; i--)
{
double velocity = 0.0;
// Krmíme filtr Typickou cenou (High + Low + Close) / 3 pro vyhlazení mikroskopického šumu
double typicalPrice = (high[i] + low[i] + close[i]) / 3.0;
double kalmanPrice = g_kalman.Update(typicalPrice, velocity);
// Reset obou bufferů na prázdnou hodnotu
KalmanBullBuffer[i] = EMPTY_VALUE;
KalmanBearBuffer[i] = EMPTY_VALUE;
// Přepínání barev podle trajektorie momenta (Velocity)
if(velocity >= 0.0)
{
KalmanBullBuffer[i] = kalmanPrice;
// Propojení čar: zajistí, že čára nebude vizuálně přerušená při změně barvy
if(i < rates_total - 1 && KalmanBearBuffer[i+1] != EMPTY_VALUE)
KalmanBullBuffer[i+1] = KalmanBearBuffer[i+1];
}
else
{
KalmanBearBuffer[i] = kalmanPrice;
if(i < rates_total - 1 && KalmanBullBuffer[i+1] != EMPTY_VALUE)
KalmanBearBuffer[i+1] = KalmanBullBuffer[i+1];
}
}
return(rates_total);
}
Re: Why Your Scalping MAs Lag: Introducing the Zero-Lag Adaptive Kalman Filter for M1 & Tick Charts
Posted: Fri Sep 04, 2026 8:46 pm
by FTtrader
Here is the direct translation of the MQL4 indicator into
Pine Script (Version 5).
In TradingView, we don't need to use the MT4 "two-buffer trick" to create a multi-colored line. We can simply calculate a single price estimate (p) and dynamically change its plot color based on the momentum (v).
Code: Select all
//@version=5
indicator("Zero-Lag Adaptive Kalman Filter", shorttitle="ZLAKF", overlay=true)
// --- Input Parameters ---
qPrice = input.float(0.00001, title="Q Price (Process Noise)", step=0.00001)
qVel = input.float(0.000001, title="Q Velocity (Process Noise)", step=0.000001)
rNoise = input.float(0.001, title="R Noise (Measurement Noise)", step=0.001)
gamma = input.float(3.84, title="Gamma (Adaptation Threshold)", step=0.1)
src = input.source(hlc3, title="Source (Typical Price)")
// --- State Variables (persisted across bars using 'var') ---
var float p = na
var float v = 0.0
var float p00 = 1.0
var float p01 = 0.0
var float p10 = 0.0
var float p11 = 1.0
// --- Kalman Filter Math Engine ---
if not na(src)
if na(p)
// Initialization (runs only on the first valid bar)
p := src
v := 0.0
p00 := 1.0
p01 := 0.0
p10 := 0.0
p11 := 1.0
else
// 1. Prediction
p_pred = p + v
v_pred = v
p00_pred = p00 + p01 + p10 + p11 + qPrice
p01_pred = p01 + p11
p10_pred = p10 + p11
p11_pred = p11 + qVel
// 2. Adaptation (Innovation Gating)
y = src - p_pred
s = p00_pred + rNoise
epsilon = (y * y) / s
if epsilon > gamma
inflation = math.sqrt(epsilon)
p00_pred *= inflation
p01_pred *= inflation
p10_pred *= inflation
p11_pred *= inflation
s := p00_pred + rNoise
// 3. Correction
k0 = p00_pred / s
k1 = p10_pred / s
p := p_pred + (k0 * y)
v := v_pred + (k1 * y)
p00 := (1.0 - k0) * p00_pred
p01 := (1.0 - k0) * p01_pred
p10 := p10_pred - (k1 * p00_pred)
p11 := p11_pred - (k1 * p01_pred)
// --- Plotting ---
// Green if velocity (momentum) is positive, Red if negative
lineColor = v >= 0 ? color.lime : color.red
plot(p, title="Adaptive Kalman Filter", color=lineColor, linewidth=2)
Re: Why Your Scalping MAs Lag: Introducing the Zero-Lag Adaptive Kalman Filter for M1 & Tick Charts
Posted: Fri Sep 04, 2026 8:46 pm
by FTtrader
Key differences handled in the translation:
Looping: MQL4 loops through every bar in its OnCalculate function. Pine Script inherently evaluates code on every bar consecutively, removing the need for a for loop.
Persistence: To retain the state of the matrix variables (like $p_{00}$, $p_{11}$, etc.) between historical bars, Pine Script's var` keyword is used.
Pointers/Classes: Pine Script does not use OOP classes or memory references, so the core logic has been streamlined directly into the runtime evaluation.
Typical Price: MQL4 explicitly calculated (high + low + close) / 3.0. In Pine Script, I mapped this default straight into the input.source(hlc3) dropdown, meaning you can also easily change it to close or hl2 right from the indicator settings menu without editing the code.
Re: Why Your Scalping MAs Lag: Introducing the Zero-Lag Adaptive Kalman Filter for M1 & Tick Charts
Posted: Fri Sep 04, 2026 8:48 pm
by FTtrader
To make this script truly professional, we can utilize
Pine Script v5's User-Defined Types (UDTs) and Methods. This allows us to directly replicate the Object-Oriented structure of your original MQL4 class (CZeroLagAdaptiveKalman), keeping the global scope clean and modular.
I have also added professional UI elements, including grouped inputs, tooltips for the user, customizable colors, visual trend change markers, and alerts.
Professional Pine Script v5 Implementation
Code: Select all
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Free Open Source
//@version=5
indicator("Zero-Lag Adaptive Kalman Filter [Pro]", shorttitle="ZLAKF Pro", overlay=true, timeframe="", timeframe_gaps=true)
// ============================================================================
// 1. INPUTS & CONFIGURATION
// ============================================================================
string GRP_CALC = "Filter Calculation"
string GRP_STYLE = "Style & Visuals"
// Source Data
float src = input.source(hlc3, title="Source Data", group=GRP_CALC)
// Kalman Parameters
float qPrice = input.float(0.00001, title="Q Price (Process Noise)", step=0.00001, group=GRP_CALC, tooltip="Variance of the price process. Lower values make the filter smoother but lag more.")
float qVel = input.float(0.000001, title="Q Velocity (Momentum Noise)", step=0.000001, group=GRP_CALC, tooltip="Variance of the velocity/momentum process.")
float rNoise = input.float(0.001, title="R Noise (Measurement Noise)", step=0.001, group=GRP_CALC, tooltip="Market noise expectation. Higher values trust the model more than the raw data.")
float gamma = input.float(3.84, title="Gamma (Adaptation Threshold)", step=0.1, group=GRP_CALC, tooltip="Innovation gating threshold. When price breaks out beyond this standard deviation, the filter rapidly adapts.")
// Style Parameters
color colBull = input.color(color.new(#00E676, 0), title="Bullish Color", group=GRP_STYLE)
color colBear = input.color(color.new(#FF5252, 0), title="Bearish Color", group=GRP_STYLE)
bool showSigns = input.bool(true, title="Show Trend Change Signals", group=GRP_STYLE)
// ============================================================================
// 2. USER-DEFINED TYPES & METHODS (Object-Oriented Core)
// ============================================================================
// @type Encapsulates the Kalman Filter state matrix and variables
type KalmanFilter
float p = na
float v = 0.0
float p00 = 1.0
float p01 = 0.0
float p10 = 0.0
float p11 = 1.0
// @function Updates the Kalman Filter state and returns the current estimated price
// @param kf The KalmanFilter instance
// @param measurement The current price source (e.g., hlc3)
method update(KalmanFilter kf, float measurement, float qP, float qV, float rN, float g) =>
if na(measurement)
// Skip calculation if data is missing
kf.p
else if na(kf.p)
// Initialization on the first valid bar
kf.p := measurement
kf.v := 0.0
kf.p00 := 1.0
kf.p01 := 0.0
kf.p10 := 0.0
kf.p11 := 1.0
kf.p
else
// 1. Prediction Step
float p_pred = kf.p + kf.v
float v_pred = kf.v
float p00_pred = kf.p00 + kf.p01 + kf.p10 + kf.p11 + qP
float p01_pred = kf.p01 + kf.p11
float p10_pred = kf.p10 + kf.p11
float p11_pred = kf.p11 + qV
// 2. Adaptation (Innovation Gating for Breakouts)
float y = measurement - p_pred
float s = p00_pred + rN
float epsilon = (y * y) / s
if epsilon > g
float inflation = math.sqrt(epsilon)
p00_pred *= inflation
p01_pred *= inflation
p10_pred *= inflation
p11_pred *= inflation
s := p00_pred + rN
// 3. Correction Step
float k0 = p00_pred / s
float k1 = p10_pred / s
kf.p := p_pred + (k0 * y)
kf.v := v_pred + (k1 * y)
kf.p00 := (1.0 - k0) * p00_pred
kf.p01 := (1.0 - k0) * p01_pred
kf.p10 := p10_pred - (k1 * p00_pred)
kf.p11 := p11_pred - (k1 * p01_pred)
kf.p // Return the estimated price
// ============================================================================
// 3. EXECUTION & LOGIC
// ============================================================================
// Instantiate the Kalman Filter object (persists across bars via 'var')
var KalmanFilter kf = KalmanFilter.new()
// Run the update method on the object
float kalmanPrice = kf.update(src, qPrice, qVel, rNoise, gamma)
// Determine momentum state
bool isBullish = kf.v >= 0
bool isBearish = kf.v < 0
// Detect momentum crossovers (Trend Changes)
bool trendUp = ta.crossover(kf.v, 0)
bool trendDn = ta.crossunder(kf.v, 0)
// ============================================================================
// 4. PLOTTING & ALERTS
// ============================================================================
// Plot the main line
color lineColor = isBullish ? colBull : colBear
plot(kalmanPrice, title="Kalman Filter", color=lineColor, linewidth=2)
// Plot Signals
plotshape(showSigns and trendUp ? kalmanPrice : na, title="Bull Signal", location=location.absolute, style=shape.triangleup, size=size.tiny, color=colBull)
plotshape(showSigns and trendDn ? kalmanPrice : na, title="Bear Signal", location=location.absolute, style=shape.triangledown, size=size.tiny, color=colBear)
// Alerts
alertcondition(trendUp, title="Kalman Bullish Reversal", message="Kalman Filter velocity crossed above 0. Bullish momentum.")
alertcondition(trendDn, title="Kalman Bearish Reversal", message="Kalman Filter velocity crossed below 0. Bearish momentum.")
Re: Why Your Scalping MAs Lag: Introducing the Zero-Lag Adaptive Kalman Filter for M1 & Tick Charts
Posted: Fri Sep 04, 2026 8:48 pm
by FTtrader
What Makes This "Professional":
Object-Oriented Architecture: By defining type KalmanFilter and linking it to a method update(), the mathematical engine is perfectly encapsulated. If you ever wanted to apply the filter to two different data sources (e.g., RSI and Price) simultaneously, you would simply create a second instance (var kf2 = KalmanFilter.new()) without copying any math.
Settings UI: The script settings menu is now organized into group tabs (Filter Calculation vs. Style) with detailed tooltip explanations for what the complex math parameters actually do.
Signal Markers: Added visual triangles (plotshape) directly on the chart right where the momentum changes (velocity crosses zero).
Alerts System: Integrated standard alertcondition triggers, allowing users to hook this indicator up to trading bots (like 3Commas or PineConnector) when the trend changes.
Hex Colors: Swapped basic MT4 colors for modern, easily visible Hex codes (#00E676 and #FF5252), with customizable inputs in the settings.
Re: Why Your Scalping MAs Lag: Introducing the Zero-Lag Adaptive Kalman Filter for M1 & Tick Charts
Posted: Wed Sep 23, 2026 9:52 pm
by LondonScalper
FTtrader wrote:What Makes This "Professional": Object-Oriented Architecture: By defining type KalmanFilter and linking it to a method update(), the mathematical engine is perfectly encapsulated. If you ever wanted to apply the filter to two different data sources (e.g.
Zero-lag ideas sell themselves; live they still need a session and spread gate. Object-oriented filters are clean engineering — I like encapsulation when I may reuse the same engine on price and on an oscillator.
For discretionary London work I treat any MA family as context, not as a trigger on its own. Lag is not always the enemy; over-fitting “zero lag” until it fits yesterday often is.
Do you run the Kalman layer as a bias filter only, or as a direct entry signal?