//
// "00-Mac5_v100.mq4" -- MA convergence
//
//    Ver. 1.00  2009/06/09(Tue)  initial version
//
//
#property  copyright "00"
#property  link      "http://www.mql4.com/"

//---- defines

//---- indicator settings
#property  indicator_chart_window

#property  indicator_buffers  8

#property  indicator_color1  DodgerBlue
#property  indicator_color2  Crimson
#property  indicator_color3  Pink
#property  indicator_color4  Magenta
#property  indicator_color5  Magenta
#property  indicator_color6  White
#property  indicator_color7  White
#property  indicator_color8  Red

#property  indicator_width1  1
#property  indicator_width2  1
#property  indicator_width3  2
#property  indicator_width4  1
#property  indicator_width5  1
#property  indicator_width6  2
#property  indicator_width7  2
#property  indicator_width8  1

#property  indicator_style1  STYLE_SOLID
#property  indicator_style2  STYLE_SOLID
#property  indicator_style3  STYLE_SOLID
#property  indicator_style4  STYLE_SOLID
#property  indicator_style5  STYLE_SOLID
#property  indicator_style6  STYLE_SOLID
#property  indicator_style7  STYLE_SOLID
#property  indicator_style8  STYLE_SOLID

//---- indicator parameters
extern double ConvergenceMargin  = 15;           // convergence margin in PP
extern double YokoYokoMargin     = 12;           // yokoyoko margin
extern int    YokoYokoBars       = 20;           // yokoyoko bars
extern int    MA1                = 21;           // MA1
extern int    MA2                = 55;           // MA2
extern int    MA3                = 89;           // MA3
extern int    MA4                = 144;          // MA4
extern int    MA5                = 200;          // MA5
extern int    appliedPrice       = PRICE_CLOSE;  // 0:CLOSE 1:OPEN 2:HIGH 3:LOW 4:MEDIAN 5:TYPICAL 6:WEIGHTED
extern int    nMaxBars           = 2000;         // maximum number of bars to calculate, 0: no limit

//---- indicator buffers
double  BufferSignalLong[];     // 0: Signal, Long
double  BufferSignalShort[];    // 1: Signal, Short
double  BufferConvergence[];    // 2: convergence of MAs
double  BufferMaUpper[];        // 3: MA upper
double  BufferMaLower[];        // 4: MA lower
double  BufferYokoYokoUpper[];  // 5: yokoyoko upper
double  BufferYokoYokoLower[];  // 6: yokoyoko lower
double  BufferMaMain[];         // 7: MA1

//---- vars
string  sIndicatorName  = "";
string  sIndSelf        = "00-Mac5_v100";
int     markLong        = 233;
int     markShort       = 234;
int     markConvergence = 159;
int     markYokoYoko    = 158;

//----------------------------------------------------------------------
string TimeFrameToStr(int timeFrame)
{
    switch (timeFrame) {
    case 1:     return("M1");
    case 5:     return("M5");
    case 15:    return("M15");
    case 30:    return("M30");
    case 60:    return("H1");
    case 240:   return("H4");
    case 1440:  return("D1");
    case 10080: return("W1");
    case 43200: return("MN");
    }
    
    return("??");
}

//----------------------------------------------------------------------
void init()
{
    string tf = TimeFrameToStr(Period());
    sIndicatorName = sIndSelf + "(" + tf + "," + MA1 + "," + MA2 + "," + MA3 + "," + MA4 + "," + MA5 + ")";
    
    IndicatorShortName(sIndicatorName);
    
    SetIndexBuffer(0, BufferSignalLong);
    SetIndexBuffer(1, BufferSignalShort);
    SetIndexBuffer(2, BufferConvergence);
    SetIndexBuffer(3, BufferMaUpper);
    SetIndexBuffer(4, BufferMaLower);
    SetIndexBuffer(5, BufferYokoYokoUpper);
    SetIndexBuffer(6, BufferYokoYokoLower);
    SetIndexBuffer(7, BufferMaMain);
    
    SetIndexLabel(0, "Signal, Long");
    SetIndexLabel(1, "Signal, Short");
    SetIndexLabel(2, "Convergence of MAs");
    SetIndexLabel(3, "MA upper");
    SetIndexLabel(4, "MA lower");
    SetIndexLabel(5, "YokoYoko upper");
    SetIndexLabel(6, "YokoYoko lower");
    SetIndexLabel(7, "MA main");
    
    SetIndexStyle(0, DRAW_ARROW);
    SetIndexStyle(1, DRAW_ARROW);
    SetIndexStyle(2, DRAW_ARROW);
    SetIndexStyle(3, DRAW_LINE);
    SetIndexStyle(4, DRAW_LINE);
    SetIndexStyle(5, DRAW_ARROW);
    SetIndexStyle(6, DRAW_ARROW);
    SetIndexStyle(7, DRAW_LINE);
    
    SetIndexArrow(0, markLong);
    SetIndexArrow(1, markShort);
    SetIndexArrow(2, markConvergence);
    SetIndexArrow(5, markYokoYoko);
    SetIndexArrow(6, markYokoYoko);
    
    SetIndexDrawBegin(0, MA5);
    SetIndexDrawBegin(1, MA5);
    SetIndexDrawBegin(2, 0);
    SetIndexDrawBegin(3, MA2);
    SetIndexDrawBegin(4, MA3);
    SetIndexDrawBegin(5, MA5);
    SetIndexDrawBegin(6, MA5);
    SetIndexDrawBegin(7, MA1);
}

//----------------------------------------------------------------------
void start()
{
    int i, j;
    int limit;
    int counted_bars = IndicatorCounted();
    
    if (counted_bars > 0) {
	counted_bars--;
    }
    
    limit = Bars - counted_bars;
    int limit0 = limit;
    if (nMaxBars > 0) {
	limit = MathMin(limit, nMaxBars);
    }
    
    // clear beyond limits
    for (i = limit0 - 1; i >= limit; i--) {
	BufferSignalLong[i]    = EMPTY_VALUE;
	BufferSignalShort[i]   = EMPTY_VALUE;
	BufferConvergence[i]   = EMPTY_VALUE;
	BufferMaMain[i]        = EMPTY_VALUE;
	BufferMaUpper[i]       = EMPTY_VALUE;
	BufferMaLower[i]       = EMPTY_VALUE;
	BufferYokoYokoUpper[i] = EMPTY_VALUE;
	BufferYokoYokoLower[i] = EMPTY_VALUE;
    }
    
    bool bConvergence;
    bool bYokoYoko;
    for (i = limit - 1; i >= 0; i--) {
	double ma1 = iMA(NULL, 0, MA1, 0, MODE_SMA, appliedPrice, i);
	double ma2 = iMA(NULL, 0, MA2, 0, MODE_SMA, appliedPrice, i);
	double ma3 = iMA(NULL, 0, MA3, 0, MODE_SMA, appliedPrice, i);
	double ma4 = iMA(NULL, 0, MA4, 0, MODE_SMA, appliedPrice, i);
	double ma5 = iMA(NULL, 0, MA5, 0, MODE_SMA, appliedPrice, i);
	double maUpper = MathMax(ma1, MathMax(ma2, MathMax(ma3, MathMax(ma4, ma5))));
	double maLower = MathMin(ma1, MathMin(ma2, MathMin(ma3, MathMin(ma4, ma5))));
	
	// MA1
	BufferMaMain[i] = ma1;
	
	// MA upper/lower line
	BufferMaUpper[i] = maUpper;
	BufferMaLower[i] = maLower;
	
	// Convergence check
	{
	    double margin = (maUpper - maLower) / Point;
	    bConvergence = (margin < ConvergenceMargin);
	    if (bConvergence) {
		BufferConvergence[i] = ma1;
	    } else {
		BufferConvergence[i] = EMPTY_VALUE;
	    }
	}
	
	// YokoYoko check
	{
	    for (j = 0; j < YokoYokoBars; j++) {
		int x = i + j;
		if (BufferMaUpper[x] - BufferMaLower[x] > YokoYokoMargin * Point) {
		    break;
		}
	    }
	    if (j == YokoYokoBars) {
		bYokoYoko = true;
		BufferYokoYokoUpper[i] = BufferMaUpper[i] - Point;
		BufferYokoYokoLower[i] = BufferMaLower[i] + Point;
	    } else {
		bYokoYoko = false;
		BufferYokoYokoUpper[i] = EMPTY_VALUE;
		BufferYokoYokoLower[i] = EMPTY_VALUE;
	    }
	}
	
	bool bLongOk = true;
	bool bShortOk = true;
	if (!bYokoYoko) {
	    if (BufferMaMain[i] >= BufferMaMain[i + 1]) {
		bShortOk = false;
	    } else {
		bLongOk = false;
	    }
	}
	
	double open0 = Open[i];
	double hi0 = High[i];
	double lo0 = Low[i];
	double close0 = Close[i];
	double upper0 = MathMax(open0, close0);
	double lower0 = MathMin(open0, close0);
	
	double sigLong = EMPTY_VALUE;
	double sigShort = EMPTY_VALUE;
	if (bConvergence) {
	    double ofst = ConvergenceMargin * Point * 0.5;
	    if (bLongOk) {
		if ((ma1 >= maUpper && close0 >= maUpper) ||
		    (bYokoYoko && lo0 >= maUpper) || (!bYokoYoko && lower0 >= maUpper)) {
		    
		    sigLong = ma1 - ofst;
		}
	    }
	    if (bShortOk) {
		if ((ma1 <= maLower && close0 <= maLower) ||
		    (bYokoYoko && hi0 < maLower) || (!bYokoYoko && upper0 < maLower)) {
		    
		    sigShort = ma1 + ofst;
		}
	    }
	}
	BufferSignalLong[i] = sigLong;
	BufferSignalShort[i] = sigShort;
    }
}
