//
// "00-TrendLine_v100.mq4" -- draw trend lines
//
//    Ver. 1.00  2008/12/26(Fri)  initial version
//    Ver. 1.01  2008/12/31(Wed)  added bWolfeWave, Wolfe wave
// 
//
#property  copyright  "00 - 00mql4@gmail.com"
#property  link       "http://www.mql4.com/"

//---- defines

//---- indicator settings
#property  indicator_chart_window

#property  indicator_buffers  6

#property  indicator_color1  Crimson     // 0: Upper line (support/resistance)
#property  indicator_color2  DodgerBlue  // 1: Lower line (support/resistance)
#property  indicator_color3  Magenta     // 2: Upper start (top peak)
#property  indicator_color4  Aqua        // 3: Lower start (bottom peak)
#property  indicator_color5  Silver      // 4: Upper large trend (Down trend)
#property  indicator_color6  Silver      // 5: Lower large trend (Up trend)

#property  indicator_width1  1
#property  indicator_width2  1
#property  indicator_width3  2
#property  indicator_width4  2
#property  indicator_width5  1
#property  indicator_width6  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

//---- indicator parameters
extern int     nBefore          = 6;           // number of bars before peak
extern int     nAfter           = 4;           // number of bars after peak
extern bool    bDrawLargeTrend  = true;        // draw large trend line (last 2 lines)
extern bool    bAlertLargeTrend = true;        // alert on large trend change
extern bool    bDrawFibo        = true;        // draw Fibonacci retracement levele
extern string  _help_fiboMode   = "0:range of last two large trends, 1:last only, 2:second from the last";
extern int     fiboMode         = 0;           // 0:last and second from the last, 1:last only, 2:second from the last
extern bool    bWolfeWave       = true;        // search Wolfe waves
extern int     nMaxWolfeWave    = 1;           // maximum number of Wolfe waves
extern color   colTrendSmall    = Aqua;        // color of small trend lines
extern color   colTrendLarge    = Gold;        // color of large trend lines
extern color   colWolfeLong     = DodgerBlue;  // color of Wolfe wave, bullish
extern color   colWolfeShort    = Crimson;     // color of Wolfe wave, bearish
extern int     wTrendSmall      = 2;           // width of small trend lines
extern int     wTrendLarge      = 3;           // width of large trend lines
extern int     wWolfe           = 1;           // width of Wolfe wave
extern color   colFiboLine      = DarkOrange;  // color of Fibonacci retracement stick line
extern color   colFiboLevel     = Gainsboro;   // color of Fibonacci retracement level lines
extern int     wFiboLine        = 1;           // width of Fibonacci retracement stick line
extern int     wFiboLevel       = 1;           // width of Fibonacci retracement level lines
extern int     styleFiboLine    = STYLE_DOT;   // style of Fibonacci retracement stick line
extern int     styleFiboLevel   = STYLE_DOT;   // style of Fibonacci retracement level lines
extern int     nMaxPeaks         = 50;          // maximum number of peaks
extern int     nMaxBars         = 2000;        // maximum number of bars to calculate, 0: no limit

//---- indicator buffers
double BufferUpperLine[];   // 0: Upper line (support/resistance)
double BufferLowerLine[];   // 1: Lower line (support/resistance)
double BufferUpperPeak[];   // 2: Upper start (top peak)
double BufferLowerPeak[];   // 3: Lower start (bottom peak)
double BufferDownTrend[];   // 4: Upper large trend (Down trend)
double BufferUpTrend[];     // 5: Lower large trend (Up trend)

//---- vars
string   sIndicatorName    = "";
string   sIndSelf          = "00-TrendLine_v100";
string   sPrefix           = "";
int      markPeak          = 159;
int      markLine          = 119;
int      markTrend         = 161;
int      IdxPeakUpper[];   // 0: newer
int      IdxPeakLower[];   // 0: newer
int      IdxTrendUpper[];  // 0: oldest
int      IdxTrendLower[];  // 0: oldest
string   sTrendUp          = " up ";
string   sTrendDown        = " down ";
string   sWolfeDownLower   = " Wolfe down lower ";
string   sWolfeDownTarget  = " Wolfe down target ";
string   sWolfeUpLower     = " Wolfe up lower ";
string   sWolfeUpTarget    = " Wolfe up target ";
datetime tup1Last          = 0;
datetime tdown1Last        = 0;
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()
{
    string tf = TimeFrameToStr(Period());
    sIndicatorName = sIndSelf + "(" + tf + "," + nBefore + "," + nAfter + ")";
    sPrefix = sIndicatorName;
    
    IndicatorShortName(sIndicatorName);
    
    SetIndexBuffer(0, BufferUpperLine);
    SetIndexBuffer(1, BufferLowerLine);
    SetIndexBuffer(2, BufferUpperPeak);
    SetIndexBuffer(3, BufferLowerPeak);
    SetIndexBuffer(4, BufferDownTrend);
    SetIndexBuffer(5, BufferUpTrend);
    
    SetIndexLabel(0, "Upper line");
    SetIndexLabel(1, "Lower line");
    SetIndexLabel(2, "Upper start");
    SetIndexLabel(3, "Lower start");
    SetIndexLabel(4, "Upper large trend (Down trend)");
    SetIndexLabel(5, "Lower large trend (Up trend)");
		  
    SetIndexStyle(0, DRAW_ARROW);
    SetIndexStyle(1, DRAW_ARROW);
    SetIndexStyle(2, DRAW_ARROW);
    SetIndexStyle(3, DRAW_ARROW);
    SetIndexStyle(4, DRAW_ARROW);
    SetIndexStyle(5, DRAW_ARROW);
    
    SetIndexArrow(0, markLine);
    SetIndexArrow(1, markLine);
    SetIndexArrow(2, markPeak);
    SetIndexArrow(3, markPeak);
    SetIndexArrow(4, markTrend);
    SetIndexArrow(5, markTrend);
    
    ArrayResize(IdxPeakUpper, nMaxPeaks);
    ArrayResize(IdxPeakLower, nMaxPeaks);
    ArrayResize(IdxTrendUpper, nMaxPeaks);
    ArrayResize(IdxTrendLower, nMaxPeaks);
}

//----------------------------------------------------------------------
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 = White,
	     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 objArrow(string sName, int win, datetime t, double p, int arrow, color col, int width = 1)
{
    sName = sPrefix + sName;
    
    ObjectCreate(sName, OBJ_ARROW, win, 0, 0);
    ObjectSet(sName, OBJPROP_TIME1,     t);
    ObjectSet(sName, OBJPROP_PRICE1,    p);
    ObjectSet(sName, OBJPROP_ARROWCODE, arrow);
    ObjectSet(sName, OBJPROP_COLOR,     col);
    ObjectSet(sName, OBJPROP_WIDTH,     width);
}

//----------------------------------------------------------------------
void objFibo(string sName, int win, datetime ts, double ps, datetime te, double pe,
	     color col, int width = 1, int style = STYLE_SOLID,
	     color levelCol = DimGray, int levelWidth = 1, int levelStyle = STYLE_DOT,
	     bool bBack = false, bool bRay = false)
{
    sName = sPrefix + sName;
    
    ObjectCreate(sName, OBJ_FIBO, 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);
    ObjectSet(sName, OBJPROP_LEVELWIDTH, levelWidth);
    ObjectSet(sName, OBJPROP_LEVELSTYLE, levelStyle);
    ObjectSet(sName, OBJPROP_LEVELCOLOR, levelCol);
}	    

//----------------------------------------------------------------------
datetime getUpperTime(int idxUpper)
{
    datetime t;
    
    if (idxUpper < 0) {
	t = Time[0];
    } else {
	t =Time[IdxPeakUpper[idxUpper]];
    }
    
    return(t);
}

//----------------------------------------------------------------------
datetime getLowerTime(int idxLower)
{
    datetime t;
    
    if (idxLower < 0) {
	t = Time[0];
    } else {
	t =Time[IdxPeakLower[idxLower]];
    }
    
    return(t);
}

//----------------------------------------------------------------------
double getUpperValue(int idxUpper)
{
    double v;
    
    if (idxUpper < 0) {
	v = High[0];
    } else {
	v = High[IdxPeakUpper[idxUpper]];
    }
    
    return(v);
}

//----------------------------------------------------------------------
double getLowerValue(int idxLower)
{
    double v;
    
    if (idxLower < 0) {
	v = Low[0];
    } else {
	v = Low[IdxPeakLower[idxLower]];
    }
    
    return(v);
}

//----------------------------------------------------------------------
void start()
{
    int limit;
    int counted_bars = IndicatorCounted();
    
    if (counted_bars > 0) {
	counted_bars--;
    }
    
    limit = Bars - counted_bars;
    for (int i = limit - 1; i >= 0; i--) {
	BufferUpperLine[i] = EMPTY_VALUE;
	BufferLowerLine[i] = EMPTY_VALUE;
	BufferUpperPeak[i] = EMPTY_VALUE;
	BufferLowerPeak[i] = EMPTY_VALUE;
	BufferDownTrend[i] = EMPTY_VALUE;
	BufferUpTrend[i]   = EMPTY_VALUE;
    }
    
    limit = MathMin(Bars, nMaxBars);
    
    int win = 0;
    int nPeakUpper = 0;
    int nPeakLower = 0;
    int nTrendUpper = 0;
    int nTrendLower = 0;
    
    // search upper/lower peaks
    {
	for (i = nAfter; i < limit; i++) {
	    // check top peak
	    double vTop = High[i];
	    bool bTop = true;
	    for (int j = -nAfter; j <= nBefore; j++) {
		if (High[i + j] > vTop) {
		    bTop = false;
		    break;
		}
	    }
	    if (bTop) {
		BufferUpperPeak[i] = vTop;
		IdxPeakUpper[nPeakUpper] = i;
		nPeakUpper++;
		if (nPeakUpper >= nMaxPeaks) {
		    break;
		}
	    }
	    
	    // check bottom peak
	    double vBot = Low[i];
	    bool bBot = true;
	    for (j = -nAfter; j < nBefore; j++) {
		if (Low[i + j] < vBot) {
		    bBot = false;
		    break;
		}
	    }
	    if (bBot) {
		BufferLowerPeak[i] = vBot;
		IdxPeakLower[nPeakLower] = i;
		nPeakLower++;
		if (nPeakLower >= nMaxPeaks) {
		    break;
		}
	    }
	}
    }
    
    // lower/upper lines (resistance/support)
    {
	// upper lines
	for (int idxStart = nPeakUpper - 1; idxStart >= 0; idxStart--) {
	    int idxEnd = idxStart - 1;
	    int barStart = IdxPeakUpper[idxStart];
	    int barEnd = 0;
	    if (idxEnd >= 0) {
		barEnd = IdxPeakUpper[idxEnd];
	    }
	    double v = High[barStart];
	    for (i = barStart; i >= barEnd; i--) {
		BufferUpperLine[i] = v;
	    }
	}
	
	// lower lines
	for (idxStart = nPeakLower - 1; idxStart >= 0; idxStart--) {
	    idxEnd = idxStart - 1;
	    barStart = IdxPeakLower[idxStart];
	    barEnd = 0;
	    if (idxEnd >= 0) {
		barEnd = IdxPeakLower[idxEnd];
	    }
	    v = Low[barStart];
	    for (i = barStart; i >= barEnd; i--) {
		BufferLowerLine[i] = v;
	    }
	}
    }
    
    if (nPeakUpper < 1 || nPeakLower < 1) {
	// no upper/lower peak
	return;
    }
    
    // trend lines (small)
    {
	int idxUpper = nPeakUpper - 1;
	int idxLower = nPeakLower - 1;
	datetime tLower, tUpper, tLowerNext, tUpperNext;
	
	// serch start lower
	for (; idxUpper >= 0; idxUpper--) {
	    if (getUpperTime(idxUpper) > getLowerTime(idxLower)) {
		break;
	    }
	}
	for (; idxLower >= 0; idxLower--) {
	    if (getLowerTime(idxLower) > getUpperTime(idxUpper)) {
		if (idxLower < nPeakLower - 1) {
		    idxLower++;
		}
		break;
	    }
	}
	
	nTrendUpper = 0;
	nTrendLower = 0;
	IdxTrendLower[nTrendLower] = idxLower;
	nTrendLower++;
	for (; ;) {
	    // trend line, lower to upper
	    tLower = getLowerTime(idxLower);
	    tLowerNext = getLowerTime(idxLower - 1);
	    tUpper = 0;
	    for (i = idxUpper; i >= -1; i--) {
		tUpper = getUpperTime(i);
		if (tUpper < tLower) {
		    continue;
		}
		if (tUpper >= tLowerNext) {
		    if (getUpperTime(i + 1) > tLower) {
			idxUpper = i + 1;
		    } else {
			idxUpper = i;
		    }
		    tUpper = getUpperTime(idxUpper);
		    break;
		}
	    }
	    IdxTrendUpper[nTrendUpper] = idxUpper;
	    objLine(sTrendUp + nTrendUpper, win, tLower, getLowerValue(idxLower),
		    tUpper, getUpperValue(idxUpper), colTrendSmall, wTrendSmall);
	    nTrendUpper++;
	    if (tUpper > Time[IdxPeakLower[0]]) {
		break;
	    }
	    
	    // trend line, upper to lower
	    tUpperNext = getUpperTime(idxUpper - 1);
	    tLower = 0;
	    for (i = idxLower - 1; i >= -1; i--) {
		tLower = getLowerTime(i);
		if (tLower < tUpper) {
		    continue;
		}
		if (tLower >= tUpperNext) {
		    if (getLowerTime(i + 1) > tUpper) {
			idxLower = i + 1;
		    } else {
			idxLower = i;
		    }
		    tLower = getLowerTime(idxLower);
		    break;
		}
	    }
	    IdxTrendLower[nTrendLower] = idxLower;
	    objLine(sTrendDown + nTrendLower, win, tUpper, getUpperValue(idxUpper),
		    tLower, getLowerValue(idxLower), colTrendSmall, wTrendSmall);
	    nTrendLower++;
	    if (tLower > Time[IdxPeakUpper[0]]) {
		break;
	    }
	}
	
	// clear unused
	for (i = nTrendUpper; i < nMaxPeaks; i++) {
	    objLine(sTrendUp + i, win, 0, 0, 0, 0);
	}
	for (i = nTrendLower; i < nMaxPeaks; i++) {
	    objLine(sTrendDown + i, win, 0, 0, 0, 0);
	}
    }
    
    // large trend lines
    if (bDrawLargeTrend || bDrawFibo) {
	datetime tup0, tup1, tdown0, tdown1;
	double vup0, vup1, vdown0, vdown1;
	
	// large up trend
	{
	    int iupTrend0 = -1;
	    int iupTrend1 = -1;
	
	    // skip down trend
	    for (i = nTrendUpper - 1; i >= 0; i--) {
		double v0 = getUpperValue(IdxTrendUpper[i]);
		double v1 = getUpperValue(IdxTrendUpper[i - 1]);
		if (v1 < v0 || i == 0) {
		    if (i < nTrendLower - 1 && getLowerValue(IdxTrendLower[i + 1]) >= getLowerValue(IdxTrendLower[i])) {
			iupTrend0 = i + 1;
		    } else {
			iupTrend0 = i;
		    }
		    break;
		}
	    }
	    // trace up trend
	    for (; i >= 0; i--) {
		v0 = getLowerValue(IdxTrendLower[i]);
		v1 = getLowerValue(IdxTrendLower[i - 1]);
		if (v1 > v0 || i == 0) {
		    iupTrend1 = i;
		    break;
		}
	    }
	    
	    tup0 = getLowerTime(IdxTrendLower[iupTrend0]);
	    vup0 = getLowerValue(IdxTrendLower[iupTrend0]);
	    tup1 = getLowerTime(IdxTrendLower[iupTrend1]);
	    vup1 = getLowerValue(IdxTrendLower[iupTrend1]);
	    
	    //objArrow(" largeUp0 " + iupTrend0, win, tup0, vup0, markPeak, White, wTrendLarge);
	    //objArrow(" largeUp1 " + iupTrend1, win, tup1, vup1, markPeak, White, wTrendLarge);
	    if (tup0 != tup1) {
		BufferUpTrend[IdxPeakLower[IdxTrendLower[iupTrend0]]] = vup0;
		BufferUpTrend[IdxPeakLower[IdxTrendLower[iupTrend1]]] = vup1;
	    }
	}
	
	// large down trend
	{
	    int idownTrend0 = -1;
	    int idownTrend1 = -1;
	    
	    // skip up trend
	    for (i = nTrendLower - 1; i >= 0; i--) {
		v0 = getLowerValue(IdxTrendLower[i]);
		v1 = getLowerValue(IdxTrendLower[i - 1]);
		if (v1 > v0 || i == 0) {
		    idownTrend0 = MathMin(i, nTrendUpper - 1);
		    break;
		}
	    }
	    // trace down trend
	    for (; i >= 0; i--) {
		v0 = getUpperValue(IdxTrendUpper[i]);
		v1 = getUpperValue(IdxTrendUpper[i - 1]);
		if (v1 < v0 || i == 0) {
		    idownTrend1 = i;
		    break;
		}
	    }
	    
	    tdown0 = getUpperTime(IdxTrendUpper[idownTrend0]);
	    vdown0 = getUpperValue(IdxTrendUpper[idownTrend0]);
	    tdown1 = getUpperTime(IdxTrendUpper[idownTrend1]);
	    vdown1 = getUpperValue(IdxTrendUpper[idownTrend1]);
	    
	    //objArrow(" largeDown0 " + idownTrend0, win, tdown0, vdown0, markPeak, White, wTrendLarge);
	    //objArrow(" largeDown1 " + idownTrend1, win, tdown1, vdown1, markPeak, White, wTrendLarge);
	    if (tdown0 != tdown1) {
		BufferDownTrend[IdxPeakUpper[IdxTrendUpper[idownTrend0]]] = vdown0;
		BufferDownTrend[IdxPeakUpper[IdxTrendUpper[idownTrend1]]] = vdown1;
	    }
	}
	
	// alert, check large trend change
	if (tup1 != tup1Last || tdown1 != tdown1Last) {
	    if (bAlertLargeTrend) {
		PlaySound("alert.wav");
		tAlertLast = Time[0];
	    }
	    tup1Last = tup1;
	    tdown1Last = tdown1;
	}
	
	if (bDrawLargeTrend) {
	    // large up trend line
	    int w;
	    if (tup0 >= tdown0) {
		w = wTrendLarge;
	    } else {
		w = 1;
	    }
	    objLine(" largeUp ", win, tup1, vup1, tup0, vup0, colTrendLarge, w, STYLE_SOLID, false, true);
	    
	    // large down trend line
	    if (tdown0 >= tup0) {
		w = wTrendLarge;
	    } else {
		w = 1;
	    }
	    objLine(" largeDown ", win, tdown1, vdown1, tdown0, vdown0, colTrendLarge, w, STYLE_SOLID, false, true);
	}
	
	if (bDrawFibo) {
	    int i0, i1;
	    
	    switch (fiboMode) {
		
	    case 1:  // last only
		i0 = 0;
		i1 = iBarShift(NULL, 0, MathMax(tup1, tdown1));
		break;
		
	    case 2:  // second from the last
		i0 = iBarShift(NULL, 0, MathMax(tup1, tdown1));
		i1 = iBarShift(NULL, 0, MathMin(tup1, tdown1));
		break;
		
	    case 0:  // last and second from the last 
	    default:
		i0 = 0;
		i1 = iBarShift(NULL, 0, MathMin(tup1, tdown1));
		break;
	    }
	    
	    int ihigh = iHighest(NULL, 0, MODE_HIGH, i1 - i0 + 1, i0);
	    int ilow  = iLowest(NULL, 0, MODE_LOW, i1 - i0 + 1, i0);
	    int tofst = 2;
	    datetime thigh = Time[ihigh + tofst];
	    datetime tlow  = Time[ilow + tofst];
	    double phigh = High[ihigh];
	    double plow  = Low[ilow];
	    if (tlow < thigh) {
		datetime ts = tlow;
		double ps = plow;
		datetime te = thigh;
		double pe = phigh;
	    } else {
		ts = thigh;
		ps = phigh;
		te = tlow;
		pe = plow;
	    }
	    objFibo(" fibo0", win, ts, ps, te, pe, colFiboLine, wFiboLine, styleFiboLine,
		    colFiboLevel, wFiboLevel, styleFiboLevel);
	}
    }
    
    if (bWolfeWave) {
	int it1, it2, it3, it4, ite;
	int dit, iwolfe;
	double v2, v3, v4;
	double a, c = 2.0;
	bool bRay;
	
	// Wolfe wave in down trend, Long
	//
	//                     v4  -  ~  ~  target line
	//      v2          -  +
	//      +       -     / \.
	//     / \  -        /   \.
	//  \ / - \         /      .
	//   + - - - - - - - - - - -
	// v1  ~    \     /          .
	//       ~   \   /
	//         ~  \ /
	//           ~ + 
	//           v3 ~         
	//                 ~   ~   ~   + v5 entry point
	// 
	bRay = true;
        iwolfe = 0;
	for (i = nTrendLower - 1; i >= 1; i--) {
	    if (i <= nTrendUpper - 1) {
		it4 = IdxPeakUpper[IdxTrendUpper[i]];
		it3 = IdxPeakLower[IdxTrendLower[i]];
		it2 = IdxPeakUpper[IdxTrendUpper[i - 1]];
		it1 = IdxPeakLower[IdxTrendLower[i - 1]];
		
		v4 = getUpperValue(IdxTrendUpper[i]);
		v3 = getLowerValue(IdxTrendLower[i]);
		v2 = getUpperValue(IdxTrendUpper[i - 1]);
		v1 = getLowerValue(IdxTrendLower[i - 1]);
		
		if (v3 < v1 && v4 > v1) {
		    dit = it3 - it1;
		    a = (v3 - v1) / dit;
		    ite = it1 + dit * c;
		    if (ite >= 0) {
			te = Time[ite];
		    } else {
			te = Time[0] - Period() * 60 * ite;
		    }
		    objLine(sWolfeDownLower + iwolfe, win, Time[it1], v1, te, v1 + a * c * dit, colWolfeLong, wWolfe, STYLE_SOLID, false, bRay);
		    dit = it4 - it1;
		    a = (v4 - v1) / dit;
		    ite = it1 + dit * c;
		    if (ite >= 0) {
			te = Time[ite];
		    } else {
			te = Time[0] - Period() * 60 * ite;
		    }
		    objLine(sWolfeDownTarget + iwolfe, win, Time[it1], v1, te, v1 + a * c * dit, colWolfeLong, wWolfe, STYLE_DOT, false, bRay);
		    bRay = false;
		    
		    iwolfe++;
		    if (iwolfe >= nMaxWolfeWave) {
			break;
		    }
		}
	    }
	}
	for (; iwolfe < nMaxWolfeWave; iwolfe++) {
	    objLine(sWolfeDownLower + iwolfe, win, 0, 0, 0, 0);
	    objLine(sWolfeDownTarget + iwolfe, win, 0, 0, 0, 0);
	}
	
	// Wolfe wave in up trend, Short
	//
	//                     -   -   + v5 entry point
	//                 ~
	//           v3 ~
	//           ~ + 
	//         ~  / \.
	//       ~   /   \.
	// v1  ~    /     .         .
	//   + - - - - - - - - - - -
	//  / \ - /         \.    .
	//     \ /  -        \.  /
	//      +       -     \./
	//      v2          -  +
	//                     v4  -   _   _  target line
	// 
	bRay = true;
        iwolfe = 0;
	for (i = nTrendUpper - 1; i >= 1; i--) {
	    if (i < nTrendLower - 1) {
		it4 = IdxPeakLower[IdxTrendLower[i + 1]];
		it3 = IdxPeakUpper[IdxTrendUpper[i]];
		it2 = IdxPeakLower[IdxTrendLower[i]];
		it1 = IdxPeakUpper[IdxTrendUpper[i - 1]];
		
		v4 = getLowerValue(IdxTrendLower[i + 1]);
		v3 = getUpperValue(IdxTrendUpper[i]);
		v2 = getLowerValue(IdxTrendLower[i1]);
		v1 = getUpperValue(IdxTrendUpper[i - 1]);
		
		if (v3 > v1 && v4 < v1) {
		    dit = it3 - it1;
		    a = (v3 - v1) / dit;
		    ite = it1 + dit * c;
		    if (ite >= 0) {
			te = Time[ite];
		    } else {
			te = Time[0] - Period() * 60 * ite;
		    }
		    objLine(sWolfeUpLower + iwolfe, win, Time[it1], v1, te, v1 + a * c * dit, colWolfeShort, wWolfe, STYLE_SOLID, false, bRay);
		    dit = it4 - it1;
		    a = (v4 - v1) / dit;
		    ite = it1 + dit * c;
		    if (ite >= 0) {
			te = Time[ite];
		    } else {
			te = Time[0] - Period() * 60 * ite;
		    }
		    objLine(sWolfeUpTarget + iwolfe, win, Time[it1], v1, te, v1 + a * c * dit, colWolfeShort, wWolfe, STYLE_DOT, false, bRay);
		    bRay = false;
		    
		    iwolfe++;
		    if (iwolfe >= nMaxWolfeWave) {
			break;
		    }
		}
	    }
	}
	for (; iwolfe < nMaxWolfeWave; iwolfe++) {
	    objLine(sWolfeUpLower + iwolfe, win, 0, 0, 0, 0);
	    objLine(sWolfeUpTarget + iwolfe, win, 0, 0, 0, 0);
	}
    }
    
    WindowRedraw();
}
