Author: Weld
JMA_001

This script implements the Jurik Moving Average (JMA), a sophisticated technical analysis indicator designed to provide a smooth representation of price trends while significantly reducing "lag"—the delay between a market move and the indicator's response.

Core Logic Overview

The primary goal of this logic is to balance two conflicting requirements in trading software: smoothness and responsiveness. Standard moving averages are often either too "choppy" (reacting to every minor noise) or too slow (reacting only after a trend is already established). This script uses a multi-stage mathematical approach to solve this.

Key Components of the Logic

1. Input Customization The script allows users to define two main parameters:

  • Length: Determines the overall timeframe or "window" the indicator looks at.
  • Phase: Adjusts the "speed" or sensitivity of the calculation, allowing the user to fine-tune how aggressively the indicator follows price changes.

2. Noise Reduction and Data Filtering Instead of simply averaging the last few prices, the script performs a "Big Cycle" of calculations. It analyzes the distance between current prices and previous values to determine which movements are significant trends and which are merely market noise.

3. Adaptive Weighting The script utilizes advanced mathematical functions (including square roots and logarithms) to calculate weights dynamically. Rather than giving every past data point equal importance, it assigns higher weight to the most relevant price actions. This allows the line to "stick" to the trend more closely when the market is moving steadily.

4. Multi-Stage Smoothing Process The logic processes data through several internal buffers:

  • Initial Filtering: It captures raw price series into a temporary memory bank to identify directional shifts.
  • Variable Power Calculation: It uses a logarithmic power function to determine how much "weight" to give to new information based on the volatility of the current price.
  • Final Smoothing: The final output is refined through a series of weighted calculations that ensure the resulting line remains fluid and continuous, preventing sharp, jagged jumps even during high-volatility events.

Summary for the User

In practical terms, this script creates a "smart" moving average. It behaves like a filter that ignores minor market "hiccups" but reacts swiftly to genuine changes in price direction. By using complex internal loops and weighted memory buffers, it provides a cleaner visual trend line than standard moving averages, helping traders identify the underlying direction of the market with greater clarity.

14 Views
0 Downloads
0 Favorites
JMA_001
//+------------------------------------------------------------------+
//|                                                          JMA.mq4 |
//|                                             Weld, Jurik Research |
//|                                          http://weld.torguem.net |
//+------------------------------------------------------------------+
#property copyright "Weld"
#property link      "http://weld.torguem.net"

#property indicator_chart_window
#property indicator_buffers 1
#property indicator_color1 Aqua
//---- input parameters
extern int       Length = 14;
extern int       Phase  = 0;
//---- buffers
double JMAValueBuffer [];
double fC0Buffer [];
double fA8Buffer [];
double fC8Buffer [];
//---- temporary buffers
double list[128], ring1[128], ring2[11], buffer[62];
//---- bool flag
bool   initFlag;
//---- integer vars
int    limitValue, startValue, loopParam, loopCriteria;
int    cycleLimit, highLimit, counterA, counterB;
//---- double vars
double cycleDelta, lowDValue, highDValue, absValue, paramA, paramB;
double phaseParam, logParam, JMAValue, series, sValue, sqrtParam, lengthDivider;
//---- temporary int variables
int   s58, s60, s40, s38, s68;
//+------------------------------------------------------------------+
//| JMA initFlagization function                                     |
//+------------------------------------------------------------------+
int init()
  {
   double   lengthParam;
//---- 3 additional buffers are used for counting.
   IndicatorBuffers(4);
//---- drawing settings
   SetIndexStyle  (0, DRAW_LINE);
   SetIndexDrawBegin(0, 30);
//---- 4 indicator buffers mapping
   SetIndexBuffer (0, JMAValueBuffer);
   SetIndexBuffer (1, fC0Buffer);
   SetIndexBuffer (2, fA8Buffer);
   SetIndexBuffer (3, fC8Buffer); 
//---- initialize one buffer (neccessary)   
   ArrayInitialize (ring2, 0);
   ArrayInitialize (ring1, 0); 
   ArrayInitialize (buffer, 0); 
//---- name for DataWindow and indicator subwindow label
   IndicatorShortName ("JMAValue(" + Length + "," + Phase + ")");
   SetIndexLabel (0, "JMAValue");
//---- initial part
   limitValue = 63; 
   startValue = 64;
//----   
   for (int i = 0; i <= limitValue; i++) list [i] = -1000000; 
   for (i = startValue; i <= 127; i++)   list [i] = 1000000; 
//----
   initFlag  = true;
   if (Length < 1.0000000002) lengthParam = 0.0000000001;
   else lengthParam = (Length - 1) / 2.0;
//----   
   if (Phase < -100) phaseParam = 0.5;
   else if (Phase > 100) phaseParam = 2.5;
   else phaseParam = Phase / 100.0 + 1.5;
//----   
   logParam = MathLog (MathSqrt (lengthParam)) / MathLog (2.0);
//----
   if (logParam + 2.0 < 0) logParam = 0;
   else logParam = logParam + 2.0; 
//----
   sqrtParam     = MathSqrt(lengthParam) * logParam; 
   lengthParam   = lengthParam * 0.9; 
   lengthDivider = lengthParam / (lengthParam + 2.0);
//----  
   return;
}
//+------------------------------------------------------------------+
//| JMA iteration function                                           |
//+------------------------------------------------------------------+
int start()
  {

//---- get already counted bars    
   int counted_bars = IndicatorCounted();
//---- check for possible errors
   if (counted_bars < 0) return (-1);
   int limit = Bars - counted_bars - 1;
//---- main cycle
   for (int shift = limit; shift >= 0; shift--) {
      series = Close [shift];
 
      if (loopParam < 61) { 
         loopParam++; 
         buffer [loopParam] = series; 
      } 
      if (loopParam > 30) {
         if (initFlag) { 
            initFlag = false;
             
            int diffFlag = 0; 
            for (int i = 1; i <= 29; i++) { 
               if (buffer [i + 1] != buffer [i]) diffFlag = 1;
            }  
            highLimit = diffFlag * 30;
             
            if (highLimit == 0) paramB = series;
            else paramB = buffer[1];
             
            paramA = paramB; 
            if (highLimit > 29) highLimit = 29; 
         } else 
            highLimit = 0;
//---- big cycle
         for (i = highLimit; i >= 0; i--) { 
			   if (i == 0) sValue = series; else sValue = buffer [31 - i]; 
	    
			   if (MathAbs (sValue - paramA) > MathAbs (sValue - paramB)) absValue = MathAbs(sValue - paramA); else absValue = MathAbs(sValue - paramB); 
			   double dValue = absValue + 0.0000000001; //1.0e-10; 
	
			   if (counterA <= 1) counterA = 127; else counterA--; 
			   if (counterB <= 1) counterB = 10;  else counterB--; 
			   if (cycleLimit < 128) cycleLimit++; 
			   cycleDelta += (dValue - ring2 [counterB]); 
			   ring2 [counterB] = dValue; 
			   if (cycleLimit > 10) highDValue = cycleDelta / 10.0; else highDValue = cycleDelta / cycleLimit; 
			   
			   if (cycleLimit > 127) { 
				   dValue = ring1 [counterA]; 
				   ring1 [counterA] = highDValue; 
				   s68 = 64; s58 = s68; 
				   while (s68 > 1) { 
					   if (list [s58] < dValue) { 
						   s68 = s68 / 2.0; 
						   s58 += s68; 
					   } else 
					   if (list [s58] <= dValue) { 
						   s68 = 1; 
					   } else { 
						   s68 = s68 / 2.0; 
						   s58 -= s68; 
					   }
               } 
            } else {
			      ring1 [counterA] = highDValue; 
			      if ((limitValue + startValue) > 127) {
				      startValue--; 
				      s58 = startValue; 
			      } else {
				      limitValue++; 
				      s58 = limitValue; 
			      }
			      if (limitValue > 96) s38 = 96; else s38 = limitValue; 
			      if (startValue < 32) s40 = 32; else s40 = startValue; 
		      }
//----		      
		      s68 = 64; 
		      s60 = s68; 
		      while (s68 > 1) {
			      if (list [s60] >= highDValue) {
				      if (list [s60 - 1] <= highDValue) {
					      s68 = 1; 
				      }
				      else {
					      s68 = s68 / 2.0; 
					      s60 -= s68; 
				      }
			      }
			      else {
				      s68 = s68 / 2.0; 
				      s60 += s68; 
			      }
			      if ((s60 == 127) && (highDValue > list[127])) s60 = 128; 
		      }
			   if (cycleLimit > 127) {
				   if (s58 >= s60) {
					   if (((s38 + 1) > s60) && ((s40 - 1) < s60)) 
						    lowDValue += highDValue; 
					   else if ((s40 > s60) && ((s40 - 1) < s58)) 
						    lowDValue += list [s40 - 1]; 
				   }
				   else if (s40 >= s60) {
					   if (((s38 + 1) < s60) && ((s38 + 1) > s58)) 
							    lowDValue += list[s38 + 1]; 
					}
				   else if ((s38 + 2) > s60) 
						   lowDValue += highDValue; 
				   else if (((s38 + 1) < s60) && ((s38 + 1) > s58)) 
						   lowDValue += list[s38 + 1]; 
			
				   if (s58 > s60) {
					   if (((s40 - 1) < s58) && ((s38 + 1) > s58)) 
						   lowDValue -= list [s58]; 
					   else if ((s38 < s58) && ((s38 + 1) > s60)) 
						   lowDValue -= list [s38]; 
				   }
				   else {
					   if (((s38 + 1) > s58) && ((s40 - 1) < s58)) 
						   lowDValue -= list [s58]; 
					   else if ((s40 > s58) && (s40 < s60)) 
						   lowDValue -= list [s40]; 
				   }
			   }
			   if (s58 <= s60) {
				   if (s58 >= s60) list[s60] = highDValue; else {
					   for (int j = s58 + 1; j <= (s60 - 1); j++) {
						   list [j - 1] = list[j]; 
					   }
					   list [s60 - 1] = highDValue; 
				   }
			   } else {
				   for (j = s58 - 1; j >= s60; j--) {
					   list [j + 1] = list [j]; 
				   }
				   list [s60] = highDValue; 
			   }
			
			   if (cycleLimit <= 127) {
				   lowDValue = 0; 
				   for (j = s40; j <= s38; j++) {
					   lowDValue += list[j]; 
				   }
			   }
//----			    
			   if ((loopCriteria + 1) > 31) loopCriteria = 31; else loopCriteria++; 
			   double JMATempValue, sqrtDivider = sqrtParam / (sqrtParam + 1.0);
			   
			   if (loopCriteria <= 30) {
				   if (sValue - paramA > 0) paramA = sValue; else paramA = sValue - (sValue - paramA) * sqrtDivider; 
				   if (sValue - paramB < 0) paramB = sValue; else paramB = sValue - (sValue - paramB) * sqrtDivider; 
				   JMATempValue = series;
				 
				   if (loopCriteria == 30) { 
				     fC0Buffer [shift] = series;
				     int intPart;
				      
				     if (MathCeil(sqrtParam) >= 1) intPart = MathCeil(sqrtParam); else intPart = 1; 
				     int leftInt = IntPortion (intPart); 
				     if (MathFloor(sqrtParam) >= 1) intPart = MathFloor(sqrtParam); else intPart = 1; 
				     int rightPart = IntPortion (intPart);
				     
				     if (leftInt == rightPart) dValue = 1.0; 
				     else 
					     dValue = (sqrtParam - rightPart) / (leftInt - rightPart);
			     
				     if (rightPart <= 29) int upShift = rightPart; else upShift = 29; 
				     if (leftInt <= 29) int dnShift = leftInt; else dnShift = 29; 
				     fA8Buffer [shift] = (series - buffer [loopParam - upShift]) * (1 - dValue) / rightPart + (series - buffer[loopParam - dnShift]) * dValue / leftInt;
               }
			   } else {
			      double powerValue, squareValue;
			      
			      dValue = lowDValue / (s38 - s40 + 1);
			      if (0.5 <= logParam - 2.0) powerValue = logParam - 2.0;
               else powerValue = 0.5;
               
				   if (logParam >= MathPow(absValue/dValue, powerValue)) dValue = MathPow (absValue/dValue, powerValue); else dValue = logParam; 
				   if (dValue < 1) dValue = 1;
				    
				   powerValue = MathPow (sqrtDivider, MathSqrt (dValue)); 
				   if (sValue - paramA > 0) paramA = sValue; else paramA = sValue - (sValue - paramA) * powerValue; 
				   if (sValue - paramB < 0) paramB = sValue; else paramB = sValue - (sValue - paramB) * powerValue; 
   		   }
         }
// ---- end of big cycle                  			   
         if (loopCriteria > 30) {
				JMATempValue = JMAValueBuffer [shift + 1];
            powerValue   = MathPow (lengthDivider, dValue);
            squareValue  = MathPow (powerValue, 2);
                         
				fC0Buffer [shift] = (1 - powerValue) * series + powerValue * fC0Buffer [shift + 1];
            fC8Buffer [shift] = (series - fC0Buffer [shift]) * (1 - lengthDivider) + lengthDivider * fC8Buffer [shift + 1];
            
            fA8Buffer [shift] = (phaseParam * fC8Buffer [shift] + fC0Buffer [shift] - JMATempValue) * 
                                 (powerValue * (-2.0) + squareValue + 1) + squareValue * fA8Buffer [shift + 1];  
            JMATempValue += fA8Buffer [shift]; 
         }
         JMAValue = JMATempValue;
      }
      if (loopParam <= 30) JMAValue = 0;
      JMAValueBuffer [shift] = JMAValue;
//---- End of main cycle
   } 
   return;
}

//+------------------------------------------------------------------+
int IntPortion (double param) {
   if (param > 0) return (MathFloor (param));
   if (param < 0) return (MathCeil (param));
   return (0.0);
}
//+------------------------------------------------------------------+

Comments