JMASlope
Download scriptThe logic behind this script is designed to track and visualize the momentum of a price trend by calculating a specialized type of moving average, specifically focusing on its "slope" or rate of change.
Instead of simply showing where the average price sits, this tool measures how fast that average is moving up or down. Here is a breakdown of the logic:
Core Processing Logic
The script employs a sophisticated mathematical approach to smooth out market noise while remaining responsive to new price movements. It processes data through several layers:
- Dynamic Weighting: The logic uses an advanced smoothing algorithm (based on Jurik Moving Average principles) that adjusts how much importance it gives to past prices versus current prices. This helps prevent the "lag" typically found in standard moving averages.
- Adaptive Sensitivity: Through the use of specific variables like
LengthandPhase, the script calculates a unique curve. It determines whether the market is experiencing a steady trend or a sharp, volatile move and adjusts its internal calculations to keep the resulting line as smooth as possible without losing its accuracy. - Volatility Handling: The script incorporates a "logarithmic" logic that helps it recognize periods of high volatility. By analyzing the distance between the current price and previous extremes, it can better distinguish between a true trend change and a temporary market spike.
Visual Output Logic
The final step of the script converts the calculated average into two distinct visual signals:
- Upward Momentum: If the current value of the smoothed moving average is higher than the previous value, the script identifies this as "UpSlope." This is represented visually in green.
- Downward Momentum: If the current value of the smoothed moving average is lower than the previous value, the script identifies this as "DownSlope," represented visually in red.
Summary for the User
Essentially, the script acts as a momentum filter. It ignores minor price fluctuations to find the underlying "flow" of the market. By calculating the derivative (the change) of this smoothed flow, it provides a clear visual histogram showing whether the current trend strength is pushing upward or downward at any given moment.
//+------------------------------------------------------------------+
//| JMASlope.mq4 |
//| Copyright © 2005, TrendLaboratory Ltd. |
//| http://finance.groups.yahoo.com/group/TrendLaboratory |
//| Thanks to Weld, Jurik Research http://weld.torguem.net|
//+------------------------------------------------------------------+
#property copyright "Copyright © 2005, TrendLaboratory Ltd."
#property link "http://finance.groups.yahoo.com/group/TrendLaboratory"
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_color1 Green
#property indicator_color2 Red
//---- input parameters
extern int Length = 14;
extern int Phase = 0;
//---- buffers
double UpBuffer [];
double DnBuffer [];
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(6);
//---- drawing settings
SetIndexStyle (0, DRAW_HISTOGRAM);
SetIndexStyle (1, DRAW_HISTOGRAM);
SetIndexDrawBegin(0, 30);
SetIndexDrawBegin(1, 30);
//---- 4 indicator buffers mapping
SetIndexBuffer (0, UpBuffer);
SetIndexBuffer (1, DnBuffer);
SetIndexBuffer (2, JMAValueBuffer);
SetIndexBuffer (3, fC0Buffer);
SetIndexBuffer (4, fA8Buffer);
SetIndexBuffer (5, fC8Buffer);
//---- initialize one buffer (neccessary)
ArrayInitialize (ring2, 0);
ArrayInitialize (ring1, 0);
ArrayInitialize (buffer, 0);
//---- name for DataWindow and indicator subwindow label
IndicatorShortName ("JMASlope(" + Length + "," + Phase + ")");
SetIndexLabel (0, "UpSlope");
SetIndexLabel (1, "DownSlope");
//---- 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;
double rel=JMAValueBuffer [shift]-JMAValueBuffer [shift+1];
if(rel>=0)
{
UpBuffer[shift]=rel;
DnBuffer[shift]=0;
}
else
{
DnBuffer[shift]=rel;
UpBuffer[shift]=0;
}
//---- 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