//
// "00-HighLowBand_v100.mq4" -- High-Low Band
//
//    Ver. 1.00  2009/01/02(Fri)  initial version
//
//
#property  copyright  "00 - 00mql4@gmail.com"
#property  link       "http://www.mql4.com/"

//---- defines
#define DodgerBlue2  0xaa6014
#define Crimson2     0x280d93

//---- indicator settings
#property  indicator_chart_window

#property  indicator_buffers 7

#property  indicator_color1  LightSkyBlue    // 0: High
#property  indicator_color2  LightSteelBlue  // 1: Center
#property  indicator_color3  LightSkyBlue    // 2: Low
#property  indicator_color4  DodgerBlue      // 3: High break signal, Long
#property  indicator_color5  Crimson         // 4: Low break signal, Short
#property  indicator_color6  DodgerBlue2     // 5: Center cross signal, Long
#property  indicator_color7  Crimson2        // 6: Center cross signal, Short

#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_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

//---- defines

//---- input parameters
extern int    timeFrame    = 0;     // time frame
extern int    nPeriod      = 20;    // period
extern int    shiftHiLo    = 1;     // number of bars to shift High-Low Band
extern int    shiftCenter  = 0;     // number of bars to shift Center line
extern bool   bAlertBreak  = true;  // alert on cross middle line
extern bool   bAlertCross  = true;  // alert on cross middle line
extern int    nMaxBars     = 2000;  // maximum number of bars to calculate, 0: no limit

//---- buffers
double BufferHigh[];              // 0: High
double BufferCenter[];            // 1: Center
double BufferLow[];               // 2: Low
double BufferHighBreakLong[];     // 3: High break signal, Long
double BufferLowBreakShort[];     // 4: Low break signal, Short
double BufferCenterCrossLong[];   // 5: Center cross signal, Long
double BufferCenterCrossShort[];  // 6: Center cross signal, Short

//---- vars
string   sIndicatorName = "";
string   sPrefix        = "";
string   sIndSelf       = "00-HighLowBand_v100";
int      markLong       = 233;
int      markShort      = 234;
datetime tAlertLast     = 0;

//----------------------------------------------------------------------
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()
{
    if (timeFrame == 0) {
	timeFrame = Period();
    }
    
    string tf = TimeFrameToStr(timeFrame);
    sIndicatorName = sIndSelf + "(" + tf + "," + nPeriod + ")";
    sPrefix = sIndicatorName;
    
    IndicatorShortName(sIndicatorName);
    
    SetIndexBuffer(0, BufferHigh);
    SetIndexBuffer(1, BufferCenter);
    SetIndexBuffer(2, BufferLow);
    SetIndexBuffer(3, BufferHighBreakLong);
    SetIndexBuffer(4, BufferLowBreakShort);
    SetIndexBuffer(5, BufferCenterCrossLong);
    SetIndexBuffer(6, BufferCenterCrossShort);
    
    SetIndexLabel(0, "High");
    SetIndexLabel(1, "Center");
    SetIndexLabel(2, "Low");
    SetIndexLabel(3, "High break, Long signal");
    SetIndexLabel(4, "Low break, Short signal");
    SetIndexLabel(5, "Center cross, Long signal");
    SetIndexLabel(6, "Center cross, Short signal");
    
    SetIndexStyle(0, DRAW_LINE);
    SetIndexStyle(1, DRAW_LINE);
    SetIndexStyle(2, DRAW_LINE);
    SetIndexStyle(3, DRAW_ARROW);
    SetIndexStyle(4, DRAW_ARROW);
    SetIndexStyle(5, DRAW_ARROW);
    SetIndexStyle(6, DRAW_ARROW);
    
    SetIndexArrow(3, markLong);
    SetIndexArrow(4, markShort);
    SetIndexArrow(5, markLong);
    SetIndexArrow(6, markShort);
    
    int n = nPeriod;
    if (nMaxBars > 0) {
	n += Bars - MathMin(Bars, nMaxBars);
    }
    
    SetIndexDrawBegin(0, n);
    SetIndexDrawBegin(1, n);
    SetIndexDrawBegin(2, n);
    SetIndexDrawBegin(3, n);
    SetIndexDrawBegin(4, n);
    SetIndexDrawBegin(5, n);
    SetIndexDrawBegin(6, n);
}

//----------------------------------------------------------------------
void start()
{
    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 (int i = limit0 - 1; i >= limit; i--) {
	BufferHigh[i]             = EMPTY_VALUE;
	BufferCenter[i]           = EMPTY_VALUE;
	BufferLow[i]              = EMPTY_VALUE;
	BufferHighBreakLong[i]    = EMPTY_VALUE;
	BufferLowBreakShort[i]    = EMPTY_VALUE;
	BufferCenterCrossLong[i]  = EMPTY_VALUE;
	BufferCenterCrossShort[i] = EMPTY_VALUE;
    }
    
    if (timeFrame != Period()) {
	// MTF
	int scale = timeFrame / Period();
	limit = MathMax(limit, scale);
	for (i = limit - 1; i >= 0; i--) {
	    int x = iBarShift(NULL, timeFrame, Time[i]);
	    BufferHigh[i]             = iCustom(NULL, timeFrame, sIndSelf, 0, nPeriod, shiftHiLo, shiftCenter, bAlertBreak, bAlertCross, nMaxBars, 0, x);
	    BufferCenter[i]           = iCustom(NULL, timeFrame, sIndSelf, 0, nPeriod, shiftHiLo, shiftCenter, bAlertBreak, bAlertCross, nMaxBars, 1, x);
	    BufferLow[i]              = iCustom(NULL, timeFrame, sIndSelf, 0, nPeriod, shiftHiLo, shiftCenter, bAlertBreak, bAlertCross, nMaxBars, 2, x);
	    BufferHighBreakLong[i]    = iCustom(NULL, timeFrame, sIndSelf, 0, nPeriod, shiftHiLo, shiftCenter, bAlertBreak, bAlertCross, nMaxBars, 3, x);
	    BufferLowBreakShort[i]    = iCustom(NULL, timeFrame, sIndSelf, 0, nPeriod, shiftHiLo, shiftCenter, bAlertBreak, bAlertCross, nMaxBars, 4, x);
	    BufferCenterCrossLong[i]  = iCustom(NULL, timeFrame, sIndSelf, 0, nPeriod, shiftHiLo, shiftCenter, bAlertBreak, bAlertCross, nMaxBars, 5, x);
	    BufferCenterCrossShort[i] = iCustom(NULL, timeFrame, sIndSelf, 0, nPeriod, shiftHiLo, shiftCenter, bAlertBreak, bAlertCross, nMaxBars, 6, x);
	}
	
	// check alert
	if (bAlertBreak || bAlertCross) {
	    bool bFire = ((bAlertBreak && (BufferHighBreakLong[0] != EMPTY_VALUE|| BufferLowBreakShort[0] != EMPTY_VALUE)) ||
			  (bAlertCross && (BufferCenterCrossLong[0] != EMPTY_VALUE|| BufferCenterCrossShort[0] != EMPTY_VALUE)));
	    if (bFire && tAlertLast != Time[0]) {
		PlaySound("alert.wav");
		tAlertLast = Time[0];
	    }
	}
	
	return;
    }
    
    // timeFrame == Period()
    for (i = limit - 1; i >= 0; i--) {
	// High-Low band
	BufferHigh[i] = High[iHighest(NULL, 0, MODE_HIGH, nPeriod, i + shiftHiLo)];
	BufferLow[i] = Low[iLowest(NULL, 0, MODE_LOW, nPeriod, i + shiftHiLo)];
	
	// Cetner line
	double hi = High[iHighest(NULL, 0, MODE_HIGH, nPeriod, i + shiftCenter)];
	double lo = Low[iLowest(NULL, 0, MODE_LOW, nPeriod, i + shiftCenter)];
	BufferCenter[i] = (hi + lo) * 0.5;
	
	// check High break
	if (High[i] > BufferHigh[i]) {
	    BufferHighBreakLong[i] = BufferHigh[i];
	}
	
	// check Low break
	if (Low[i] < BufferLow[i]) {
	    BufferLowBreakShort[i] = BufferLow[i];
	}
	
	// check Center cross
	double center2 = BufferCenter[i + 2];
	double center1 = BufferCenter[i + 1];
	double center0 = BufferCenter[i + 0];
	double c2 = Close[i + 2];
	double c1 = Close[i + 1];
	if (c2 < center2 && c1 >= center1) {
	    BufferCenterCrossLong[i] = center0;
	}
	if (c2 >= center2 && c1 < center1) {
	    BufferCenterCrossShort[i] = center0;
	}
    }
    
    // alert
    if (bAlertBreak || bAlertCross) {
	bFire = ((bAlertBreak && (BufferHighBreakLong[0] != EMPTY_VALUE|| BufferLowBreakShort[0] != EMPTY_VALUE)) ||
		 (bAlertCross && (BufferCenterCrossLong[0] != EMPTY_VALUE|| BufferCenterCrossShort[0] != EMPTY_VALUE)));
	if (bFire && tAlertLast != Time[0]) {
	    PlaySound("alert.wav");
	    tAlertLast = Time[0];
	}
    }
}
