Author: Spiggy
JMA_009

This script implements a sophisticated technical analysis tool known as the Jurik Moving Average (JMA). Its primary purpose is to track price trends on a trading chart while minimizing two of the most common issues in standard moving averages: "lag" (the delay between a price move and the indicator's reaction) and "overshoot" (the erratic spikes or oscillations that occur when the market becomes volatile).

Here is a breakdown of how the logic functions for a non-technical user:

Core Logic and Smoothing

The script processes historical price data to create a smoothed line. Unlike simple moving averages that just take an average of the last few candles, this script uses complex mathematical calculations to determine the "true" direction of the market. It utilizes various coefficients—determined by the Len (Length) and phase inputs—to balance how quickly the indicator reacts to new information versus how much it filters out market noise.

Key Mechanical Features

  • Dynamic Weighting: The logic evaluates current price movements against historical volatility. It essentially "weights" recent data more heavily when a strong trend is detected, but applies extra smoothing during choppy or sideways markets to prevent the indicator from giving false signals.
  • Adaptive Filtering: The script includes an internal mechanism that adjusts its sensitivity based on the rate of change. If the price moves sharply, the indicator attempts to "catch up" without creating a jagged line; if the price stays flat, the indicator remains stable rather than flickering.
  • Advanced Error Correction: One of the unique aspects of this logic is its ability to look back at previous calculations to ensure that the current value remains mathematically consistent with the preceding trend. This helps in maintaining a fluid, organic-looking line on the chart.

User Interaction Parameters

The behavior of the script is primarily governed by three settings:

  1. Len (Length): This defines the primary lookback period. A higher number makes the indicator smoother and slower, while a lower number makes it more responsive to immediate price changes.
  2. Phase: This acts as an offset or "fine-tuning" knob. It allows the user to adjust the acceleration of the average, helping to customize how aggressively the indicator follows the price.
  3. BarCount: This tells the script how much historical data to process at once to ensure accurate calculations from the start of the visible chart.

Summary of Visual Output

The final result is an orange line displayed on your trading window. Because of the underlying logic, this line should appear much "cleaner" than a standard moving average. It aims to provide a clear visual path of price momentum, making it easier for traders to identify when a trend is truly changing versus when the market is simply experiencing temporary noise.

Miscellaneous
Implements a curve of type %1
11 Views
0 Downloads
0 Favorites
JMA_009
//+------------------------------------------------------------------+
//|                                                          JMA.mq4 |
//|                                                           Spiggy |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "Spiggy"
#property link      ""

#property indicator_chart_window
#property indicator_buffers 1
#property indicator_color1 Orange

//---- 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