JMA_RSI_IFT
Download scriptThis technical script is designed to generate a specialized visual indicator for trading charts. It combines three distinct types of mathematical analysis—Relative Strength Index (RSI), Zero-Lag Jurik Moving Average (JMA), and a Hyperbolic Tangent transformation—to create a smoothed, responsive signal line.
Here is the step-by-step logic of how the script processes data:
1. Data Foundation (RSI)
The process begins by calculating the Relative Strength Index (RSI). Instead of looking at raw price action alone, the script uses RSI to measure the momentum of the market (the speed and change of price movements). It then normalizes this value into a specific range to prepare it for further filtering.
2. The Primary Filter (JMA Logic)
The core of the script is a sophisticated "Zero-Lag" moving average logic. Unlike standard moving averages, which often suffer from significant delay (lag), this logic uses a complex series of internal calculations to identify price trends while minimizing that delay.
- Cycle Processing: It breaks the data into "cycles" to identify underlying trends.
- Volatility Adjustment: It dynamically calculates weights based on current market volatility, ensuring the indicator stays "tight" to the price during stable periods and remains smooth during erratic ones.
- Error Correction: It utilizes a feedback loop where previous values are compared against current trends to correct for over-shooting or under-shooting the actual price movement.
3. Secondary Smoothing (MA Calculation)
Once the Zero-Lag JMA has processed the RSI data, the script applies an additional layer of smoothing using a Moving Average. This step acts as a "polishing" mechanism, removing minor fluctuations (noise) from the JMA result to ensure that the final line on your chart represents clear, actionable trends rather than tiny market wobbles.
4. Signal Transformation (Hyperbolic Tangent)
The final mathematical operation involves a Hyperbolic Tangent transformation. This is a non-linear calculation used to compress the resulting data into a specific visual scale.
- Why this is done: It converts the smoothed moving average into a wave-like output that stays within a defined boundary (typically between -1 and 1).
- Visual Result: This makes it much easier for a human trader to identify "overbought" or "oversold" conditions, as the indicator will flatten out at the extremes of its range rather than continuing to climb infinitely.
Summary for the User
In plain English: The script takes market momentum (RSI), cleans it of delays using a high-performance "zero-lag" algorithm (JMA), smooths out the remaining noise, and then transforms it into a clean, oscillating wave. This allows you to see the underlying trend of the market's strength with high precision and minimal lag.
//+------------------------------------------------------------------+
//| JMA_RSI.mq4 |
//| Copyright © 2008, MetaQuotes Software Corp. |
//| http://www.metaquotes.net |
//+------------------------------------------------------------------+
//mod2009fxtsd ift (fo)
#property copyright "Spiggy"
#property link ""
//----
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_color1 Green
#property indicator_level1 0.5
#property indicator_level2 -0.5
//#property indicator_level3 50
#property indicator_maximum 1.1
#property indicator_minimum -1.1
//---- input parameters
extern int RSIPeriod = 10;
extern int RSIPrice = PRICE_CLOSE;
extern int MAPeriod = 9;
extern int MAMode = MODE_LWMA;
extern int Len=14;
extern int phase=-5;
extern int BarCount=1000;
//---- buffers
double ExtMapBuffer1[];
double Buffer2[];
double Buffer3[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int init()
{
//---- indicators
IndicatorBuffers(3);
SetIndexStyle(0,DRAW_LINE);
SetIndexBuffer(2,ExtMapBuffer1);
SetIndexBuffer(1,Buffer2);
SetIndexBuffer(0,Buffer3);
//----
return(0);
}
//+------------------------------------------------------------------+
//| Custor indicator deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
//----
//----
return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int start()
{
int counted_bars=IndicatorCounted();
//----
// variable definitions
bool firstTime=True;
int AccountedBars=0;
int jj=0;
int ii=0;
int shift=0;
double series=0;
//----
double vv=0;
double v1=0;
double v2=0;
double v3=0;
double v4=0;
double s8=0;
double s10=0;
double s18=0;
double s20=0;
int v5=0;
int v6=0;
double s28=0;
double s30=0;
int s38=0;
int s40=0;
int s48=0;
int s50=0;
int s58=0;
int s60=0;
double s68=0;
double s70=0;
double f8=0;
double f10=0;
double f18=0;
double f20=0;
double f28=0;
double f30=0;
double f38=0;
double f40=0;
double f48=0;
double f50=0;
double f58=0;
double f60=0;
double f68=0;
double f70=0;
double f78=0;
double f80=0;
double f88=0;
double f90=0;
double f98=0;
double fA0=0;
double fA8=0;
double fB0=0;
double fB8=0;
double fC0=0;
double fC8=0;
double fD0=0;
double f0=0;
double fD8=0;
double fE0=0;
double fE8=0;
int fF0=0;
double fF8=0;
int value2=0;
double JMA=0;
//----
double list[127];
double ring1[127];
double ring2[10];
double buffer[61];
//----
ArrayInitialize(list,0);
ArrayInitialize(ring1,0);
ArrayInitialize(ring2,0);
ArrayInitialize(buffer,0);
//----
if (firstTime)
{
AccountedBars=Bars-BarCount;
firstTime=False;
}
//SetLoopCount(0);
{
s28=63;
s30=64;
for( ii=1;ii<=s28;ii++)
{
list[ii]=-1000000;
}
for( ii=s30;ii<=127 ;ii++ )
{
list[ii]=1000000;
}
f0=1;
}
//----
for( shift=BarCount;shift>=0;shift-- )
{
series=0.1*(iRSI(NULL,0,RSIPeriod,RSIPrice,shift)-50);
if (fF0 < 61)
{
fF0= fF0 + 1;
buffer[fF0]=series;
} //{ main cycle }
if (fF0 > 30)
{
if (Len < 1.0000000002)
{
f80=0.0000000001; //{1.0e-10}
}
else
{
f80=(Len - 1)/2.0;
}
if (phase < -100)
{
f10=0.5;
}
else
{
if (phase > 100)
{
f10=2.5;
}
else
{
f10=phase/100 + 1.5;
}
}
v1=MathLog(MathSqrt(f80));
v2=v1;
if (v1/MathLog(2.0) + 2.0 < 0.0)
{
v3=0;
}
else
{
v3=v2/MathLog(2.0) + 2.0;
}
f98=v3;
//----
if (0.5<=f98 - 2.0)
{
f88=f98 - 2.0;
}
else
{
f88=0.5;
}
f78=MathSqrt(f80) * f98;
f90=f78/(f78 + 1.0);
f80=f80 * 0.9;
f50=f80/(f80 + 2.0);
//----
if (f0!=0)
{
f0=0;
v5=0;
for( ii=1;ii <=29;ii++)
{
if (buffer[ii+1]!=buffer[ii])
{
v5=1.0;
}
}
fD8=v5*30.0;
if (fD8==0)
{
f38=series;
}
else
{
f38=buffer[1];
}
f18=f38;
if (fD8 > 29)
fD8=29;
}
else
fD8=0;
//----
for( ii=fD8;ii>=0;ii-- )
{ //{ another bigcycle...}
value2=31-ii;
if (ii==0)
{
f8=series;
}
else
{
f8=buffer[value2];
}
f28=f8 - f18;
f48=f8 - f38;
if (MathAbs(f28) > MathAbs(f48))
{
v2=MathAbs(f28);
}
else
{
v2=MathAbs(f48);
}
fA0=v2;
vv=fA0 + 0.0000000001; //{1.0e-10;}
//----
if (s48<=1)
{
s48=127;
}
else
{
s48=s48 - 1;
}
if (s50<=1)
{
s50=10;
}
else
{
s50=s50 - 1;
}
if (s70 < 128)
s70=s70 + 1;
s8=s8 + vv - ring2[s50];
ring2[s50]=vv;
if (s70 > 10)
{
s20=s8/10;
}
else
s20=s8/s70;
//----
if (s70 > 127)
{
s10=ring1[s48];
ring1[s48]=s20;
s68=64;
s58=s68;
while(s68 > 1)
{
if (list[s58] < s10)
{
s68=s68 *0.5;
s58=s58 + s68;
}
else
if (list[s58]<=s10)
{
s68=1;
}
else
{
s68=s68 *0.5;
s58=s58 - s68;
}
}
}
else
{
ring1[s48]=s20;
if (s28 + s30 > 127)
{
s30=s30 - 1;
s58=s30;
}
else
{
s28=s28 + 1;
s58=s28;
}
if (s28 > 96)
{
s38=96;
}
else
s38=s28;
if (s30 < 32)
{
s40=32;
}
else
s40=s30;
}
//----
s68=64;
s60=s68;
while(s68 > 1)
{
if (list[s60]>=s20)
{
if (list[s60 - 1]<=s20)
{
s68=1;
}
else
{
s68=s68 *0.5;
s60=s60 - s68;
}
}
else
{
s68=s68 *0.5;
s60=s60 + s68;
}
if ((s60==127) && (s20 > list[127]))
s60=128;
}
if (s70 > 127)
{
if (s58>=s60)
{
if ((s38 + 1 > s60) && (s40 - 1 < s60))
{
s18=s18 + s20;
}
else
if ((s40 > s60) && (s40 - 1 < s58))
s18=s18 + list[s40 - 1];
}
else
if (s40>=s60)
{
if ((s38 + 1 < s60) && (s38 + 1 > s58))
s18=s18 + list[s38 + 1];
}
else
if (s38 + 2 > s60)
{
s18=s18 + s20;
}
else
if ((s38 + 1 < s60) && (s38 + 1 > s58))
s18=s18 + list[s38 + 1];
if (s58 > s60)
{
if ((s40 - 1 < s58) && (s38 + 1 > s58))
{
s18=s18 - list[s58];
}
else
if ((s38 < s58) && (s38 + 1 > s60))
s18=s18 - list[s38];
}
else
{
if ((s38 + 1 > s58) && (s40 - 1 < s58))
{
s18=s18 - list[s58];
}
else
if ((s40 > s58) && (s40 < s60))
s18=s18 - list[s40];
}
}
if (s58<=s60)
{
if (s58>=s60)
{
list[s60]=s20;
}
else
{
for( jj=s58 + 1;jj<=s60 - 1;jj++)
{
list[jj - 1]=list[jj];
}
list[s60 - 1]=s20;
}
}
else
{
for( jj=s58 - 1;jj>=s60;jj-- )
{
list[jj + 1]=list[jj];
}
list[s60]=s20;
}
if (s70<=127)
{
s18=0;
for(jj=s40;jj<=s38;jj++)
{
s18=s18 + list[jj];
}
}
f60=s18/(s38 - s40 + 1);
if (fF8 + 1 > 31)
{
fF8=31;
}
else
fF8=fF8 + 1;
//----
if (fF8<=30)
{
if (f28 > 0)
{
f18=f8;
}
else
f18=f8 - f28 * f90;
if (f48 < 0)
{
f38=f8;
}
else
f38=f8 - f48 * f90;
fB8=series;
//{EasyLanguage does not have "continue" statement}
if (fF8!=30)
{
continue;
}
if (fF8==30)
{
fC0=series;
if (MathCeil(f78)>=1)
{
v4=MathCeil(f78);
}
else
v4=1;
fE8=MathCeil(v4);
if (MathFloor(f78)>=1)
{
v2=MathFloor(f78);
}
else
v2=1;
fE0=MathCeil(v2);
if (fE8==fE0)
{
f68=1;
}
else
{
v4=fE8 - fE0;
f68=(f78 - fE0)/v4;
}
if (fE0<=29)
{
v5=fE0;
}
else
v5=29;
if (fE8<=29)
{
v6=fE8;
}
else
v6=29;
fA8=(series - buffer[fF0 - v5]) * (1 - f68)/fE0 + (series - buffer[fF0 - v6]) * f68/fE8;
}
}
else
{
if (f98>=MathPow(fA0/f60, f88))
{
v1=MathPow(fA0/f60, f88);
}
else
v1=f98;
if (v1 < 1)
{
v2=1;
}
else
{
if (f98>=MathPow(fA0/f60, f88))
{
v3=MathPow(fA0/f60, f88);
}
else
v3=f98;
v2=v3;
}
f58=v2;
f70=MathPow(f90, MathSqrt(f58));
if (f28 > 0)
{
f18=f8;
}
else
{
f18=f8 - f28 * f70;
}
if (f48 < 0)
{
f38=f8;
}
else
{
f38=f8 - f48 * f70;
}
}
}
if (fF8 > 30)
{
f30=MathPow(f50, f58);
fC0=(1 - f30) * series + f30 * fC0;
fC8=(series - fC0) * (1 - f50) + f50 * fC8;
fD0=f10 * fC8 + fC0;
f20=-f30 * 2;
f40=f30 * f30;
fB0=f20 + f40 + 1;
fA8=(fD0 - fB8) * fB0 + f40 * fA8;
fB8=fB8 + fA8;
}
JMA= fB8;
}
if (fF0<=30)
{
JMA=0;
}
//Print ("JMA is " + JMA + " shift is " + shift);
ExtMapBuffer1[shift]=JMA;
//----
if (shift>0)
{
AccountedBars=AccountedBars+1;
}
}
for( shift=BarCount;shift>=0;shift-- )
{
Buffer2[shift] = iMAOnArray(ExtMapBuffer1,0,MAPeriod,0,MAMode,shift);
Buffer3[shift] = (MathExp(2*Buffer2[shift])-1)/(MathExp(2*Buffer2[shift])+1);
}
//----
return(0);
}
//+------------------------------------------------------------------+
Comments