//
// "00-LineMan_v103.mq4" -- LineMan
//
//    Ver. 1.00  2009/01/29(Thu)  initial version
//    Ver. 1.01  2009/01/29(Thu)  modified to alert only line/price crosses
//    Ver. 1.02  2009/02/02(Mon)  bugfixed: clear old signals on symbol change
//               2009/02/08(Sun)  modified to apply iFractal() manner for nBefore/nAfter=2
//    Ver. 1.03  2009/02/09(Mon)  added bShowTarget, target price on margin line
//
//
#property  copyright "00"
#property  link      "http://www.mql4.com/"

#include <stdlib.mqh>

//---- defines
#define DodgerBlue2  C'0x0d,0x28,0x93'
#define Crimson2     C'0xaa,0x14,0x60'

//---- indicator settings
#property  indicator_chart_window

#property  indicator_buffers  8

#property  indicator_color1  Gray
#property  indicator_color2  Gray
#property  indicator_color3  DimGray
#property  indicator_color4  DimGray
#property  indicator_color5  DarkGray
#property  indicator_color6  DarkGray
#property  indicator_color7  DodgerBlue
#property  indicator_color8  Crimson

#property  indicator_width1  1
#property  indicator_width2  1
#property  indicator_width3  2
#property  indicator_width4  2
#property  indicator_width5  3
#property  indicator_width6  3
#property  indicator_width7  1
#property  indicator_width8  1

//---- indicator parameters
extern bool   bDispShort      = true;           // short period LineMan
extern bool   bDispMid        = false;          // mid period  LineMan
extern bool   bDispLong       = false;          // long period LineMan
extern bool   bAlertDialog    = true;           // show dialog on signal occur
extern bool   bAlertSound     = true;           // play sound on signal occur
extern bool   bDispTarget     = true;           // target price of current and next bars
extern string sWavAlert       = "alert.wav";    // alert sound file name
extern int    nShortBefore    = 2;              // short, number of check bars before peaks
extern int    nShortAfter     = 2;              // short, number of check bars after peaks 
extern int    nMidBefore      = 6;              // mid, number of check bars before peaks
extern int    nMidAfter       = 6;              // mid, number of check bars after peaks 
extern int    nLongBefore     = 24;             // long, number of check bars before peaks
extern int    nLongAfter      = 24;             // long, number of check bars after peaks 
extern double marginShort     = 2;              // short, margin pips
extern double marginMid       = 5;              // mid, margin pips
extern double marginLong      = 10;             // long, margin pips
extern double ppPerBar        = 1.0;            // minimum angles of valid LineMan in (pips/5min)
extern color  colLineUpper    = DodgerBlue;     // upper LineMan color
extern color  colLineLower    = Crimson;        // lower LineMan color
extern color  colMarginUpper  = DodgerBlue2;    // upper margin line color
extern color  colMarginLower  = Crimson2;       // lower margin line color
extern int    styleShort      = STYLE_SOLID;    // short, line style
extern int    styleMid        = STYLE_DASH;     // mid, line style
extern int    styleLong       = STYLE_DASHDOT;  // long, line style
extern int    pointScale      = 0;              // 0: auto, 1: 123.45, 10: 123.456
extern int    nMaxBars        = 2000;           // maximum number of bars to calculate, 0: no limit

//---- indicator buffers
double BufferShortUpper[];   // 0: short period, upper peak
double BufferShortLower[];   // 1: short period, lower peak
double BufferMidUpper[];     // 2: mid period, upper peak
double BufferMidLower[];     // 3: mid period, lower peak
double BufferLongUpper[];    // 4: long period, upper peak
double BufferLongLower[];    // 5: long period, lower peak
double BufferSignalLong[];   // 6: Long signal peak
double BufferSignalShort[];  // 7: Short signal peak

//---- vars
string   sIndicatorName;
string   sPrefix;
string   sIndSelf  = "00-LineMan_v103";
double   point;
int      markUpper = 217;
int      markLower = 218;
int      markLong  = 233;
int      markShort = 234;
datetime tAlertLast;

//----------------------------------------------------------------------
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("??");
}

//----------------------------------------------------------------------
double checkPoint(string sym, int pointScale)
{
    if (pointScale != 0) {
	// point manually scaled
	return(Point * pointScale);
    }
    
    // auto scale
    string   s_point001[] = {  // point=0.01 pairs, for auto pointScale(0), *JPY are 0.01 as default
	"EURHUF", "USDHUF"
    };
    string   s_point0001[] = {  // point=0.001 pairs, for auto pointScale(0)
	"EURCZK", "EURHKD", "EURSKK", "EURZAR", "GBPNOK",
	"GBPSEK", "GBPZAR", "USDCZK", "USDMXN", "USDRUB",
	"USDSKK"
    };
    double point = 0;
    
    if (StringFind(sym, "JPY") == 3) {
	point = 0.01;
    } else {
	// check point=0.01 table
	int n = ArraySize(s_point001);
	for (int i = 0; i < n; i++) {
	    if (StringFind(sym, s_point001[i]) == 0) {
		point = 0.01;
		break;
	    }
	}
	if (point == 0) {
	    // check point=0.001 table
	    n = ArraySize(s_point0001);
	    for (i = 0; i < n; i++) {
		if (StringFind(sym, s_point0001[i]) == 0) {
		    point = 0.001;
		    break;
		}
	    }
	}
	if (point == 0) {
	    // others
	    point = 0.0001;
	}
    }
    
    return(point);
}

//----------------------------------------------------------------------
void init()
{
    string tf = TimeFrameToStr(Period());
    sIndicatorName = sIndSelf + "(" + tf + ")";
    sPrefix = sIndicatorName;
    
    IndicatorShortName(sIndicatorName);
    
    SetIndexBuffer(0, BufferShortUpper);
    SetIndexBuffer(1, BufferShortLower);
    SetIndexBuffer(2, BufferMidUpper);
    SetIndexBuffer(3, BufferMidLower);
    SetIndexBuffer(4, BufferLongUpper);
    SetIndexBuffer(5, BufferLongLower);
    SetIndexBuffer(6, BufferSignalLong);
    SetIndexBuffer(7, BufferSignalShort);
    
    SetIndexLabel(0, "Short Upper");
    SetIndexLabel(1, "Short Lower");
    SetIndexLabel(2, "Mid Upper");
    SetIndexLabel(3, "Mid Lower");
    SetIndexLabel(4, "Long Upper");
    SetIndexLabel(5, "Long Lower");
    SetIndexLabel(6, "Signal Long");
    SetIndexLabel(7, "Signal Short");
    
    SetIndexStyle(0, DRAW_ARROW);
    SetIndexStyle(1, DRAW_ARROW);
    SetIndexStyle(2, DRAW_ARROW);
    SetIndexStyle(3, DRAW_ARROW);
    SetIndexStyle(4, DRAW_ARROW);
    SetIndexStyle(5, DRAW_ARROW);
    SetIndexStyle(6, DRAW_ARROW);
    SetIndexStyle(7, DRAW_ARROW);
    
    SetIndexArrow(0, markUpper);
    SetIndexArrow(1, markLower);
    SetIndexArrow(2, markUpper);
    SetIndexArrow(3, markLower);
    SetIndexArrow(4, markUpper);
    SetIndexArrow(5, markLower);
    SetIndexArrow(6, markLong);
    SetIndexArrow(7, markShort);
    
    SetIndexDrawBegin(0, nShortBefore);
    SetIndexDrawBegin(1, nShortBefore);
    SetIndexDrawBegin(2, nMidBefore);
    SetIndexDrawBegin(3, nMidBefore);
    SetIndexDrawBegin(4, nLongBefore);
    SetIndexDrawBegin(5, nLongBefore);
    SetIndexDrawBegin(6, nShortBefore);
    SetIndexDrawBegin(7, nShortBefore);
    
    // clear old signals
    int n = ArraySize(BufferShortUpper);
    for (int i = 0; i < n; i++) {
	BufferShortUpper[i]  = EMPTY_VALUE;
	BufferShortLower[i]  = EMPTY_VALUE;
	BufferMidUpper[i]    = EMPTY_VALUE;
	BufferMidLower[i]    = EMPTY_VALUE;
	BufferLongUpper[i]   = EMPTY_VALUE;
	BufferLongLower[i]   = EMPTY_VALUE;
	BufferSignalLong[i]  = EMPTY_VALUE;
	BufferSignalShort[i] = EMPTY_VALUE;
    }
    
    point = checkPoint(Symbol(), pointScale);
}

//----------------------------------------------------------------------
void deinit()
{
    int n = ObjectsTotal();
    for (int i = n - 1; i >= 0; i--) {
	string sName = ObjectName(i);
	if (StringFind(sName, sPrefix) == 0) {
	    ObjectDelete(sName);
	}
    }
}

//----------------------------------------------------------------------
void objLine(string sName, int win, datetime ts, double ps, datetime te, double pe, color col,
	     int width = 1, int style = STYLE_SOLID, bool bBack = false, bool bRay = false)
{
    sName = sPrefix + sName;
    
    ObjectCreate(sName, OBJ_TREND, win, 0, 0);
    ObjectSet(sName, OBJPROP_TIME1,  ts);
    ObjectSet(sName, OBJPROP_PRICE1, ps);
    ObjectSet(sName, OBJPROP_TIME2,  te);
    ObjectSet(sName, OBJPROP_PRICE2, pe);
    ObjectSet(sName, OBJPROP_COLOR,  col);
    ObjectSet(sName, OBJPROP_WIDTH,  width);
    ObjectSet(sName, OBJPROP_STYLE,  style);
    ObjectSet(sName, OBJPROP_BACK,   bBack);
    ObjectSet(sName, OBJPROP_RAY,    bRay);
}	    

//----------------------------------------------------------------------
void objText(string sName, int win, datetime t, double p, string text, color col, int fontSize = 10, string fontName = "Arial")
{
    sName = sPrefix + sName;
    
    ObjectCreate(sName, OBJ_TEXT, win, 0, 0);
    ObjectSetText(sName, text, fontSize, fontName, col);
    ObjectSet(sName, OBJPROP_TIME1, t);
    ObjectSet(sName, OBJPROP_PRICE1, p);
}

//----------------------------------------------------------------------
bool isUpperFractal2(int i)
{
    double hi0 = High[i];
    
    if (hi0 > High[i - 1] && hi0 > High[i - 2]) {
	if (hi0 > High[i + 1] && hi0 > High[i + 2]) {
	    return(true);
	}
	
	if (hi0 == High[i + 1] && hi0 > High[i + 2] && hi0 > High[i + 3]) {
	    return(true);
	}
	
	if(hi0 >= High[i + 1] && hi0 == High[i + 2]) {
	    if (hi0 > High[i + 3] && hi0 > High[i + 4]) {
		return(true);
	    }
	    
	    if (hi0 == High[i + 3] && hi0 >High[i + 4] && hi0 >High[i + 5]) {
		return(true);
	    }
	    
	    if (hi0 >= High[i + 3] && hi0 == High[i + 4] && hi0 > High[i + 5] && hi0 > High[i + 6]) {
		return(true);
	    }
	}
    }
    
    return(false);
}

//----------------------------------------------------------------------
bool isLowerFractal2(int i)
{
    double lo0 = Low[i];
    
    if (lo0 < Low[i - 1] && lo0 < Low[i - 2]) {
	if (lo0 < Low[i + 1] && lo0 < Low[i + 2]) {
	    return(true);
	}
	
	if (lo0 == Low[i + 1] && lo0 < Low[i + 2] && lo0 < Low[i + 3]) {
	    return(true);
	}
    
	if (lo0 <= Low[i + 1] && lo0 == Low[i + 2]) {
	    if (lo0 < Low[i + 3] && lo0 < Low[i + 4]) {
		return(true);
	    }
	
	    if (lo0 == Low[i + 3] && lo0 < Low[i + 4] && lo0 < Low[i + 5]) {
		return(true);
	    }
	    
	    if (lo0 <= Low[i + 3] && lo0 == Low[i + 4] && lo0 < Low[i + 5] && lo0 < Low[i + 6]) {
		return(true);
	    }
	}
    }
    
    return(false);
}

//----------------------------------------------------------------------
bool isUpperPeak(int i, int nBefore, int nAfter)
{
    if (nBefore == 2 && nAfter == 2) {
	// original iFractal()
	return(isUpperFractal2(i));
    }
    
    bool bPeak = true;
    
    double hi = High[i];
    for (int j = 1; j <= nBefore; j++) {
	int x = i + j;
	if (High[x] > hi) {
	    bPeak = false;
	    break;
	}
    }
    if (bPeak) {
	for (j = 1; j <= nAfter; j++) {
	    x = i - j;
	    if (x < 0 || High[x] >= hi) {
		bPeak = false;
		break;
	    }
	}
    }
    
    return(bPeak);
}

//----------------------------------------------------------------------
bool isLowerPeak(int i, int nBefore, int nAfter)
{
    if (nBefore == 2 && nAfter == 2) {
	// original iFractal()
	return(isLowerFractal2(i));
    }
    
    bool bPeak = true;
    
    double lo = Low[i];
    for (int j = 1; j <= nBefore; j++) {
	int x = i + j;
	if (Low[x] < lo) {
	    bPeak = false;
	    break;
	}
    }
    if (bPeak) {
	for (j = 1; j <= nAfter; j++) {
	    x = i - j;
	    if (x < 0 || Low[x] <= lo) {
		bPeak = false;
		break;
	    }
	}
    }
    
    return(bPeak);
}

//----------------------------------------------------------------------
void findPeak(int &i1, int &i2, double buffer[], int istart)
{
    i1 = EMPTY_VALUE;
    i2 = EMPTY_VALUE;
    
    for (int i = istart; i < nMaxBars; i++) {
	if (buffer[i] != EMPTY_VALUE) {
	    if (i2 == EMPTY_VALUE) {
		i2 = i;
	    } else if (i1 == EMPTY_VALUE) {
		i1 = i;
		break;
	    }
	}
    }
}

//----------------------------------------------------------------------
int getR(color col)
{
    return((col >> 0) & 0x0ff);
}

//----------------------------------------------------------------------
int getG(color col)
{
    return((col >> 8) & 0x0ff);
}

//----------------------------------------------------------------------
int getB(color col)
{
    return((col >> 16) & 0x0ff);
}

//----------------------------------------------------------------------
void darken(color &col, double c = 0.5)
{
    int r = getR(col) * c;
    int g = getG(col) * c;
    int b = getB(col) * c;
    
    col = RGB(r, g, b);
}

//----------------------------------------------------------------------
void lineMan(int idx, int limit, string sName, bool bDisp, bool bSignal, int nBefore, int nAfter,
	     double margin, double &BufferUpper[], double &BufferLower[], int w, int style)
{
    static datetime s_tsUpper[3], s_teUpper[3];
    static datetime s_tsLower[3], s_teLower[3];
    
    int iupper1 = EMPTY_VALUE;
    int iupper2 = EMPTY_VALUE;
    int ilower1 = EMPTY_VALUE;
    int ilower2 = EMPTY_VALUE;
    
    if (bDisp) {
	for (int i = MathMax(limit - 1, nAfter + 5); i >= nAfter; i--) {
	    double upper = EMPTY_VALUE;
	    double lower = EMPTY_VALUE;
	    
	    if (isUpperPeak(i, nBefore, nAfter)) {
		upper = High[i];
	    }
	    if (isLowerPeak(i, nBefore, nAfter)) {
		lower = Low[i];
	    }
	    
	    BufferUpper[i] = upper;
	    BufferLower[i] = lower;
	}
	findPeak(iupper1, iupper2, BufferUpper, nAfter);
	findPeak(ilower1, ilower2, BufferLower, nAfter);
    }
    
    if (iupper1 == EMPTY_VALUE || iupper2 == EMPTY_VALUE ||
	ilower1 == EMPTY_VALUE || ilower2 == EMPTY_VALUE) {
	// not found
	return;
    }
    
    datetime tsUpper = Time[iupper1];
    datetime teUpper = Time[iupper2];
    double   psUpper = High[iupper1];
    double   peUpper = High[iupper2];
    
    datetime tsLower = Time[ilower1];
    datetime teLower = Time[ilower2];
    double   psLower = Low[ilower1];
    double   peLower = Low[ilower2];
    
    if (iupper2 == EMPTY_VALUE) {
	psUpper = 0;
	peUpper = 0;
    }
    
    if (ilower2 == EMPTY_VALUE) {
	psLower = 0;
	peLower = 0;
    }
    
    bool bUpperChanged = (s_tsUpper[idx] != tsUpper || s_teUpper[idx] != teUpper);
    bool bLowerChanged = (s_tsLower[idx] != tsLower || s_teLower[idx] != teLower);
    s_tsUpper[idx] = tsUpper;
    s_teUpper[idx] = teUpper;
    s_tsLower[idx] = tsLower;
    s_teLower[idx] = teLower;
    
    datetime t1 = Time[1];
    datetime t0 = Time[0];
    datetime t00 = Time[0] + Period() * 60;
    
    double close1 = Close[1];
    double close0 = Close[0];
    
    double hi1 = High[1];
    double lo1 = Low[1];
    double psMargin, peMargin, psu, peu, psl, pel, psm, pem;
    double pm00, pm0, pm1;
    int ww;
    
    // upper
    {
	// line
	if (margin != 0.0) {
	    psMargin = psUpper + margin * point;
	    peMargin = peUpper + margin * point;
	    psu = psUpper;
	    peu = peUpper;
	    psm = psMargin;
	    pem = peMargin;
	} else {
	    psMargin = 0;
	    peMargin = 0;
	    psu = psUpper;
	    peu = peUpper;
	    psm = psu;
	    pem = peu;
	}
	color colMargin = colMarginUpper;
	color colLine = colLineUpper;
	ww = w;
	if (peu >= psu) {
	    ww = 1;
	    darken(colMargin);
	    darken(colLine);
	}
	objLine(sName + " upper margin", 0, tsUpper, psMargin, teUpper, peMargin, colMargin, 1, STYLE_DOT, true, true);
	objLine(sName + " upper",        0, tsUpper, psUpper,  teUpper, peUpper,  colLine,   ww, style,    true, true);
	
	// check signal, Long
	tsUpper = Time[0] - iupper1 * Period() * 60;
	teUpper = Time[0] - iupper2 * Period() * 60;
	double a = (peu - psu) / (teUpper - tsUpper);  // (pips/sec)
	pm1 = psm + a * (t1 - tsUpper);
	pm0 = psm + a * (t0 - tsUpper);
	pm00 = psm + a * (t00 - tsUpper);
	
	if (bSignal) {
	    bool bValid = (a * Period() * 60 <= -ppPerBar * point);
	    
	    if (bValid && bDispTarget) {
		double dtxLine = Period() * 60 * 2;
		double dtxText = Period() * 60 * 4;
		double dpyLine0  = (WindowPriceMax() - WindowPriceMin()) * 0.05;
		double dpyText0  = dpyLine0 + 3 * point;  // add offset
		double dpyLine00 = dpyLine0 / 2;
		double dpyText00 = dpyLine00 + 3 * point;  // add offset
		
		objLine(sName + " upline target0 a",  0, t0 + Period() * 60, pm0,            t0,           pm0,            colLineUpper);
		objLine(sName + " upline target0 b",  0, t0,                 pm0,            t0 + dtxLine, pm0 + dpyLine0, colLineUpper);
		objText(sName + " uptext target0",    0, t0 + dtxText,       pm0 + dpyText0, DoubleToStr(pm0, Digits), colLineUpper);
		
		objLine(sName + " upline target00 a", 0, t00 + Period() * 60, pm00,             t00,              pm00,             colLineUpper);
		objLine(sName + " upline target00 b", 0, t00,                 pm00,             t00 + dtxLine,    pm00 + dpyLine00, colLineUpper);
		objText(sName + " uptext target00",   0, t00 + dtxText,       pm00 + dpyText00, DoubleToStr(pm00, Digits), colLineUpper);
	    } else {
		objLine(sName + " upline target0 a", 0, 0, 0, 0, 0, Black);
		objLine(sName + " upline target0 b", 0, 0, 0, 0, 0, Black);
		objText(sName + " uptext target0",   0, 0, 0, 0, 0, Black);
		
		objLine(sName + " upline target00 a", 0, 0, 0, 0, 0, Black);
		objLine(sName + " upline target00 b", 0, 0, 0, 0, 0, Black);
		objText(sName + " uptext target00",   0, 0, 0, 0, 0, Black);
	    }
	    
	    if (bValid && ((close1 < pm1 || bUpperChanged) && close0 >= pm0)) {
		BufferSignalLong[0] = Low[0] - iATR(NULL, 0, 14, 0);
		if (t0 != tAlertLast) {
		    if (bAlertSound) {
			PlaySound(sWavAlert);
		    }
		    if (bAlertDialog) {
			Alert(Symbol() + ", Long signal, LineMan= ", peu, ", prev hi= ", High[iupper2], ", prev lo= ", Low[ilower2]);
		    }
		    tAlertLast = t0;
		}
	    } else {
		BufferSignalLong[0] = EMPTY_VALUE;
	    }
	}
    }
    
    // lower
    {
	// line
	if (margin != 0.0) {
	    psMargin = psLower - margin * point;
	    peMargin = peLower - margin * point;
	    psl = psLower;
	    pel = peLower;
	    psm = psMargin;
	    pem = peMargin;
	} else {
	    psMargin = 0;
	    peMargin = 0;
	    psl = psLower;
	    pel = peLower;
	    psm = psl;
	    pem = pel;
	}
	colMargin = colMarginLower;
	colLine = colLineLower;
	ww = w;
	if (pel <= psl) {
	    ww = 1;
	    darken(colMargin);
	    darken(colLine);
	}
	objLine(sName + " lower",        0, tsLower, psLower,  teLower, peLower,  colLine,   ww, style,     true, true);
	objLine(sName + " lower margin", 0, tsLower, psMargin, teLower, peMargin, colMargin, 1,  STYLE_DOT, true, true);
	
	// check signal, Short
	tsLower = Time[0] - ilower1 * Period() * 60;
	teLower = Time[0] - ilower2 * Period() * 60;
	a = (pel - psl) / (teLower - tsLower);  // (pips/sec)
	pm1 = psm + a * (t1 - tsLower);
	pm0 = psm + a * (t0 - tsLower);
	pm00 = psm + a * (t00 - tsLower);
	
	if (bSignal) {
	    bValid = (a * Period() * 60 >= ppPerBar * point);
	    
	    if (bValid && bDispTarget) {
		dtxLine = Period() * 60 * 5;
		dtxText = Period() * 60 * 7;
		dpyLine0  = (WindowPriceMax() - WindowPriceMin()) * 0.05;
		dpyText0  = dpyLine0; // no offset
		dpyLine00 = dpyLine0 / 2;
		dpyText00 = dpyLine00; // no offset
		
		objLine(sName + " loline target0 a", 0, t0 + Period() * 60, pm0,            t0,           pm0,            colLineLower);
		objLine(sName + " loline target0 b", 0, t0,                 pm0,            t0 + dtxLine, pm0 - dpyLine0, colLineLower);
		objText(sName + " lotext target0",   0, t0 + dtxText,       pm0 - dpyText0, DoubleToStr(pm0, Digits), colLineLower);
		
		objLine(sName + " loline target00 a", 0, t00 + Period() * 60, pm00,             t00,           pm00,             colLineLower);
		objLine(sName + " loline target00 b", 0, t00,                 pm00,             t00 + dtxLine, pm00 - dpyLine00, colLineLower);
		objText(sName + " lotext target00",   0, t00 + dtxText,       pm00 - dpyText00, DoubleToStr(pm00, Digits), colLineLower);
	    } else {
		objLine(sName + " loline target0 a", 0, 0, 0, 0, 0, Black);
		objLine(sName + " loline target0 b", 0, 0, 0, 0, 0, Black);
		objText(sName + " lotext target0",   0, 0, 0, 0, 0, Black);

		
		objLine(sName + " loline target00 a", 0, 0, 0, 0, 0, Black);
		objLine(sName + " loline target00 b", 0, 0, 0, 0, 0, Black);
		objText(sName + " lotext target00",   0, 0, 0, 0, 0, Black);
	    }
	    
	    if (bValid && ((close1 >= pm1 || bLowerChanged) && close0 < pm0)) {
		BufferSignalShort[0] = High[0] + iATR(NULL, 0, 14, 0);
		if (t0 != tAlertLast) {
		    if (bAlertSound) {
			PlaySound(sWavAlert);
		    }
		    if (bAlertDialog) {
			Alert(Symbol() + ", Short signal, LineMan= ", pel, ", prev hi= ", High[iupper2], ", prev lo= ", Low[ilower2]);
		    }
		    tAlertLast = t0;
		}
	    } else {
		BufferSignalShort[0] = EMPTY_VALUE;
	    }
	}
    }
}

//----------------------------------------------------------------------
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--) {
	BufferShortUpper[i]  = EMPTY_VALUE;
	BufferShortLower[i]  = EMPTY_VALUE;
	BufferMidUpper[i]    = EMPTY_VALUE;
	BufferMidLower[i]    = EMPTY_VALUE;
	BufferLongUpper[i]   = EMPTY_VALUE;
	BufferLongLower[i]   = EMPTY_VALUE;
	BufferSignalLong[i]  = EMPTY_VALUE;
	BufferSignalShort[i] = EMPTY_VALUE;
    }
    
    lineMan(0, limit, "short", bDispShort, true,  nShortBefore, nShortAfter, marginShort, BufferShortUpper, BufferShortLower, 3, styleShort);
    lineMan(1, limit, "mid",   bDispMid,   false, nMidBefore,   nMidAfter,   marginMid,   BufferMidUpper,   BufferMidLower,   1, styleMid);
    lineMan(2, limit, "long",  bDispLong,  false, nLongBefore,  nLongAfter,  marginLong,  BufferLongUpper,  BufferLongLower,  1, styleLong);
}
