The following description outlines the operational logic of the "Laguerre RSI & Filter" script, designed to provide traders with a refined perspective on market momentum and trend direction.
Core Analytical Logic
The primary function of this script is to calculate a specialized version of the Relative Strength Index (RSI) known as the Laguerre RSI. Unlike standard moving averages or basic oscillators that can sometimes be "noisy" or lag significantly behind price action, the Laguerre logic utilizes a multi-stage mathematical approach to smooth out fluctuations while remaining responsive to current market changes.
Key Components of the System
1. Dynamic Price Selection The script is highly versatile in how it perceives "price." It allows users to choose from various data points—such as standard High, Low, Open, and Close prices, or more complex variations like Weighted averages and Heiken Ashi calculations. By selecting different inputs, the user can customize how sensitive the indicator is to specific types of price movement.
2. The Laguerre RSI Calculation The script processes the chosen price through a series of four internal memory states. This creates a "flowing" calculation that tracks the rate of change. It calculates the difference between these states to determine whether the momentum is moving up or down, ultimately producing a smoothed oscillator value.
3. The Laguerre Filter To further refine the data, the script applies a second layer of processing called the Laguerre Filter. This acts as a sophisticated smoothing mechanism. It uses adjustable "speed" settings (ranging from 0 to 6) to weight different historical values. This ensures that the final line shown on your chart isn't jumping erratically but instead follows a fluid, coherent path that highlights the prevailing trend.
4. Visual Boundaries and No-Trade Zones The script includes built-in visual aids to help traders identify high-probability areas:
- Overbought/Oversold Levels: It establishes specific thresholds (Level Up and Level Down) to indicate where price may be overextended.
- No-Trade Zone: A unique feature of this script is the "No-Trade Zone." This creates a shaded background area in the middle of the indicator window. The logic assumes that when the indicator is moving within this central band, the market is in a state of equilibrium or consolidation, suggesting that it may be safer to avoid entering new trades until a clear breakout occurs.
Summary for the User
In essence, this tool takes raw market price data, cleans it through two layers of sophisticated mathematical smoothing (Laguerre RSI and Laguerre Filter), and projects it into a visual oscillator. It is designed to help you distinguish between "market noise" and actual momentum, while providing a clear visual "neutral zone" to help manage trade entries and exits.
//------------------------------------------------------------------
#property copyright "mladen"
#property link "mladenfx@gmail.com"
#property link "www.forex-station.com"
//------------------------------------------------------------------
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_color1 PaleVioletRed
#property indicator_color2 DimGray
#property indicator_width1 2
#property indicator_style2 STYLE_DASHDOTDOT
#property indicator_levelcolor DimGray
#property strict
enum enPrices
{
pr_close, // Close
pr_open, // Open
pr_high, // High
pr_low, // Low
pr_median, // Median
pr_typical, // Typical
pr_weighted, // Weighted
pr_average, // Average (high+low+open+close)/4
pr_medianb, // Average median body (open+close)/2
pr_tbiased, // Trend biased price
pr_haclose, // Heiken ashi close
pr_haopen , // Heiken ashi open
pr_hahigh, // Heiken ashi high
pr_halow, // Heiken ashi low
pr_hamedian, // Heiken ashi median
pr_hatypical, // Heiken ashi typical
pr_haweighted, // Heiken ashi weighted
pr_haaverage, // Heiken ashi average
pr_hamedianb, // Heiken ashi median body
pr_hatbiased // Heiken ashi trend biased price
};
extern string UniqueID = "Laguerre rsi & filter 1"; // Indicator unique ID
extern double RsiGamma = 0.80; // Laguerre RSI gamma
extern enPrices RsiPrice = 0; // Price
extern double RsiSmoothGamma = 0.001; // Laguerre RSI smooth gamma
extern int RsiSmoothSpeed = 2; // Laguerre RSI smooth speed (min 0, max 6)
extern double FilterGamma = 0.60; // Laguerre filter gamma
extern int FilterSpeed = 2; // Laguerre filter speed (min 0, max 6)
extern double LevelUp = 0.85; // Level up
extern double LevelDown = 0.15; // Level down
extern bool NoTradeZoneVisible = true; // Display no trade zone?
extern double NoTradeZoneUp = 0.65; // No trade zone up
extern double NoTradeZoneDown = 0.35; // No trade zone down
extern color NoTradeZoneColor = C'255,238,210'; // No trade zone color
extern color NoTradeZoneTextColor = Black; // No trade zone text color
//
//
//
//
//
double lag[],fil[]; string shortName;
//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//
int init()
{
SetIndexBuffer(0,lag);
SetIndexBuffer(1,fil);
SetLevelValue(0,LevelUp);
SetLevelValue(1,LevelDown);
shortName = UniqueID+": ("+DoubleToStr(RsiGamma,2)+","+DoubleToStr(RsiSmoothGamma,2)+") filter ("+DoubleToStr(FilterGamma,2)+")";
IndicatorShortName(shortName);
return(0);
}
int deinit() { ObjectsDeleteAll(0,UniqueID+":"); return(0); }
//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//
int start()
{
int counted_bars=IndicatorCounted();
if(counted_bars<0) return(-1);
if(counted_bars>0) counted_bars--;
int limit = MathMin(Bars - counted_bars,Bars-1);
//
//
//
//
//
for(int i = limit; i >= 0 ; i--)
{
lag[i] = LaGuerreRsi(getPrice(RsiPrice,Open,Close,High,Low,i),RsiGamma,RsiSmoothGamma,RsiSmoothSpeed,i);
fil[i] = LaGuerreFil(lag[i],FilterGamma,FilterSpeed,i);
}
//
//
//
//
//
if (NoTradeZoneVisible)
{
string name = UniqueID+":zone";
int window = WindowFind(shortName);
if (ObjectFind(name) == -1)
ObjectCreate(name,OBJ_RECTANGLE,window,0,0,0,0);
ObjectSet(name,OBJPROP_TIME1,Time[Bars-1]);
ObjectSet(name,OBJPROP_TIME2,Time[0]);
ObjectSet(name,OBJPROP_PRICE1,NoTradeZoneUp);
ObjectSet(name,OBJPROP_PRICE2,NoTradeZoneDown);
ObjectSet(name,OBJPROP_COLOR,NoTradeZoneColor);
ObjectSet(name,OBJPROP_BACK,true);
name = UniqueID+":text";
if (ObjectFind(name) == -1)
ObjectCreate(name,OBJ_TEXT,window,0,0);
ObjectSet(name,OBJPROP_TIME1,Time[0]+30*Period()*60);
ObjectSet(name,OBJPROP_PRICE1,(NoTradeZoneUp+NoTradeZoneDown)/2.0);
ObjectSet(name,OBJPROP_COLOR,NoTradeZoneTextColor);
ObjectSetText(name,"no-trade zone "+DoubleToStr(NoTradeZoneDown,2)+":"+DoubleToStr(NoTradeZoneUp,2),10,"Courier new");
}
return(0);
}
//+------------------------------------------------------------------
//|
//+------------------------------------------------------------------
//
//
//
//
//
//
double workHa[][4];
double getPrice(int price, const double& open[], const double& close[], const double& high[], const double& low[], int i, int instanceNo=0)
{
if (price>=pr_haclose && price<=pr_hatbiased)
{
if (ArrayRange(workHa,0)!= Bars) ArrayResize(workHa,Bars);
int r = Bars-i-1;
//
//
//
//
//
double haOpen;
if (r>0)
haOpen = (workHa[r-1][instanceNo+2] + workHa[r-1][instanceNo+3])/2.0;
else haOpen = (open[i]+close[i])/2;
double haClose = (open[i] + high[i] + low[i] + close[i]) / 4.0;
double haHigh = MathMax(high[i], MathMax(haOpen,haClose));
double haLow = MathMin(low[i] , MathMin(haOpen,haClose));
if(haOpen <haClose) { workHa[r][instanceNo+0] = haLow; workHa[r][instanceNo+1] = haHigh; }
else { workHa[r][instanceNo+0] = haHigh; workHa[r][instanceNo+1] = haLow; }
workHa[r][instanceNo+2] = haOpen;
workHa[r][instanceNo+3] = haClose;
//
//
//
//
//
switch (price)
{
case pr_haclose: return(haClose);
case pr_haopen: return(haOpen);
case pr_hahigh: return(haHigh);
case pr_halow: return(haLow);
case pr_hamedian: return((haHigh+haLow)/2.0);
case pr_hamedianb: return((haOpen+haClose)/2.0);
case pr_hatypical: return((haHigh+haLow+haClose)/3.0);
case pr_haweighted: return((haHigh+haLow+haClose+haClose)/4.0);
case pr_haaverage: return((haHigh+haLow+haClose+haOpen)/4.0);
case pr_hatbiased:
if (haClose>haOpen)
return((haHigh+haClose)/2.0);
else return((haLow+haClose)/2.0);
}
}
//
//
//
//
//
switch (price)
{
case pr_close: return(close[i]);
case pr_open: return(open[i]);
case pr_high: return(high[i]);
case pr_low: return(low[i]);
case pr_median: return((high[i]+low[i])/2.0);
case pr_medianb: return((open[i]+close[i])/2.0);
case pr_typical: return((high[i]+low[i]+close[i])/3.0);
case pr_weighted: return((high[i]+low[i]+close[i]+close[i])/4.0);
case pr_average: return((high[i]+low[i]+close[i]+open[i])/4.0);
case pr_tbiased:
if (close[i]>open[i])
return((high[i]+close[i])/2.0);
else return((low[i]+close[i])/2.0);
}
return(0);
}
//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//
double workLagRsi[][15];
double LaGuerreRsi(double price, double gamma, double smooth, double smoothSpeed, int i, int instanceNo=0)
{
if (ArrayRange(workLagRsi,0)!=Bars) ArrayResize(workLagRsi,Bars); int r = i; i=Bars-i-1; instanceNo*=5;
//
//
//
//
//
workLagRsi[i][instanceNo+0] = (i>0) ? (1.0 - gamma)*price + gamma*workLagRsi[i-1][instanceNo+0] : price;
workLagRsi[i][instanceNo+1] = (i>0) ? -gamma*workLagRsi[i][instanceNo+0] + workLagRsi[i-1][instanceNo+0] + gamma*workLagRsi[i-1][instanceNo+1] : price;
workLagRsi[i][instanceNo+2] = (i>0) ? -gamma*workLagRsi[i][instanceNo+1] + workLagRsi[i-1][instanceNo+1] + gamma*workLagRsi[i-1][instanceNo+2] : price;
workLagRsi[i][instanceNo+3] = (i>0) ? -gamma*workLagRsi[i][instanceNo+2] + workLagRsi[i-1][instanceNo+2] + gamma*workLagRsi[i-1][instanceNo+3] : price;
//
//
//
//
//
double CU = 0.00;
double CD = 0.00;
if (i>0)
{
if (workLagRsi[i][instanceNo+0] >= workLagRsi[i][instanceNo+1])
CU = workLagRsi[i][instanceNo+0] - workLagRsi[i][instanceNo+1];
else CD = workLagRsi[i][instanceNo+1] - workLagRsi[i][instanceNo+0];
if (workLagRsi[i][instanceNo+1] >= workLagRsi[i][instanceNo+2])
CU = CU + workLagRsi[i][instanceNo+1] - workLagRsi[i][instanceNo+2];
else CD = CD + workLagRsi[i][instanceNo+2] - workLagRsi[i][instanceNo+1];
if (workLagRsi[i][instanceNo+2] >= workLagRsi[i][instanceNo+3])
CU = CU + workLagRsi[i][instanceNo+2] - workLagRsi[i][instanceNo+3];
else CD = CD + workLagRsi[i][instanceNo+3] - workLagRsi[i][instanceNo+2];
}
if (CU + CD != 0)
workLagRsi[i][instanceNo+4] = CU / (CU + CD);
else workLagRsi[i][instanceNo+4] = 0;
//
//
//
//
//
return(LaGuerreFil(workLagRsi[i][instanceNo+4],smooth,(int)smoothSpeed,r,1));
}
//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//
double workLagFil[][8];
double LaGuerreFil(double price, double gamma, int smoothSpeed, int i, int instanceNo=0)
{
if (ArrayRange(workLagFil,0)!=Bars) ArrayResize(workLagFil,Bars); i=Bars-i-1; instanceNo*=4;
if (gamma<=0) return(price);
//
//
//
//
//
workLagFil[i][instanceNo+0] = (i>0) ? (1.0 - gamma)*price + gamma*workLagFil[i-1][instanceNo+0] : price;
workLagFil[i][instanceNo+1] = (i>0) ? -gamma*workLagFil[i][instanceNo+0] + workLagFil[i-1][instanceNo+0] + gamma*workLagFil[i-1][instanceNo+1] : price;
workLagFil[i][instanceNo+2] = (i>0) ? -gamma*workLagFil[i][instanceNo+1] + workLagFil[i-1][instanceNo+1] + gamma*workLagFil[i-1][instanceNo+2] : price;
workLagFil[i][instanceNo+3] = (i>0) ? -gamma*workLagFil[i][instanceNo+2] + workLagFil[i-1][instanceNo+2] + gamma*workLagFil[i-1][instanceNo+3] : price;
//
//
//
//
//
double coeffs[]={0,0,0,0};
smoothSpeed = MathMax(MathMin(smoothSpeed,6),0);
switch (smoothSpeed)
{
case 0: coeffs[0] = 1; coeffs[1] = 1; coeffs[2] = 1; coeffs[3] = 1; break;
case 1: coeffs[0] = 1; coeffs[1] = 1; coeffs[2] = 2; coeffs[3] = 1; break;
case 2: coeffs[0] = 1; coeffs[1] = 2; coeffs[2] = 2; coeffs[3] = 1; break;
case 3: coeffs[0] = 2; coeffs[1] = 2; coeffs[2] = 2; coeffs[3] = 1; break;
case 4: coeffs[0] = 2; coeffs[1] = 3; coeffs[2] = 2; coeffs[3] = 1; break;
case 5: coeffs[0] = 3; coeffs[1] = 3; coeffs[2] = 2; coeffs[3] = 1; break;
case 6: coeffs[0] = 4; coeffs[1] = 3; coeffs[2] = 2; coeffs[3] = 1; break;
}
double sumc = 0; for (int k=0; k<4; k++) sumc += coeffs[k];
return((coeffs[0]*workLagFil[i][instanceNo+0]+coeffs[1]*workLagFil[i][instanceNo+1]+coeffs[2]*workLagFil[i][instanceNo+2]+coeffs[3]*workLagFil[i][instanceNo+3])/sumc);
}
Comments