//+------------------------------------------------------------------+ //| Custom MACD.mq4 | //+------------------------------------------------------------------+ /* Added variable levels for different currency pairs. Calculated reasonable levels based on Phillip Nel's 4-hr macd strategy, using a EURUSD price of 1.3 and levels of 15/30/45. If the price goes up, we take the levels up with it, and vice versa. Utilizies different levels (*2 for daily, 1/3 for minute) for different TFs, as in v103. Also, I like the border around the histogram area, so I've created a permanent border, and added the ability to change the signal line from it's default of 1 and still keep the border around the histogram (so you can make this a standard 12,26,9 MACD and still have a border around the histogram if you want). Enjoy! - JoshDance, ForexFactory.com 2007-05-16 Christof Risch (iya) Added the option to use DEMAs instead of EMAs. (DEMA = 2*EMA - EMA of EMA) DEMA.ex4 (compiled DEMA.mq4) is needed in your indicator folder though. */ #property copyright "Copyright © 2007, Herb Spirit, Inc., portions Josh Jones" #property link "http://www.herbspirit.com/mql" #define INDICATOR_NAME "MACD_Colored" #define INDICATOR_VERSION "v104_DEMA" // iya (forexfactory) added DEMA option //---- indicator settings #property indicator_separate_window #property indicator_buffers 4 #property indicator_color1 Navy #property indicator_color2 Red #property indicator_color3 MidnightBlue #property indicator_style3 STYLE_SOLID #property indicator_color4 Black #property indicator_style4 STYLE_SOLID #property indicator_level1 45 #property indicator_level2 30 #property indicator_level3 15 #property indicator_level4 -15 #property indicator_level5 -30 #property indicator_level6 -45 #property indicator_level7 0 #property indicator_levelcolor Gray #property indicator_levelstyle STYLE_DOT //---- indicator parameters extern string Alert_On=""; extern bool EMail_Alert=false; extern int Max_Alerts=1; extern int Alert_Before_Minutes=15; extern int Alert_Every_Minutes=5; extern bool ShowSignal=true; extern int FastEMA=5; extern int SlowEMA=13; extern int SignalSMA=1; extern int FontSize=8; extern color FontColor=Black; extern bool Use_DEMAs=false; //---- indicator buffers double MacdBuffer[]; double MacdBufferUp[]; double MacdBufferDn[]; double SignalBuffer[]; double BorderLine[]; string shortname; datetime alertbartime,nextalerttime; int alertcount; string alerttype[]={"RT","RB","VT","VB","TC","ZB"}; int minlevel[]={5,10,15,-5,-10,-15}; int hourlevel[]={45,30,15,-15,-30,-45}; int daylevel[]={90,60,30,-30,-60,-90}; datetime nextbartime; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int init() { ///////////////////////////// ///////////////////////////// //---- drawing settings SetIndexStyle(0,DRAW_HISTOGRAM); SetIndexStyle(1,DRAW_HISTOGRAM); SetIndexStyle(2,DRAW_LINE); SetIndexStyle(3,DRAW_LINE); /* Okay, so I don't know what's up here--Apparently I can't reference a previously defined variable when initializing another variable, as it says that the variable is already defined... well, no duh, but I'm not trying to REdefine it. Anyway, all I know is, it's not like this in C or C++ or any other language I've used, so I'll just nasty my way around it this time... */ /* This is the base multiplier. Calculated from Phillip Nel's original 15/30/45 levels for EURUSD. So, if 15 is our low level for a typical EURUSD value of 1.3, we say 1.3 * baseMult = 15, and we get baseMult ~= 11.5. Good enough! Doesn't have to be really exact. */ double lastPrice = iClose(NULL,0,1); if (StringFind(Symbol(), "JPY", 0) != -1) { lastPrice = lastPrice / 100; } double baseHourMult = 11.5; double baseDayMult = baseHourMult*2; double baseMinMult = baseHourMult/3; double lowMinLevel = baseMinMult*lastPrice; double lowHourLevel = baseHourMult*lastPrice; double lowDayLevel = baseDayMult*lastPrice; ArrayInitialize(minlevel,0); minlevel[0] = lowMinLevel*3; minlevel[1] = lowMinLevel*2; minlevel[2] = lowMinLevel; minlevel[3] = -lowMinLevel; minlevel[4] = -lowMinLevel*2; minlevel[5] = -lowMinLevel*3; ArrayInitialize(hourlevel,0); hourlevel[0] = lowHourLevel*3; hourlevel[1] = lowHourLevel*2; hourlevel[2] = lowHourLevel; hourlevel[3] = -lowHourLevel; hourlevel[4] = -lowHourLevel*2; hourlevel[5] = -lowHourLevel*3; ArrayInitialize(daylevel,0); daylevel[0] = lowDayLevel*3; daylevel[1] = lowDayLevel*2; daylevel[2] = lowDayLevel; daylevel[3] = -lowDayLevel; daylevel[4] = -lowDayLevel*2; daylevel[5] = -lowDayLevel*3; switch(Period()) { case PERIOD_M1: case PERIOD_M5: case PERIOD_M15: case PERIOD_M30: for(int x=0;xMacdBuffer[i+1]) { MacdBufferUp[i]=MacdBuffer[i]; MacdBufferDn[i]=0; } else { MacdBufferDn[i]=MacdBuffer[i]; MacdBufferUp[i]=0; } if(ShowSignal||firstsignal) { if(!ShowTops(i)) { if(ShowBottoms(i)) firstsignal=false; } else firstsignal=false; } } //---- signal line counted in the 2-nd buffer for(i=0; ipriMACD) { pips--; close[0]-=Point; curMACD=(iMAOnArray(close,0,FastEMA,0,MODE_EMA,0)- iMAOnArray(close,0,SlowEMA,0,MODE_EMA,0))/Point; } } string objname=shortname+","+Symbol()+","+Period()+",pips"; if(ObjectFind(objname)<0) ObjectCreate(objname,OBJ_TEXT, WindowFind(shortname), Time[0]+Period()*60,MacdBuffer[0]/2); else ObjectMove(objname,0,Time[0]+Period()*60,MacdBuffer[0]/2); if(pips!=0) ObjectSetText(objname,DoubleToStr(pips,0),FontSize,"Courier",FontColor); else ObjectSetText(objname," ",FontSize,"Courier",FontColor); } //---- send alerts if(Max_Alerts==0) return(0); string alertmsg; if(!IsAlert(alertmsg)) return(0); alertmsg=Symbol()+","+Period()+" : "+alertmsg; Alert(alertmsg); if(EMail_Alert) SendMail("MACD Colored Alert",TimeToStr(TimeLocal(),TIME_DATE|TIME_SECONDS)+" : "+alertmsg); Print(alertmsg); //---- done return(0); } //+------------------------------------------------------------------+ bool ShowTops(int shift) { // check for basic pattern string objname=SetPatternObjectName(shift); bool basicpattern=(MacdBuffer[shift]diff1); if(MacdBuffer[shift+2]!=0) double ratio2=MathAbs(MacdBuffer[shift+3]/MacdBuffer[shift+2]); else ratio2=1000; if(MacdBuffer[shift+1]!=0) double ratio1=MathAbs(MacdBuffer[shift+2]/MacdBuffer[shift+1]); else ratio1=1000; if(MacdBuffer[shift+1]!=0) double ratio0=MathAbs(MacdBuffer[shift]/MacdBuffer[shift+1]); else ratio0=1000; roundpattern=(roundpattern||MathAbs(ratio0-ratio1)>0.1); // 0 and 2 are close to each other double minratio=0.8; if(MacdBuffer[shift+1]<10&&MacdBuffer[shift+1]>-10) minratio=0.6; bool ratioround=(ratio0>minratio&&ratio1>minratio&&ratio2>minratio); bool ratiovtop=(MathAbs(ratio0-ratio1)<0.3); string patname=" "; if(ratiovtop) patname="VT"; // default is v-top if(ratioround&&roundpattern) if(MacdBuffer[shift+1]<5) return(false); else patname="RT"; // round top pattern if(patname==" ") return(false); if(MacdBuffer[shift+1]<3&&MacdBuffer[shift+1]>-3) patname="ZB"; // zero line bounce if(MacdBuffer[shift+1]<=-3) patname="TC"; // trend continue bool strongpattern=(MacdBuffer[shift+4]10); if(ObjectFind(objname)<0) { ObjectCreate(objname,OBJ_TEXT, WindowFind(shortname), Time[shift+1],0); } if(strongpattern) ObjectSetText(objname,patname,FontSize+2,"Arial",FontColor); else ObjectSetText(objname,patname,FontSize,"Arial",FontColor); return(true); } bool ShowBottoms(int shift) { // check for basic pattern string objname=SetPatternObjectName(shift); string objdesc=ObjectDescription(objname); bool basicpattern=(MacdBuffer[shift]>MacdBuffer[shift+1]&& MacdBuffer[shift+2]>MacdBuffer[shift+1]&& MacdBuffer[shift+3]>MacdBuffer[shift+2]); if(!basicpattern) { ObjectDelete(objname); return(false); } double diff2=MathAbs(MacdBuffer[shift+2]-MacdBuffer[shift+3]); double diff1=MathAbs(MacdBuffer[shift+1]-MacdBuffer[shift+2]); double diff0=MathAbs(MacdBuffer[shift]-MacdBuffer[shift+1]); bool roundpattern=(diff2>diff1);//&&diff2>diff0); if(MacdBuffer[shift+3]!=0) double ratio2=MathAbs(MacdBuffer[shift+2]/MacdBuffer[shift+3]); else ratio2=1000; if(MacdBuffer[shift+2]!=0) double ratio1=MathAbs(MacdBuffer[shift+1]/MacdBuffer[shift+2]); else ratio1=1000; if(MacdBuffer[shift]!=0) double ratio0=MathAbs(MacdBuffer[shift+1]/MacdBuffer[shift]); else ratio0=1000; roundpattern=(roundpattern||MathAbs(ratio0-ratio1)>0.1); // 0 and 2 are close to each other double minratio=0.8; if(MacdBuffer[shift+1]<10&&MacdBuffer[shift+1]>-10) minratio=0.6; bool ratioround=(ratio0>minratio&&ratio1>minratio&&ratio2>minratio); bool ratiovtop=(MathAbs(ratio0-ratio1)<0.3); string patname=" "; if(ratiovtop) patname="VB"; // default is v-top if(ratioround&&roundpattern) if(MacdBuffer[shift+1]>-5) return(false); else patname="RB"; // round top pattern if(patname==" ") return(false); if(MacdBuffer[shift+1]<3&&MacdBuffer[shift+1]>-3) patname="ZB"; // zero line bounce if(MacdBuffer[shift+1]>=3) patname="TC"; // trend continue bool strongpattern=(MacdBuffer[shift+4]>MacdBuffer[shift+3]&& MacdBuffer[shift+5]>MacdBuffer[shift+4]&& MacdBuffer[shift+1]>10); if(ObjectFind(objname)<0) ObjectCreate(objname,OBJ_TEXT, WindowFind(shortname), Time[shift+1],0); if(strongpattern) ObjectSetText(objname,patname,FontSize+2,"Arial",FontColor); else ObjectSetText(objname,patname,FontSize,"Arial",FontColor); return(true); } bool IsAlert(string& alertmsg) { if(ArraySize(alerttype)==0) return(false); if(alerttype[0]=="") return(false); int shift; if(TimeCurrent()nextalerttime) { if(alertcount0) alertmsg=timetoalert+" minutes since "+alertname; else alertmsg=alertname; if(alertcount=97&&char<=122) input=StringSetChar(input,i,char-32); } } void StringToArray(string input, string& output[],string delim) { ArrayResize(output,0); int start=0; while(start