//+------------------------------------------------------------------+ //| StepMACrossover_v3.1 600+.mq4 | //| Copyright © 2010-18, TrendLaboratory | //| http://finance.groups.yahoo.com/group/TrendLaboratory | //| E-mail: igorad2003@yahoo.co.uk | //+------------------------------------------------------------------+ #property copyright "Copyright © 2010-18, TrendLaboratory" #property link "http://finance.groups.yahoo.com/group/TrendLaboratory" #property link "http://newdigital-world.com" #property indicator_chart_window #property indicator_buffers 5 #property indicator_color1 clrYellow #property indicator_color2 clrAqua #property indicator_color3 clrLime #property indicator_color4 clrDeepSkyBlue #property indicator_color5 clrTomato #property indicator_width1 1 #property indicator_width2 1 #property indicator_width3 1 #property indicator_width4 2 #property indicator_width5 2 enum ENUM_PRICE { close, // Close open, // Open high, // High low, // Low median, // Median typical, // Typical weightedClose, // Weighted Close medianBody, // Median Body (Open+Close)/2 average, // Average (High+Low+Open+Close)/4 trendBiased, // Trend Biased haClose, // Heiken Ashi Close haOpen, // Heiken Ashi Open haHigh, // Heiken Ashi High haLow, // Heiken Ashi Low haMedian, // Heiken Ashi Median haTypical, // Heiken Ashi Typical haWeighted, // Heiken Ashi Weighted Close haMedianBody, // Heiken Ashi Median Body haAverage, // Heiken Ashi Average haTrendBiased // Heiken Ashi Trend Biased }; enum ENUM_ATRMODE { atr, // ATR watr // WATR }; //---- input parameters input ENUM_TIMEFRAMES TimeFrame = 0; // TimeFrame input string FastMA = "=== Fast StepMA ==="; input ENUM_PRICE FastPrice = 0; // Fast StepMA Price input int FastLength = 5; // Fast StepMA Period input double FastStepSize = 0; // Fast Step Size in pips input double FastMultiplier = 2; // Fast Volatility's Factor or Multiplier input double FastMinStep = 0; // Fast Min Step in pips input ENUM_ATRMODE FastATRMode = 0; // Fast ATR Mode:0-ATR,1-WATR input int FastShift = 0; // Fast MA Displace input string SlowMA = "=== Slow StepMA ==="; input ENUM_PRICE SlowPrice = 0; // Slow StepMA Price input int SlowLength = 5; // Slow StepMA Period input double SlowStepSize = 0; // Slow Step Size in pips input double SlowMultiplier = 4; // Slow Volatility's Factor or Multiplier input double SlowMinStep = 0; // Slow Min Step in pips input ENUM_ATRMODE SlowATRMode = 0; // Slow ATR Mode:0-ATR,1-WATR input int SlowShift = 0; // Slow MA Displace input string TrendMA = "=== Trend StepMA ==="; input bool UseTrendStepMA = true; // Use Trend StepMA input ENUM_PRICE TrendPrice = 0; // Trend StepMA Price input int TrendLength = 5; // Trend StepMA Period input double TrendStepSize = 0; // Trend Step Size in pips input double TrendMultiplier = 8; // Trend Volatility's Factor or Multiplier input double TrendMinStep = 0; // Trend Min Step in pips input ENUM_ATRMODE TrendATRMode = 0; // Trend ATR Mode:0-ATR,1-WATR input int TrendShift = 0; // Trend MA Displace input string ColorLines = "=== Color Lines ==="; input bool ShowColorLines = true; // Show Color Lines input int ColorLineWidth = 1; // Color Line Width input color UpTrendColor = clrDodgerBlue; // UpTrend Color input color DnTrendColor = clrTomato; // DownTrend Color input string UniqueName = "StepMACross"; // Unique Name input int CountBars = 0; // Number of bars counted: 0-all bars input string Alerts = "=== Alerts, Emails & Notifications ==="; input bool AlertOn = false; // Alert On input int AlertShift = 1; // Alert Shift:0-current bar,1-previous bar input int SoundsNumber = 5; // Number of sounds after Signal input int SoundsPause = 5; // Pause in sec between sounds input string UpTrendSound = "alert.wav"; // UpTrend Sound input string DnTrendSound = "alert2.wav"; // DownTrend Sound input bool EmailOn = false; // Email Alert On input int EmailsNumber = 1; // Emails Number input bool PushNotificationOn = false; // Push Notification On //---- indicator buffers double fastLine[]; double slowLine[]; double trendLine[]; double buySignal[]; double sellSignal[]; double trend[]; double fastshift[]; double slowshift[]; double trendshift[]; double fastprice[]; double slowprice[]; double trendprice[]; double maintrend[]; int timeframe, sumlength, cBars, draw_begin; double _point; string IndicatorName, TF, short_name; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { timeframe = TimeFrame; if(timeframe <= Period()) timeframe = Period(); TF = tf(timeframe); IndicatorDigits(Digits); //---- IndicatorBuffers(13); SetIndexBuffer( 0, fastLine); SetIndexStyle(0,DRAW_LINE ); SetIndexBuffer( 1, slowLine); SetIndexStyle(1,DRAW_LINE ); SetIndexBuffer( 2, trendLine); SetIndexStyle(2,DRAW_LINE ); SetIndexBuffer( 3, buySignal); SetIndexStyle(3,DRAW_ARROW); SetIndexArrow(3,233); SetIndexBuffer( 4,sellSignal); SetIndexStyle(4,DRAW_ARROW); SetIndexArrow(4,234); SetIndexBuffer( 5, trend); SetIndexBuffer( 6, fastshift); SetIndexBuffer( 7, slowshift); SetIndexBuffer( 8,trendshift); SetIndexBuffer( 9, fastprice); SetIndexBuffer(10, slowprice); SetIndexBuffer(11,trendprice); SetIndexBuffer(12, maintrend); //---- IndicatorName = WindowExpertName(); short_name = IndicatorName+"["+TF+"]("+(string)FastPrice+","+(string)FastLength+","+DoubleToStr(FastStepSize,1)+","+(string)SlowPrice+","+(string)SlowLength+","+DoubleToStr(SlowStepSize,1)+")"; IndicatorShortName(short_name); SetIndexLabel(0,"Fast StepMA"); SetIndexLabel(1,"Slow StepMA"); SetIndexLabel(2,"Trend StepMA"); SetIndexLabel(3,"Buy Signal" ); SetIndexLabel(4,"Sell Signal"); //---- if(UseTrendStepMA) sumlength = MathMax(FastLength,MathMax(SlowLength,TrendLength)); else sumlength = MathMax(FastLength,SlowLength); if(CountBars == 0) cBars = Bars - sumlength; else cBars = CountBars; draw_begin = Bars - cBars; SetIndexDrawBegin(0,draw_begin); SetIndexDrawBegin(1,draw_begin); SetIndexDrawBegin(2,draw_begin); SetIndexDrawBegin(3,draw_begin); SetIndexDrawBegin(4,draw_begin); //---- _point = _Point*MathPow(10,Digits%2); return(INIT_SUCCEEDED); } void OnDeinit(const int reason) { Comment(""); ObjectsDeleteAll(0,UniqueName); ChartRedraw(); } //+------------------------------------------------------------------+ //| StepMACrossover_v3.1 600+ | //+------------------------------------------------------------------+ int start() { int i, shift, limit, limit1, counted_bars = IndicatorCounted(); bool uptrend, dntrend; if(counted_bars > 0) limit = Bars - counted_bars - 1; if(counted_bars < 0) return(0); if(counted_bars < 1) { limit = MathMin(Bars - 1,(cBars + sumlength)*timeframe/Period()); for(i=0;i trendLine[shift] && fastLine1 <= trendLine1) PlotVLine(upline,0,Time[shift],UpTrendColor,ColorLineWidth,0); if(fastLine[shift] < trendLine[shift] && fastLine1 >= trendLine1) PlotVLine(dnline,0,Time[shift],DnTrendColor,ColorLineWidth,0); } } if(CountBars > 0) { SetIndexDrawBegin(0,Bars - cBars); SetIndexDrawBegin(1,Bars - cBars); SetIndexDrawBegin(2,Bars - cBars); SetIndexDrawBegin(3,Bars - cBars); SetIndexDrawBegin(4,Bars - cBars); } return(0); } for(shift=limit;shift>=0;shift--) { if(FastPrice <= 9) fastprice[shift] = getPrice((int)FastPrice,shift); else if(FastPrice > 9 && FastPrice <= 19) fastprice[shift] = HeikenAshi(0,FastPrice-10,MathMin(Bars-1,cBars+sumlength),shift); fastshift[shift] = StepMA(0,fastprice,FastLength,FastStepSize,FastMultiplier,FastATRMode,FastMinStep,MathMin(Bars-FastLength-1,cBars),shift); if(SlowPrice <= 9) slowprice[shift] = getPrice((int)SlowPrice,shift); else if(SlowPrice > 9 && SlowPrice <= 19) slowprice[shift] = HeikenAshi(0,SlowPrice-10,MathMin(Bars-1,cBars+sumlength),shift); slowshift[shift] = StepMA(1,slowprice,SlowLength,SlowStepSize,SlowMultiplier,SlowATRMode,SlowMinStep,MathMin(Bars-SlowLength-1,cBars),shift); if(UseTrendStepMA) { if(TrendPrice <= 9) trendprice[shift] = getPrice((int)TrendPrice,shift); else if(TrendPrice > 9 && TrendPrice <= 19) trendprice[shift] = HeikenAshi(0,TrendPrice-10,MathMin(Bars-1,cBars+sumlength),shift); trendshift[shift] = StepMA(2,trendprice,TrendLength,TrendStepSize,TrendMultiplier,TrendATRMode,TrendMinStep,MathMin(Bars-TrendLength-1,cBars),shift); } } for(shift=limit1;shift>=0;shift--) { if(FastShift >= 0 || (FastShift < 0 && shift >= MathAbs(FastShift ))) fastLine[shift] = fastshift[shift+FastShift]; if(SlowShift >= 0 || (SlowShift < 0 && shift >= MathAbs(SlowShift ))) slowLine[shift] = slowshift[shift+SlowShift]; if(UseTrendStepMA) { if(TrendShift >= 0 || (TrendShift < 0 && shift >= MathAbs(TrendShift))) trendLine[shift] = trendshift[shift+TrendShift]; maintrend[shift] = maintrend[shift+1]; if(trendLine[shift] > trendLine[shift+1]) maintrend[shift] = 1; if(trendLine[shift] < trendLine[shift+1]) maintrend[shift] =-1; uptrend = maintrend[shift] > 0; dntrend = maintrend[shift] < 0; if(ShowColorLines && shift < cBars) { upline = UniqueName+" uptrend "+TimeToString(Time[shift]); dnline = UniqueName+" dntrend "+TimeToString(Time[shift]); ObjectDelete(0,upline); ObjectDelete(0,dnline); if(fastLine[shift] > trendLine[shift] && fastLine[shift] != EMPTY_VALUE && fastLine[shift+1] <= trendLine[shift+1]) PlotVLine(upline,0,Time[shift],UpTrendColor,ColorLineWidth,0); if(fastLine[shift] < trendLine[shift] && trendLine[shift] != EMPTY_VALUE && fastLine[shift+1] >= trendLine[shift+1]) PlotVLine(dnline,0,Time[shift],DnTrendColor,ColorLineWidth,0); } } else { uptrend = true; dntrend = true; } trend[shift] = trend[shift+1]; if(fastLine[shift] > slowLine[shift] && fastLine[shift] != EMPTY_VALUE && trend[shift+1] != 1) trend[shift] = 1; if(fastLine[shift] < slowLine[shift] && slowLine[shift] != EMPTY_VALUE && trend[shift+1] !=-1) trend[shift] =-1; double gap = 0.5*MathCeil(iATR(NULL,0,14,shift+1)/_Point)*_Point; buySignal [shift] = EMPTY_VALUE; sellSignal[shift] = EMPTY_VALUE; if(trend[shift] != trend[shift+1]) { if(trend[shift] > 0) buySignal [shift] = MathMin(fastLine[shift],slowLine[shift]) - gap; if(trend[shift] < 0) sellSignal[shift] = MathMax(fastLine[shift],slowLine[shift]) + 2*gap; } } if(AlertOn || EmailOn || PushNotificationOn) { int alertbar = limit1 + AlertShift; bool crossAbove = (trend[alertbar] > 0 && trend[alertbar+1] <= 0)||(UseTrendStepMA && fastLine[alertbar] > trendLine[alertbar] && fastLine[alertbar] != EMPTY_VALUE && fastLine[alertbar+1] <= trendLine[alertbar+1]); bool crossBelow = (trend[alertbar] < 0 && trend[alertbar+1] >= 0)||(UseTrendStepMA && fastLine[alertbar] < trendLine[alertbar] && trendLine[alertbar] != EMPTY_VALUE && fastLine[alertbar+1] >= trendLine[alertbar+1]); ; if(crossAbove || crossBelow) { if(isNewBar(timeframe)) { if(AlertOn) { BoxAlert(crossAbove," : BUY Signal @ " +DoubleToStr(Close[AlertShift],Digits)); BoxAlert(crossBelow," : SELL Signal @ "+DoubleToStr(Close[AlertShift],Digits)); } if(EmailOn) { EmailAlert(crossAbove,"BUY" ," : BUY Signal @ " +DoubleToStr(Close[AlertShift],Digits),EmailsNumber); EmailAlert(crossBelow,"SELL"," : SELL Signal @ "+DoubleToStr(Close[AlertShift],Digits),EmailsNumber); } if(PushNotificationOn) { PushAlert(crossAbove," : BUY Signal @ " +DoubleToStr(Close[AlertShift],Digits)); PushAlert(crossBelow," : SELL Signal @ "+DoubleToStr(Close[AlertShift],Digits)); } } else { if(AlertOn) { WarningSound(crossAbove,SoundsNumber,SoundsPause,UpTrendSound,Time[AlertShift]); WarningSound(crossBelow,SoundsNumber,SoundsPause,DnTrendSound,Time[AlertShift]); } } } } if(CountBars > 0) { SetIndexDrawBegin(0,Bars - cBars); SetIndexDrawBegin(1,Bars - cBars); SetIndexDrawBegin(2,Bars - cBars); SetIndexDrawBegin(3,Bars - cBars); SetIndexDrawBegin(4,Bars - cBars); } return(0); } //--- StepMA int steptrend[3][2]; double smax[3][2], smin[3][2], stepma[3][2]; datetime prevtime[3]; double StepMA(int index,double& price[],int length,double size,double mult,int atrmode,double minstep,int cbars,int bar) { if(prevtime[index] != Time[bar]) { smin[index][1] = smin[index][0]; smax[index][1] = smax[index][0]; stepma[index][1] = stepma[index][0]; steptrend[index][1] = steptrend[index][0]; prevtime[index] = Time[bar]; } if(bar >= cbars) {smax[index][0] = price[bar]; smax[index][0] = price[bar]; return(EMPTY_VALUE);} if(length > 0) { double sumRange = 0; double weight = 0; for (int i=length-1;i>=0;i--) { if(atrmode == 0) double alpha = 1.0; else alpha = 1.0*(length - i)/length; sumRange += alpha*MathAbs(price[bar+i] - price[bar+i+1]); weight += alpha; } double volty = MathMax(size*_point,mult*sumRange/length); } else volty = size*_point; smax[index][0] = smax[index][1]; smin[index][0] = smin[index][1]; steptrend[index][0] = steptrend[index][1]; if(price[bar] > smax[index][1]) steptrend[index][0] = 1; if(price[bar] < smin[index][1]) steptrend[index][0] =-1; if(steptrend[index][0] > 0) { smax[index][0] = MathMax(smax[index][1],MathMax(price[bar],price[bar+1])); if(smax[index][0] < smax[index][1]) smax[index][0] = smax[index][1]; smin[index][0] = NormalizeDouble(smax[index][0] - volty,Digits); if(smin[index][0] < smin[index][1]) smin[index][0] = smin[index][1]; if(smin[index][0] > smin[index][1] && smax[index][0] == smax[index][1]) smin[index][0] = smin[index][1]; } else if(steptrend[index][0] < 0) { smin[index][0] = MathMin(smin[index][1],MathMin(price[bar],price[bar+1])); if(smin[index][0] > smin[index][1]) smin[index][0] = smin[index][1]; smax[index][0] = NormalizeDouble(smin[index][0] + volty,Digits); if(smax[index][0] > smax[index][1]) smax[index][0] = smax[index][1]; if(smax[index][0] < smax[index][1] && smin[index][0] == smin[index][1]) smax[index][0] = smax[index][1]; } stepma[index][0] = 0.5*(smin[index][0] + smax[index][0]); if(minstep > 0) { if(MathAbs(stepma[index][0] - stepma[index][1]) < minstep*_point) stepma[index][0] = stepma[index][1]; } return(stepma[index][0]); } double getPrice(int price,int bar) { double close = Close[bar]; double open = Open [bar]; double high = High [bar]; double low = Low [bar]; switch(price) { case 0: return(close); break; case 1: return(open ); break; case 2: return(high ); break; case 3: return(low ); break; case 4: return((high + low)/2); break; case 5: return((high + low + close)/3); break; case 6: return((high + low + 2*close)/4); break; case 7: return((close + open)/2); break; case 8: return((high + low + close + open)/4); break; case 9: if(close > open) return((high + close)/2); else return((low + close)/2); break; default: return(close); break; } } // HeikenAshi Price double haClose[1][2], haOpen[1][2], haHigh[1][2], haLow[1][2]; datetime prevhatime[1]; double HeikenAshi(int index,int price,int cbars,int bar) { if(prevhatime[index] != Time[bar]) { haClose[index][1] = haClose[index][0]; haOpen [index][1] = haOpen [index][0]; haHigh [index][1] = haHigh [index][0]; haLow [index][1] = haLow [index][0]; prevhatime[index] = Time[bar]; } if(bar == cbars) { haClose[index][0] = Close[bar]; haOpen [index][0] = Open [bar]; haHigh [index][0] = High [bar]; haLow [index][0] = Low [bar]; } else if(bar < cbars) { haClose[index][0] = (Open[bar] + High[bar] + Low[bar] + Close[bar])/4; haOpen [index][0] = (haOpen[index][1] + haClose[index][1])/2; haHigh [index][0] = MathMax(High[bar],MathMax(haOpen[index][0],haClose[index][0])); haLow [index][0] = MathMin(Low [bar],MathMin(haOpen[index][0],haClose[index][0])); } switch(price) { case 0: return(haClose[index][0]); break; case 1: return(haOpen [index][0]); break; case 2: return(haHigh [index][0]); break; case 3: return(haLow [index][0]); break; case 4: return((haHigh [index][0] + haLow [index][0])/2); break; case 5: return((haHigh[index][0] + haLow[index][0] + haClose[index][0])/3); break; case 6: return((haHigh[index][0] + haLow[index][0] + 2*haClose[index][0])/4); break; case 7: return((haClose[index][0] + haOpen[index][0])/2); break; case 8: return((haHigh[index][0] + haLow[index][0] + haClose[index][0] + haOpen[index][0])/4); break; case 9: if(haClose[index][0] > haOpen[index][0]) return((haHigh[index][0] + haClose[index][0])/2); else return((haLow[index][0] + haClose[index][0])/2); break; default: return(haClose[index][0]); break; } } datetime prevnbtime; bool isNewBar(int tf) { bool res = false; if(tf >= 0) { if(iTime(NULL,tf,0) != prevnbtime) { res = true; prevnbtime = iTime(NULL,tf,0); } } else res = true; return(res); } string prevmess; bool BoxAlert(bool cond,string text) { string mess = IndicatorName + "("+Symbol()+","+TF + ")" + text; if (cond && mess != prevmess) { Alert (mess); prevmess = mess; return(true); } return(false); } datetime pausetime; bool Pause(int sec) { if(TimeCurrent() >= pausetime + sec) {pausetime = TimeCurrent(); return(true);} return(false); } datetime warningtime; void WarningSound(bool cond,int num,int sec,string sound,datetime curtime) { static int i; if(cond) { if(curtime != warningtime) i = 0; if(i < num && Pause(sec)) {PlaySound(sound); warningtime = curtime; i++;} } } string prevemail; bool EmailAlert(bool cond,string text1,string text2,int num) { string subj = "New " + text1 +" Signal from " + IndicatorName + "!!!"; string mess = IndicatorName + "("+Symbol()+","+TF + ")" + text2; if (cond && mess != prevemail) { if(subj != "" && mess != "") for(int i=0;i= PERIOD_H1 ) result = "H" + (string)(itimeframe/PERIOD_H1); if(itimeframe >= PERIOD_D1 ) result = "D" + (string)(itimeframe/PERIOD_D1); if(itimeframe >= PERIOD_W1 ) result = "W" + (string)(itimeframe/PERIOD_W1); if(itimeframe >= PERIOD_MN1) result = "MN" + (string)(itimeframe/PERIOD_MN1); } return(result); } void PlotVLine(string name,int win,datetime time,color clr,int width,int style) { int objfind = ObjectFind(0,name); if(objfind < 0) { if(!ObjectCreate(0,name,OBJ_VLINE,win,time,0)) { Print(__FUNCTION__,": failed to create OBJ_VLINE! Error code = ",GetLastError()); return; } else objfind = 1; } if(objfind >= 0) { ObjectSetInteger(0,name,OBJPROP_TIME ,0, time); ObjectSetInteger(0,name,OBJPROP_WIDTH , width); ObjectSetInteger(0,name,OBJPROP_STYLE , style); ObjectSetInteger(0,name,OBJPROP_RAY , false); ObjectSetInteger(0,name,OBJPROP_BACK , true); ObjectSetInteger(0,name,OBJPROP_COLOR , clr); ObjectSetInteger(0,name,OBJPROP_SELECTABLE , false); ObjectSetInteger(0,name,OBJPROP_SELECTED , 0); ObjectSetInteger(0,name,OBJPROP_HIDDEN , true); ObjectSetInteger(0,name,OBJPROP_ZORDER , 0); } }