//
// "00-MultiHeikinAshiSTF_v101.mq4" -- multi HeikinAshiSTF
//
//    Ver. 1.00  2008/11/15(Sat)  initial version
// 
// 
#property  copyright "00 - 00mql4@gmail.com"
#property  link      "http://www.mql4.com/"

//---- indicator settings
#property  indicator_separate_window

#property  indicator_buffers  8

#property  indicator_color1  DodgerBlue  // 0: long
#property  indicator_color2  Crimson     // 1: short
#property  indicator_color3  White       // 2: D1
#property  indicator_color4  Yellow      // 3: H4
#property  indicator_color5  Aqua        // 4: H1
#property  indicator_color6  Lime        // 5: M30
#property  indicator_color7  Orange      // 5: M15
#property  indicator_color8  Gold        // 5: M5

#property  indicator_width1  1
#property  indicator_width2  1
#property  indicator_width3  1
#property  indicator_width4  1
#property  indicator_width5  1
#property  indicator_width6  1
#property  indicator_width7  1
#property  indicator_width8  1

#property  indicator_level1  0

//---- defines
#define N_TF     6  // D1/H4/H1/M30/M15/M5
#define IDX_D1   5
#define IDX_H4   4
#define IDX_H1   3
#define IDX_M30  2
#define IDX_M15  1
#define IDX_M5   0

//---- indicator parameters
//
// HeikinAshi
extern string  sIndHeikinAshi    = "00-HeikinAshiSTF_v100";
extern int nMaxDays       = 10;
extern int nLongShortD1   = 0;
extern int nLongShortH4   = 0;
extern int nLongShortH1   = 1;
extern int nLongShortM30  = 1;
extern int nLongShortM15  = 1;
extern int nLongShortM5   = 1;
extern int nUpDownD1      = 0;
extern int nUpDownH4      = 0;
extern int nUpDownH1      = 0;
extern int nUpDownM30     = 0;
extern int nUpDownM15     = 1;
extern int nUpDownM5      = 1;

/*extern*/ color  colLong        = DodgerBlue;  // color for long lines
/*extern*/ color  colShort       = Crimson;     // color for short lines

//---- indicator buffers
double BufferLong[];   // 0: long signal
double BufferShort[];  // 1: short signal
double BufferD1[];     // 2: signal S/M/L, +/-1..+/-3
double BufferH4[];     // 3: signal S/M/L, +/-1..+/-3
double BufferH1[];     // 4: signal S/M/L, +/-1..+/-3
double BufferM30[];    // 5: signal S/M/L, +/-1..+/-3
double BufferM15[];    // 6: signal S/M/L, +/-1..+/-3
double BufferM5[];     // 7: signal S/M/L, +/-1..+/-3

//---- vars
string sIndicatorName;
string sPrefix;
int    markLong   = 233;
int    markShort  = 234;
int    nCheckLongShort[N_TF];    // 
int    nCheckUpDown[N_TF];    // 
int    nMaxHaCheck;
int    nMaxBars;
int    nMaxGroup[N_TF];   // maximum number of groups
int    nOffset[N_TF];     // maximum number of groups
double yOffset    = 0.0;  // y offset (pips)
int    nSkipD1    = 288;
int    nSkipH4    = 48;
int    nSkipH1    = 12;
int    nSkipM30   = 6;
int    nSkipM15   = 3;
int    nSkipM5    = 1;

//----------------------------------------------------------------------
void init()
{
    sIndicatorName = "00-MultiHeikinAshiSTF_v100";
    sPrefix = sIndicatorName;
    
    IndicatorShortName(sIndicatorName);
    
    SetIndexBuffer(0, BufferLong);
    SetIndexBuffer(1, BufferShort);
    SetIndexBuffer(2, BufferD1);
    SetIndexBuffer(3, BufferH4);
    SetIndexBuffer(4, BufferH1);
    SetIndexBuffer(5, BufferM30);
    SetIndexBuffer(6, BufferM15);
    SetIndexBuffer(7, BufferM5);
    
    SetIndexLabel(0, "Long signal");
    SetIndexLabel(1, "Short signal");
    SetIndexLabel(2, "D1");
    SetIndexLabel(3, "H4");
    SetIndexLabel(4, "H1");
    SetIndexLabel(5, "M30");
    SetIndexLabel(6, "M15");
    SetIndexLabel(7, "M5");
    
    SetIndexStyle(0, DRAW_ARROW);
    SetIndexStyle(1, DRAW_ARROW);
    SetIndexStyle(2, DRAW_LINE);
    SetIndexStyle(3, DRAW_LINE);
    SetIndexStyle(4, DRAW_LINE);
    SetIndexStyle(5, DRAW_LINE);
    SetIndexStyle(6, DRAW_LINE);
    SetIndexStyle(7, DRAW_LINE);
    
    SetIndexArrow(0, markLong);
    SetIndexArrow(1, markShort);
    
    SetIndexDrawBegin(0, 100);
    SetIndexDrawBegin(1, 100);
    SetIndexDrawBegin(2, 100);
    SetIndexDrawBegin(3, 100);
    SetIndexDrawBegin(4, 100);
    SetIndexDrawBegin(5, 100);
    SetIndexDrawBegin(6, 100);
    SetIndexDrawBegin(7, 100);
    
    nCheckLongShort[IDX_D1]  = nLongShortD1;
    nCheckLongShort[IDX_H4]  = nLongShortH4;
    nCheckLongShort[IDX_H1]  = nLongShortH1;
    nCheckLongShort[IDX_M30] = nLongShortM30;
    nCheckLongShort[IDX_M15] = nLongShortM15;
    nCheckLongShort[IDX_M5]  = nLongShortM5;
    
    nCheckUpDown[IDX_D1]  = nUpDownD1;
    nCheckUpDown[IDX_H4]  = nUpDownH4;
    nCheckUpDown[IDX_H1]  = nUpDownH1;
    nCheckUpDown[IDX_M30] = nUpDownM30;
    nCheckUpDown[IDX_M15] = nUpDownM15;
    nCheckUpDown[IDX_M5]  = nUpDownM5;
    
    nMaxHaCheck = MathMax(nLongShortD1,
			  MathMax(nLongShortH4,
				  MathMax(nLongShortH1,
					  MathMax(nLongShortM30,
						  MathMax(nLongShortM15, nLongShortM5)))));
    nMaxHaCheck = MathMax(nMaxHaCheck,
			  MathMax(nUpDownD1,
				  MathMax(nUpDownH4,
					  MathMax(nUpDownH1,
						  MathMax(nUpDownM30,
							  MathMax(nUpDownM15, nUpDownM5))))));
    
    if (nMaxDays == 0) {
	nMaxBars = MathMax(MathMax(nLongShortD1, nUpDownD1) * nSkipD1,
			   MathMax(MathMax(nLongShortH4, nUpDownH4) * nSkipH4,
				   MathMax(MathMax(nLongShortH1, nUpDownH1) * nSkipH1,
					   MathMax(MathMax(nLongShortM30, nUpDownM30) * nSkipM30,
						   MathMax(MathMax(nLongShortM15, nUpDownM15) * nSkipM15,
							   MathMax(nLongShortM5, nUpDownM5) * nSkipM5)))));
	
	nMaxGroup[IDX_D1]  = MathMax(MathMax(nCheckLongShort[IDX_D1], nCheckUpDown[IDX_D1]),  12);
	nMaxGroup[IDX_H4]  = MathMax(MathMax(nCheckLongShort[IDX_H4], nCheckUpDown[IDX_H4]),  12);
	nMaxGroup[IDX_H1]  = MathMax(MathMax(nCheckLongShort[IDX_H1], nCheckUpDown[IDX_H1]),  12);
	nMaxGroup[IDX_M30] = MathMax(MathMax(nCheckLongShort[IDX_M30], nCheckUpDown[IDX_M30]), 12);
	nMaxGroup[IDX_M15] = MathMax(MathMax(nCheckLongShort[IDX_M15], nCheckUpDown[IDX_M15]), 12);
	nMaxGroup[IDX_M5]  = MathMax(MathMax(nCheckLongShort[IDX_M5], nCheckUpDown[IDX_M5]),  12);
    } else {
	nMaxBars = nMaxDays * 24 * 12;
	nMaxGroup[IDX_D1]  = MathMax(MathMax(nCheckLongShort[IDX_D1],  nCheckUpDown[IDX_D1]),  MathMax(nMaxDays * 1,       12));
	nMaxGroup[IDX_H4]  = MathMax(MathMax(nCheckLongShort[IDX_H4],  nCheckUpDown[IDX_H4]),  MathMax(nMaxDays * 6,       12));
	nMaxGroup[IDX_H1]  = MathMax(MathMax(nCheckLongShort[IDX_H1],  nCheckUpDown[IDX_H1]),  MathMax(nMaxDays * 24,      12));
	nMaxGroup[IDX_M30] = MathMax(MathMax(nCheckLongShort[IDX_M30], nCheckUpDown[IDX_M30]), MathMax(nMaxDays * 24 * 2,  12));
	nMaxGroup[IDX_M15] = MathMax(MathMax(nCheckLongShort[IDX_M15], nCheckUpDown[IDX_M15]), MathMax(nMaxDays * 24 * 4,  12));
	nMaxGroup[IDX_M5]  = MathMax(MathMax(nCheckLongShort[IDX_M5],  nCheckUpDown[IDX_M5]),  MathMax(nMaxDays * 24 * 12, 12));
    }
    
    nOffset[IDX_M5]  = 1;
    nOffset[IDX_M15] = nOffset[IDX_M5]  * 3;
    nOffset[IDX_M30] = nOffset[IDX_M15] * 2;
    nOffset[IDX_H1]  = nOffset[IDX_M30] * 2;
    nOffset[IDX_H4]  = nOffset[IDX_H1]  * 4;
    nOffset[IDX_D1]  = nOffset[IDX_H4]  * 6;
}

//----------------------------------------------------------------------
double MathSign(double x)
{
    if (x < 0) {
	return(-1);
    }
    if (x > 0) {
	return(1);
    }
    
    return(0);
}

//----------------------------------------------------------------------
void start()
{
    int i, tf, n, c, s;
    int limit;
    int counted_bars = IndicatorCounted();
    
    if (counted_bars > 0) {
	counted_bars--;
    }
    
    limit = Bars - counted_bars;
    int limit0 = limit;
    limit = MathMin(limit, nMaxBars);
    
    for (i = limit0 - 1; i >= limit; i--) {
	BufferLong[i]  = EMPTY_VALUE;
	BufferShort[i] = EMPTY_VALUE;
    }
    
    double haDir[][N_TF];
    ArrayResize(haDir, nMaxHaCheck + 1);
    
    for (i = limit - 1; i >= 0; i--) {

	BufferLong[i]  = EMPTY_VALUE;
	BufferShort[i] = EMPTY_VALUE;
	
	BufferD1[i]  = iCustom(NULL, 0, sIndHeikinAshi, nOffset[IDX_D1],  nMaxGroup[IDX_D1],  yOffset, 4, i);
	BufferH4[i]  = iCustom(NULL, 0, sIndHeikinAshi, nOffset[IDX_H4],  nMaxGroup[IDX_H4],  yOffset, 4, i);
	BufferH1[i]  = iCustom(NULL, 0, sIndHeikinAshi, nOffset[IDX_H1],  nMaxGroup[IDX_H1],  yOffset, 4, i);
	BufferM30[i] = iCustom(NULL, 0, sIndHeikinAshi, nOffset[IDX_M30], nMaxGroup[IDX_M30], yOffset, 4, i);
	BufferM15[i] = iCustom(NULL, 0, sIndHeikinAshi, nOffset[IDX_M15], nMaxGroup[IDX_M15], yOffset, 4, i);
	BufferM5[i]  = iCustom(NULL, 0, sIndHeikinAshi, nOffset[IDX_M5],  nMaxGroup[IDX_M5],  yOffset, 4, i);
	
	// check Ha up/down
	{
	    int nHaUp   = 0;
	    int nHaDown = 0;
	    bool bHaUp[N_TF];
	    bool bHaDown[N_TF];
	    
	    for (tf = 0; tf < N_TF; tf++) {
		bHaUp[tf] = true;
		bHaDown[tf] = true;
	    }
	
	    // D1 up
	    tf = IDX_D1;
	    c = MathAbs(nCheckUpDown[tf]);
	    s = MathSign(nCheckUpDown[tf]);
	    if (c > 0) {
		for (n = 0; n < c; n++) {
		    if (BufferD1[i + n * nSkipD1 + 1] < s * BufferD1[i + (n + 1) * nSkipD1 + 1]) {
			bHaUp[tf] = false;
			break;
		    }
		}
	    }
	
	    // H4 up
	    tf = IDX_H4;
	    c = MathAbs(nCheckUpDown[tf]);
	    s = MathSign(nCheckUpDown[tf]);
	    for (n = 0; n < c; n++) {
		if (BufferH4[i + n * nSkipH4 + 1] < s * BufferH4[i + (n + 1) * nSkipH4 + 1]) {
		    bHaUp[tf] = false;
		    break;
		}
	    }
	
	    // H1 up
	    tf = IDX_H1;
	    c = MathAbs(nCheckUpDown[tf]);
	    s = MathSign(nCheckUpDown[tf]);
	    for (n = 0; n < c; n++) {
		if (BufferH1[i + n * nSkipH1 + 1] < s * BufferH1[i + (n + 1) * nSkipH1 + 1]) {
		    bHaUp[tf] = false;
		    break;
		}
	    }
	
	    // M30 up
	    tf = IDX_M30;
	    c = MathAbs(nCheckUpDown[tf]);
	    s = MathSign(nCheckUpDown[tf]);
	    for (n = 0; n < c; n++) {
		if (BufferM30[i + n * nSkipM30 + 1] < s * BufferM30[i + (n + 1) * nSkipM30 + 1]) {
		    bHaUp[tf] = false;
		    break;
		}
	    }
	
	    // M15 up
	    tf = IDX_M15;
	    c = MathAbs(nCheckUpDown[tf]);
	    s = MathSign(nCheckUpDown[tf]);
	    for (n = 0; n < c; n++) {
		if (BufferM15[i + n * nSkipM15 + 1] < s * BufferM15[i + (n + 1) * nSkipM15 + 1]) {
		    bHaUp[tf] = false;
		    break;
		}
	    }
	
	    // M5 up
	    tf = IDX_M5;
	    c = MathAbs(nCheckUpDown[tf]);
	    s = MathSign(nCheckUpDown[tf]);
	    for (n = 0; n < c; n++) {
		if (BufferM5[i + n * nSkipM5 + 1] < s * BufferM5[i + (n + 1) * nSkipM5 + 1]) {
		    bHaUp[tf] = false;
		    break;
		}
	    }
	
	    // D1 down
	    tf = IDX_D1;
	    c = MathAbs(nCheckUpDown[tf]);
	    s = MathSign(nCheckUpDown[tf]);
	    for (n = 0; n < c; n++) {
		if (BufferD1[i + n * nSkipD1 + 1] >= s * BufferD1[i + (n + 1) * nSkipD1 + 1]) {
		    bHaDown[tf] = false;
		    break;
		}
	    }
	
	    // H4 down
	    tf = IDX_H4;
	    c = MathAbs(nCheckUpDown[tf]);
	    s = MathSign(nCheckUpDown[tf]);
	    for (n = 0; n < c; n++) {
		if (BufferH4[i + n * nSkipH4 + 1] >= s * BufferH4[i + (n + 1) * nSkipH4 + 1]) {
		    bHaDown[tf] = false;
		    break;
		}
	    }
	
	    // H1 down
	    tf = IDX_H1;
	    c = MathAbs(nCheckUpDown[tf]);
	    s = MathSign(nCheckUpDown[tf]);
	    for (n = 0; n < c; n++) {
		if (BufferH1[i + n * nSkipH1 + 1] >= s * BufferH1[i + (n + 1) * nSkipH1 + 1]) {
		    bHaDown[tf] = false;
		    break;
		}
	    }
	
	    // M30 down
	    tf = IDX_M30;
	    c = MathAbs(nCheckUpDown[tf]);
	    s = MathSign(nCheckUpDown[tf]);
	    for (n = 0; n < c; n++) {
		if (BufferM30[i + n * nSkipM30 + 1] >= s * BufferM30[i + (n + 1) * nSkipM30 + 1]) {
		    bHaDown[tf] = false;
		    break;
		}
	    }
	
	    // M15 down
	    tf = IDX_M15;
	    c = MathAbs(nCheckUpDown[tf]);
	    s = MathSign(nCheckUpDown[tf]);
	    for (n = 0; n < c; n++) {
		if (BufferM15[i + n * nSkipM15 + 1] >= s *  BufferM15[i + (n + 1) * nSkipM15 + 1]) {
		    bHaDown[tf] = false;
		    break;
		}
	    }
	
	    // M5 down
	    tf = IDX_M5;
	    c = MathAbs(nCheckUpDown[tf]);
	    s = MathSign(nCheckUpDown[tf]);
	    for (n = 0; n < c; n++) {
		if (BufferM5[i + n * nSkipM5 + 1] >= s * BufferM5[i + (n + 1) * nSkipM5 + 1]) {
		    bHaDown[tf] = false;
		    break;
		}
	    }
	
	    for (tf = 0; tf < N_TF; tf++) {	
		if (bHaUp[tf]) {
		    nHaUp++;
		}
		if (bHaDown[tf]) {
		    nHaDown++;
		}
	    }
	}
	
	// check Ha long/short
	{
	    int nHaLong   = 0;
	    int nHaShort = 0;
	    bool bHaLong[N_TF];
	    bool bHaShort[N_TF];
	    
	    for (tf = 0; tf < N_TF; tf++) {
		bHaLong[tf] = true;
		bHaShort[tf] = true;
	    }
	    
	    // D1 long
	    tf = IDX_D1;
	    c = MathAbs(nCheckLongShort[tf]);
	    s = MathSign(nCheckLongShort[tf]);
	    for (n = 0; n < c; n++) {
		if (BufferD1[i + n * nSkipD1 + 1] * s < 0) {
		    bHaLong[tf] = false;
		    break;
		}
	    }
	
	    // H4 long
	    tf = IDX_H4;
	    c = MathAbs(nCheckLongShort[tf]);
	    s = MathSign(nCheckLongShort[tf]);
	    for (n = 0; n < nCheckLongShort[tf]; n++) {
		if (BufferH4[i + n * nSkipH4 + 1] * s < 0) {
		    bHaLong[tf] = false;
		    break;
		}
	    }
	
	    // H1 long
	    tf = IDX_H1;
	    c = MathAbs(nCheckLongShort[tf]);
	    s = MathSign(nCheckLongShort[tf]);
	    for (n = 0; n < nCheckLongShort[tf]; n++) {
		if (BufferH1[i + n * nSkipH1 + 1] * s < 0) {
		    bHaLong[tf] = false;
		    break;
		}
	    }
	
	    // M30 long
	    tf = IDX_M30;
	    c = MathAbs(nCheckLongShort[tf]);
	    s = MathSign(nCheckLongShort[tf]);
	    for (n = 0; n < nCheckLongShort[tf]; n++) {
		if (BufferM30[i + n * nSkipM30 + 1] * s < 0) {
		    bHaLong[tf] = false;
		    break;
		}
	    }
	
	    // M15 long
	    tf = IDX_M15;
	    c = MathAbs(nCheckLongShort[tf]);
	    s = MathSign(nCheckLongShort[tf]);
	    for (n = 0; n < nCheckLongShort[tf]; n++) {
		if (BufferM15[i + n * nSkipM15 + 1] * s < 0) {
		    bHaLong[tf] = false;
		    break;
		}
	    }
	
	    // M5 long
	    tf = IDX_M5;
	    c = MathAbs(nCheckLongShort[tf]);
	    s = MathSign(nCheckLongShort[tf]);
	    for (n = 0; n < nCheckLongShort[tf]; n++) {
		if (BufferM5[i + n * nSkipM5 + 1] * s < 0) {
		    bHaLong[tf] = false;
		    break;
		}
	    }
	
	    // D1 short
	    tf = IDX_D1;
	    c = MathAbs(nCheckLongShort[tf]);
	    s = MathSign(nCheckLongShort[tf]);
	    for (n = 0; n < nCheckLongShort[tf]; n++) {
		if (BufferD1[i + n * nSkipD1 + 1] * s >= 0) {
		    bHaShort[tf] = false;
		    break;
		}
	    }
	
	    // H4 short
	    tf = IDX_H4;
	    c = MathAbs(nCheckLongShort[tf]);
	    s = MathSign(nCheckLongShort[tf]);
	    for (n = 0; n < nCheckLongShort[tf]; n++) {
		if (BufferH4[i + n * nSkipH4 + 1] * s >= 0) {
		    bHaShort[tf] = false;
		    break;
		}
	    }
	
	    // H1 short
	    tf = IDX_H1;
	    c = MathAbs(nCheckLongShort[tf]);
	    s = MathSign(nCheckLongShort[tf]);
	    for (n = 0; n < nCheckLongShort[tf]; n++) {
		if (BufferH1[i + n * nSkipH1 + 1] * s >= 0) {
		    bHaShort[tf] = false;
		    break;
		}
	    }
	
	    // M30 short
	    tf = IDX_M30;
	    c = MathAbs(nCheckLongShort[tf]);
	    s = MathSign(nCheckLongShort[tf]);
	    for (n = 0; n < nCheckLongShort[tf]; n++) {
		if (BufferM30[i + n * nSkipM30 + 1] * s >= 0) {
		    bHaShort[tf] = false;
		    break;
		}
	    }
	
	    // M15 short
	    tf = IDX_M15;
	    c = MathAbs(nCheckLongShort[tf]);
	    s = MathSign(nCheckLongShort[tf]);
	    for (n = 0; n < nCheckLongShort[tf]; n++) {
		if (BufferM15[i + n * nSkipM15 + 1] * s >= 0) {
		    bHaShort[tf] = false;
		    break;
		}
	    }
	
	    // M5 short
	    tf = IDX_M5;
	    c = MathAbs(nCheckLongShort[tf]);
	    s = MathSign(nCheckLongShort[tf]);
	    for (n = 0; n < nCheckLongShort[tf]; n++) {
		if (BufferM5[i + n * nSkipM5 + 1] * s >= 0) {
		    bHaShort[tf] = false;
		    break;
		}
	    }
	
	    for (tf = 0; tf < N_TF; tf++) {	
		if (bHaLong[tf]) {
		    nHaLong++;
		}
		if (bHaShort[tf]) {
		    nHaShort++;
		}
	    }
	}
	
	bool bUp = true;
	bool bDown = true;
	for (tf = 0; tf < N_TF; tf++) {
	    if (!bHaUp[tf]) {
		bUp = false;
		break;
	    }
	}
	for (tf = 0; tf < N_TF; tf++) {
	    if (!bHaDown[tf]) {
		bDown = false;
		break;
	    }
	}
	
	bool bLong = true;
	bool bShort = true;
	for (tf = 0; tf < N_TF; tf++) {
	    if (!bHaLong[tf]) {
		bLong = false;
		break;
	    }
	}
	for (tf = 0; tf < N_TF; tf++) {
	    if (!bHaShort[tf]) {
		bShort = false;
		break;
	    }
	}
	
	if (bLong && bUp) {
	    BufferLong[i] = -1;
	}
	if (bShort && bDown) {
	    BufferShort[i] = 1;
	}
    }
}
