JMA_StarLight_v1
Download scriptThis script implements a sophisticated technical analysis tool known as the Jurik Moving Average (JMA). Designed for financial charting, its primary goal is to provide a smooth, responsive trend line that minimizes the "lag" typically found in standard moving averages while filtering out market noise.
Core Logic and Functionality
1. Dynamic Smoothing and Responsiveness Unlike basic moving averages that treat all data points equally over a set period, this script uses complex mathematical modeling to balance two competing needs: smoothness and speed. It analyzes the rate of change in price to determine how quickly the indicator should react. If the market is moving steadily, it prioritizes smoothness; if the market makes a sharp turn, the logic adjusts to follow that move more aggressively.
2. Adaptive Signal Processing The script employs several layers of calculation to refine the final output:
- Price Selection: Users can choose which price data point to track (e.g., Close, Open, High, Low, or an average), allowing for customization based on different trading styles.
- Phase and Length Adjustments: The "Length" determines the overall window of data considered, while the "Phase" acts as a quality control parameter. It fine-tunes the transition process to ensure the indicator doesn't overreact to minor price fluctuations (noise) or become too sluggish during significant trends.
3. Memory and History Management To ensure accuracy, the script maintains an internal memory of previous price movements and calculation results. It uses "ring buffers" and various lists to store historical data points. This allows the algorithm to compare current market behavior against recent history to calculate the most accurate "current" value without losing the context of where the price came from.
4. Complex Mathematical Interpolation The script utilizes advanced operations—including square roots, logarithms, and power functions—to calculate weighting. It essentially creates a unique "weighted" average for every single bar on the chart. By calculating these weights dynamically, it attempts to "anticipate" the trend by giving more importance to data points that align with the current momentum of the market.
Summary for the User
In simple terms, this script is an intelligent trend-follower. It looks at the history of price movement and uses a series of complex filters to draw a line on your chart. Its "intelligence" lies in its ability to change its behavior automatically: it stays flat and smooth during sideways markets to avoid "fake" signals, but becomes reactive and sharp when a real trend begins.
/*-----------------------------+
| |
| Shared by www.Aptrafx.com |
| |
+------------------------------*/
//+GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG+
//| JMA_StarLight.mq4 |
//| JMA_Star_Light: Copyright © 2005, Weld, Jurik Research |
//| http://weld.torguem.net |
//| MQL4: Copyright © 2005, Nikolay Kositsin |
//| Khabarovsk, violet@mail.kht.ru |
//+GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG+
#property copyright "Weld"
#property link "http://weld.torguem.net"
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_color1 Red
//---- input parameters
extern int Length = 5; // ãëóáèíà ñãëàæèâàíèÿ
extern int Phase = 5; // ïàðàìåòð, èçìåíÿþùèéñÿ â ïðåäåëàõ -150 ... +150, âëèÿåò íà êà÷åñòâî ïåðåõîäíîãî ïðîöåññà;
extern int Shift = 0; // cäâèã èíäèêàòîðà âäîëü îñè âðåìåíè
extern int Input_Price_Customs = 0;//Âûáîð öåí, ïî êîòîðûì ïðîèçâîäèòñÿ ðàñ÷¸ò èíäèêàòîðà (0-"Close", 1-"Open", 2-"(High+Low)/2", 3-"High", 4-"Low")
//---- indicator buffers
double JMA_Buf[ ];
double MEMORY1[9];
int MEMORY2[12];
double MEMORY3[128];
//---- temporary double buffers
double list[128], ring1[128], ring2[11], buffer[62];
//---- double vars
double f8, f60,f20,f28,f30,f40,f48,f58,f68,f70,f90,f78,f88,f98;
double Kg,Dr,Ds,Dl,Pf,JMA,series,vv,v1,v2,v3,v4,s20,s10,fB0,fD0;
//---- integer vars
int ii,jj,s28,s30,f0,v5,v6,fE0,fD8,fE8,val,s48,s58,s60,s68,T0;
//+GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG+
//| JMA initFlagization function |
//+GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG+
int init()
{
SetIndexStyle(0, DRAW_LINE);
SetIndexShift(0, Shift);
//---- 1 indicator buffers mapping
IndicatorBuffers(1);
SetIndexBuffer (0, JMA_Buf);
SetIndexEmptyValue(0,0.0);
//----
IndicatorShortName ("JMA Star Light( Length="+Length+", Phase="+Phase+", Shift="+Shift+")");
SetIndexLabel (0, "JMA Star Light");
IndicatorDigits(MarketInfo(Symbol(),MODE_DIGITS));
//+==== initial part ==============================================================================================================+
if(Phase<-100){Alert("Ïàðàìåòð Phase äîëæåí áûòü îò -100 äî +100" + " Âû ââåëè íåäîïóñòèìîå " + Phase+ " áóäåò èñïîëüçîâàíî -100");}
if(Phase> 100){Alert("Ïàðàìåòð Phase äîëæåí áûòü îò -100 äî +100" + " Âû ââåëè íåäîïóñòèìîå " + Phase+ " áóäåò èñïîëüçîâàíî 100");}
if(Length< 1){Alert("Ïàðàìåòð Length äîëæåí íå ìåíåå 1" + " Âû ââåëè íåäîïóñòèìîå " + Length+ " áóäåò èñïîëüçîâàíî 1");}
if(Input_Price_Customs<0){Alert("Ïàðàìåòð Input_Price_Customs äîëæåí íå ìåíåå 0" + " Âû ââåëè íåäîïóñòèìîå " + Input_Price_Customs+ " áóäåò èñïîëüçîâàíî 0");}
if(Input_Price_Customs>4){Alert("Ïàðàìåòð Input_Price_Customs äîëæåí íå áîëåå 4" + " Âû ââåëè íåäîïóñòèìîå " + Input_Price_Customs+ " áóäåò èñïîëüçîâàíî 0");}
if (Length < 1.0000000002) Dr = 0.0000000001; //{1.0e-10}
else Dr = (Length - 1.0) / 2.0;
if (Phase > 100) Pf = 2.5;
if (Phase < -100) Pf = 0.5;
if((Phase >= -100)&&(Phase <= 100)) Pf = Phase / 100.0 + 1.5;
Dr = Dr * 0.9; Kg = Dr / (Dr + 2.0);
Ds=MathSqrt(Dr); Dl=MathLog(Ds);
//----==========================+
return(0);
}
//+GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG+
//| JMA iteration function |
//+GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG+
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;
//----
if(limit==Bars-1)
{
//---- Ïîâòîðíîå îáúÿâëåíèå ïåðåìåííûõ è èõ èíèöèàëèçàöèÿ ============+
ArrayInitialize (MEMORY1, 0.0);ArrayInitialize (MEMORY2, 0 );
ArrayInitialize (MEMORY3, 0.0);
ArrayInitialize (buffer, 0.0);ArrayInitialize (ring1, 0.0);
ArrayInitialize (ring2, 0.0);ArrayInitialize (list, 0.0);
//----+===============================================================+
double f18=0.0,f38=0.0,fA0=0.0,fA8=0.0,fC0=0.0,fC8=0.0,s8=0.0,s18=0.0;
int s38=0, s40=0, s50=0, s70=0, LP2=0, LP1=0;
//----+===============================================================+
f0=1; s28=63; s30=64;
for (ii=0; ii<=s28; ii++)list[ii]=-1000000.0;
for (ii=s30; ii<=127; ii++)list[ii]= 1000000.0;
//----+#########################################+
}
if (limit<Bars-1)
{
//---- èíèöèàëèçàöèÿ ïåðåìåííûõ èíèöèàëèçàöèÿ =======================+
ArrayInitialize (buffer, 0.0);ArrayInitialize (ring1, 0.0);
ArrayInitialize (list, 0.0);ArrayInitialize (ring2, 0.0);
//----+===============================================================+
f8 =0.0;f60=0.0;f20=0.0;f28=0.0;f30=0.0;f40=0.0;f48=0.0;f58=0.0;f68=0.0;
f70=0.0;f90=0.0;f78=0.0;f88=0.0;f98=0.0;vv =0.0;v1 =0.0;v2 =0.0;v3 =0.0;
v4 =0.0;fB0=0.0;fD0=0.0;v5 =0; v6 =0; fE0=0; fD8=0; fE8=0; val=0;
//----+===============================================================+
if(Time[limit+1]!=T0)
{
//+--- Âîññòàíîâåíèå ïåðåìåííûõ ############+
if(Time[limit+1]!=MEMORY2[0])return(-1);
fC0=MEMORY1[00];
fC8=MEMORY1[01];
fA8=MEMORY1[02];
s8 =MEMORY1[03];
f18=MEMORY1[04];
f38=MEMORY1[05];
s18=MEMORY1[06];
s20=MEMORY1[07];
s10=MEMORY1[08];
//+=======================+
s38=MEMORY2[01];
s48=MEMORY2[02];
s50=MEMORY2[03];
LP1=MEMORY2[04];
LP2=MEMORY2[05];
s28=MEMORY2[06];
s30=MEMORY2[07];
s48=MEMORY2[08];
s58=MEMORY2[09];
s60=MEMORY2[10];
s68=MEMORY2[11];
JMA=JMA_Buf[limit+1];
for(ii=0;ii<=127;ii++)list [ii]=MEMORY3[ii];
//+--- ####################################+
}
}
for(int bar = limit; bar >= 0; bar--)
{
//XXXXXXXX main cycle XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+
if((Input_Price_Customs<=0)||Input_Price_Customs>4)series=Close[bar];
if (Input_Price_Customs==1)series= Open[bar];
if (Input_Price_Customs==2)series=(High[bar]+Low[bar])/2;
if (Input_Price_Customs==3)series= High[bar];
if (Input_Price_Customs==4)series= Low [bar];
//----
if (LP1<61){LP1++; buffer[LP1]=series;}
if (LP1>30)
{
//++++++++++++++++++
v1 = Dl; v2 = v1;
if ((v1 / MathLog(2.0)) + 2.0 < 0.0) v3 = 0.0; else v3 = (v2 / MathLog(2.0)) + 2.0;
f98 = v3;
if ( f98 >= 2.5 ) f88 = f98 - 2.0; else f88 = 0.5;
f78 = Ds * f98; f90 = f78 / (f78 + 1.0);
if (f0 != 0)
{
f0 = 0; v5 = 0;
for( ii=0; ii<=29; ii++) {if (buffer[ii+1] != buffer[ii]) v5 = 1; break; }
fD8 = v5*30;
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--)
{
val=31-ii;
if (ii == 0) f8 = series; else f8 = buffer[val];
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.0; 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 + 0 > 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 + 0 > s58) && (s40 - 0 < 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.0);
if (LP2 + 1 > 31) LP2 = 31; else LP2 = LP2 + 1;
if (LP2 <= 30)
{
if (f28 > 0.0) f18 = f8; else f18 = f8 - f28 * f90;
if (f48 < 0.0) f38 = f8; else f38 = f8 - f48 * f90;
JMA = series;
if (LP2!=30) continue;
if (LP2==30)
{
fC0 = series;
if ( MathCeil(f78) >= 1) v4 = MathCeil(f78); else v4 = 1.0;
fE8 = IntPortion(v4);
if (MathFloor(f78) >= 1) v2 = MathFloor(f78); else v2 = 1.0;
fE0 = IntPortion(v2);
if (fE8== fE0) f68 = 1.0; 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[LP1 - v5]) * (1.0 - f68) / fE0 + (series - buffer[LP1 - v6]) * f68 / fE8;
}
}
else
{
if (f98 >= MathPow(fA0/f60, f88)) v1 = MathPow(fA0/f60, f88);
else v1 = f98;
if (v1 < 1.0) v2 = 1.0;
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.0) f18 = f8; else f18 = f8 - f28 * f70;
if (f48 < 0.0) f38 = f8; else f38 = f8 - f48 * f70;
}
}
if (LP2 >30)
{
f30 = MathPow(Kg, f58);
fC0 =(1.0 - f30) * series + f30 * fC0;
fC8 =(series - fC0) * (1.0 - Kg) + Kg * fC8;
fD0 = Pf * fC8 + fC0;
f20 = f30 *(-2.0);
f40 = f30 * f30;
fB0 = f20 + f40 + 1.0;
fA8 =(fD0 - JMA) * fB0 + f40 * fA8;
JMA = JMA + fA8;
}
}
//++++++++++++++++++
if (LP1 <=30)JMA=0.0;
JMA_Buf[bar]=JMA;
if (bar==1)
{
//+--- Ñîõðàíåíèå ïåðåìåííûõ
MEMORY1[00]=fC0;
MEMORY1[01]=fC8;
MEMORY1[02]=fA8;
MEMORY1[03]= s8;
MEMORY1[04]=f18;
MEMORY1[05]=f38;
MEMORY1[06]=s18;
MEMORY1[07]=s20;
MEMORY1[08]=s10;
//+====================+
MEMORY2[01]=s38;
MEMORY2[02]=s48;
MEMORY2[03]=s50;
MEMORY2[04]=LP1;
MEMORY2[05]=LP2;
MEMORY2[06]=s28;
MEMORY2[07]=s30;
MEMORY2[08]=s48;
MEMORY2[09]=s58;
MEMORY2[10]=s60;
MEMORY2[11]=s68;
MEMORY2[00]=Time[1];
for (ii=0; ii<=127; ii++)
MEMORY3[ii]=list[ii];
T0=Time[0];
//+--- ###################+
}
}
//XXXXXXX main cycle done XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+
return(0);
}
//+-----------------------------------------+
int IntPortion (double param)
{
if (param > 0) return (MathFloor (param));
if (param < 0) return (MathCeil (param));
return (0.0);
}
//+-----------------------------------------+
Comments