Price Data Components
Indicators Used
Miscellaneous
0
Views
0
Downloads
0
Favorites
MACD_Colored_v104
//+------------------------------------------------------------------+
//| 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
*/
#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" // JoshDance (forexfactory) added variable levels
//---- indicator settings
#property indicator_separate_window
#property indicator_buffers 4
#property indicator_color1 Lime
#property indicator_color2 Red
#property indicator_color3 Silver
#property indicator_style3 STYLE_SOLID
#property indicator_color4 Silver
#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="RT,RB,VT,VB,TC,ZB";
extern bool EMail_Alert=true;
extern int Max_Alerts=1;
extern int Alert_Before_Minutes=5;
extern int Alert_Every_Minutes=5;
extern bool ShowSignal=False;
extern int FastEMA=5;
extern int SlowEMA=13;
extern int SignalSMA=1;
extern int FontSize=8;
extern color FontColor=White;
//---- 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;x<ArraySize(minlevel);x++)
SetLevelValue(x,minlevel[x]);
break;
case PERIOD_H1:
case PERIOD_H4:
for(x=0;x<ArraySize(hourlevel);x++)
SetLevelValue(x,hourlevel[x]);
break;
default:
for(x=0;x<ArraySize(daylevel);x++)
SetLevelValue(x,daylevel[x]);
}
SetIndexDrawBegin(1,SlowEMA);
IndicatorDigits(1);
//---- indicator buffers mapping
SetIndexBuffer(0,MacdBufferUp);
SetIndexBuffer(1,MacdBufferDn);
SetIndexBuffer(2,SignalBuffer);
SetIndexBuffer(3,BorderLine);
//---- name for DataWindow and indicator subwindow label
shortname=WindowExpertName();
IndicatorShortName(shortname);
SetIndexLabel(0,"MACD Up");
SetIndexLabel(1,"MACD Down");
SetIndexLabel(2,"Signal");
SetIndexLabel(3,"Border");
ArrayResize(MacdBuffer,Bars-SlowEMA);
ArraySetAsSeries(MacdBuffer,true);
// check input parms
ValidateAlertType();
//---- initialization done
alertbartime=0;
nextalerttime=0;
alertcount=0;
nextbartime=0;
return(0);
}
int deinit()
{
string objname=shortname+","+Symbol()+","+Period();
int i;
while(i<ObjectsTotal())
{
string nextobj=ObjectName(i);
if(StringSubstr(nextobj,0,StringLen(objname))==objname)
ObjectDelete(nextobj);
else
i++;
}
}
//+------------------------------------------------------------------+
//| Moving Averages Convergence/Divergence |
//+------------------------------------------------------------------+
int start()
{
int limit;
int counted_bars=IndicatorCounted();
//---- last counted bar will be recounted
if(Time[0]!=nextbartime)
{
limit=Bars-SlowEMA;
ArrayResize(MacdBuffer,limit);
nextbartime=Time[0];
}
else
limit=MathMin(Bars-SlowEMA,Bars-counted_bars);
//---- macd counted in the 1-st buffer
for(int i=0;i<limit;i++) {
MacdBuffer[i]=(iMA(NULL,0,FastEMA,0,MODE_EMA,PRICE_CLOSE,i)-
iMA(NULL,0,SlowEMA,0,MODE_EMA,PRICE_CLOSE,i))/Point;
}
// macd colored set here
bool firstsignal=true;
for(i=0;i<limit;i++)
{
if(MacdBuffer[i]>MacdBuffer[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; i<limit; i++) {
SignalBuffer[i]=iMAOnArray(MacdBuffer,Bars,SignalSMA,0,MODE_SMA,i);
BorderLine[i]=MacdBuffer[i];
}
//---- pips to change color calculation
double priMACD=(iMA(NULL,0,FastEMA,0,MODE_EMA,PRICE_CLOSE,1)-
iMA(NULL,0,SlowEMA,0,MODE_EMA,PRICE_CLOSE,1))/Point;
double close[];
ArrayResize(close,Bars);
ArraySetAsSeries(close,true);
ArrayCopy(close,Close,0,0,ArraySize(close));
double curMACD=(iMAOnArray(close,0,FastEMA,0,MODE_EMA,0)-
iMAOnArray(close,0,SlowEMA,0,MODE_EMA,0))/Point;
int pips;
if(curMACD<priMACD)
{
while(curMACD<priMACD)
{
pips++;
close[0]+=Point;
curMACD=(iMAOnArray(close,0,FastEMA,0,MODE_EMA,0)-
iMAOnArray(close,0,SlowEMA,0,MODE_EMA,0))/Point;
}
}
else
{
while(curMACD>priMACD)
{
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]<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);
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]<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 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()<Time[0]+(Period()-Alert_Before_Minutes)*60)
shift=1;
string objname=SetPatternObjectName(shift);
if(ObjectFind(objname)<0)
return(false);
string thisalert=StringTrimLeft(StringTrimRight(ObjectDescription(objname)));
bool needalert=false;
if(alerttype[0]=="ANY")
needalert=(thisalert!="");
else
{
for(int i=0;i<ArraySize(alerttype);i++)
{
if(alerttype[i]==thisalert)
{
needalert=true;
break;
}
}
}
if(alertbartime!=Time[shift])
{
nextalerttime=0;
alertcount=0;
}
if(!needalert)
return(false);
alertbartime=Time[shift];
if(TimeCurrent()>nextalerttime)
{
if(alertcount<Max_Alerts)
{
alertcount++;
nextalerttime=TimeCurrent()+Alert_Every_Minutes*60;
int timetoalert=(TimeCurrent()-Time[shift]-Period()*60)/60;
string alertname=SetAlertName(thisalert);
if(timetoalert<0)
alertmsg=(-1*timetoalert)+" minutes till "+alertname;
else
if(timetoalert>0)
alertmsg=timetoalert+" minutes since "+alertname;
else
alertmsg=alertname;
if(alertcount<Max_Alerts)
alertmsg=alertmsg+". Next Alert at "+TimeToStr(
nextalerttime+TimeLocal()-TimeCurrent(),TIME_SECONDS);
else
alertmsg=alertmsg+". This was the last Alert";
return(true);
}
}
return(false);
}
string SetAlertName(string alertabbr)
{
if(alertabbr=="RT")
return("Round Top");
if(alertabbr=="VT")
return("V-Top");
if(alertabbr=="RB")
return("Round Bottom");
if(alertabbr=="VB")
return("V-Bottom");
if(alertabbr=="TC")
return("Trend Continue");
if(alertabbr=="ZB")
return("Zero Bounce");
return("");
}
string SetPatternObjectName(int shift)
{
return(shortname+","+Symbol()+","+Period()+","+Time[shift]);
}
void ValidateAlertType()
{
StringUpperCase(Alert_On);
StringToArray(StringTrimLeft(StringTrimRight(Alert_On)), alerttype,",");
}
void StringUpperCase(string& input)
{
for(int i=0;i<StringLen(input);i++)
{
int char=StringGetChar(input,i);
if(char>=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<StringLen(input))
{
int delpos=StringFind(input,delim,start);
if(delpos<0)
{
string nextelem=StringSubstr(input,start);
start=StringLen(input);
}
else
{
nextelem=StringSubstr(input,start,delpos-start);
start=delpos+1;
}
ArrayResize(output,ArraySize(output)+1);
output[ArraySize(output)-1]=nextelem;
}
}
Comments
Markdown Formatting Guide
# H1
## H2
### H3
**bold text**
*italicized text*
[title](https://www.example.com)

`code`
```
code block
```
> blockquote
- Item 1
- Item 2
1. First item
2. Second item
---