JMA_v1
Download scriptThis script is designed to create a specialized moving average indicator for financial charts. Unlike standard moving averages that simply calculate the mean price over a set period, this logic utilizes a sophisticated "Jurik Moving Average" (JMA) approach. The primary goal of this methodology is to provide a smoothed trend line that significantly reduces market noise and "lag"—the delay between a price movement and the indicator's reaction to it.
Core Logic Breakdown
1. Dynamic Data Processing The script processes historical price data starting from a specific look-back point. It uses a rolling buffer to keep track of recent closing prices. By analyzing this sequence, the script builds a foundation for identifying both immediate price changes and broader trends.
2. Adaptive Smoothing and Phase Control A key feature of this logic is its ability to adjust based on user inputs like "Length" and "Phase."
- Length determines how much historical data influences the current calculation.
- Phase acts as a sensitivity regulator, allowing the indicator to be "faster" or "slower" depending on the market environment. The script performs complex mathematical transformations (including logarithmic and square root calculations) to normalize these inputs into a smooth flow that mimics human observation of a trend rather than raw mathematical averages.
3. Noise Reduction and Volatility Filtering To prevent the indicator from reacting to "jitter" (minor, insignificant price fluctuations), the logic employs a multi-layered filtering system:
- It monitors the difference between current prices and previous data points.
- It calculates the magnitude of these differences to determine if a move is significant enough to warrant a change in the trend line.
- If a movement is deemed insignificant noise, the script effectively ignores it, keeping the line stable.
4. Trend Acceleration and Velocity The script doesn't just look at where the price is; it estimates where it is going by calculating "velocity." It evaluates the distance between current prices and historical benchmarks to project the momentum of the trend. This allows the indicator to curve more naturally during market shifts, staying closer to the price action during high volatility while remaining smooth during periods of consolidation.
5. Recursive Calculation The final value is generated through a recursive process. This means that each new data point is influenced by the previous calculated result, creating a continuous, flowing line. This feedback loop ensures that the transition from one trend state to another happens organically, providing traders with a visual representation of market "momentum" rather than just a historical average.
Summary for the User
In simple terms, this script acts as an intelligent filter. It takes messy, erratic price movements and distills them into a clean, smooth line. Because it uses advanced calculations to balance speed against smoothness, it aims to give you a clearer view of the market's direction while filtering out the "false signals" that often plague simpler moving averages.
//+------------------------------------------------------------------+
//| JMA.mq4 |
//| Spiggy |
//| |
//+------------------------------------------------------------------+
#property copyright "Spiggy"
#property link ""
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_color1 White
//---- input parameters
extern int Len=14;
extern int phase=0;
extern int BarCount=300;
//---- buffers
double ExtMapBuffer1[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int init()
{
//---- indicators
SetIndexStyle(0,DRAW_LINE);
SetIndexBuffer(0,ExtMapBuffer1);
//----
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 prevtime=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;
}
if ((CurTime()-prevtime)<30)
return(-1);
prevtime=CurTime();
//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=Close[shift];
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;
}
}
//----
return(0);
}
//+------------------------------------------------------------------+
Comments