//
// "00-ADX_v101.mq4" -- ADX
//
//    Ver. 0.01  2008/11/03(Mon)  initial version
//    Ver. 1.00  2008/12/28(Sun)  release version
//    Ver. 1.01  2008/12/29(Mon)  bugfix: MTF don't work
//
//
#property  copyright  "00 - 00mql4@gmail.com"
#property  link       "http://www.mql4.com/"

//---- indicator settings
#property  indicator_separate_window

#property  indicator_buffers 3

#property  indicator_color1  LightSeaGreen  // 0: ADX
#property  indicator_color2  -1             // 1: +DI
#property  indicator_color3  -1             // 2: -DI

#property  indicator_width1  1
#property  indicator_width2  1
#property  indicator_width3  1

#property  indicator_style1  STYLE_DOT
#property  indicator_style2  STYLE_SOLID
#property  indicator_style3  STYLE_SOLID

#property indicator_minimum  0

#property indicator_level1  20

//---- defines

//---- input parameters
extern int    timeFrame         = 0;        // time frame
extern int    nAdx              = 14;       // period
extern bool   bAlertOnIncrease  = false;    // alert on dADX >= 0
extern bool   bAlertOnDecrease  = false;    // alert on dADX < 0
extern int    nMaxObjLines      = 1000;     // max number of signal line (dADX > 0)
extern color  colIncrease       = Magenta;  // color of increasing signal line
extern int    wIncrease         = 2;        // width of increasing signal line
extern int    window            = 0;        // window no, 0: auto
extern int    nMaxBars          = 2000;     // maximum number of bars to calculate, 0: no limit

//---- buffers
double BufferAdx[];       // 0: ADX
double BufferPlusDi[];    // 1: +DI
double BufferMinusDi[];   // 2: -DI
double BufferPlusSdi[];   // 3: tmp
double BufferMinusSdi[];  // 4: tmp
double BufferTmp[];       // 5: tmp

//---- vars
string   sIndicatorName = "";
string   sPrefix        = "";
int      g_window       = 0;
string   sIndSelf       = "00-ADX_v101";
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 (window > 0) {
	g_window = window;
    } else {
	g_window = WindowFind(sIndicatorName);
    }
    
    if (timeFrame == 0) {
	timeFrame = Period();
    }
    
    string tf = TimeFrameToStr(timeFrame);
    sIndicatorName = sIndSelf + "(" + tf + "," + nAdx + ")";
    sPrefix = sIndicatorName;
    
    IndicatorShortName(sIndicatorName);
    
    IndicatorBuffers(6);
    
    SetIndexBuffer(0, BufferAdx);
    SetIndexBuffer(1, BufferPlusDi);
    SetIndexBuffer(2, BufferMinusDi);
    SetIndexBuffer(3, BufferPlusSdi);
    SetIndexBuffer(4, BufferMinusSdi);
    SetIndexBuffer(5, BufferTmp);
    
    SetIndexLabel(0, "ADX");
    SetIndexLabel(1, "+DI");
    SetIndexLabel(2, "-DI");
    
    SetIndexStyle(0, DRAW_LINE);
    SetIndexStyle(1, DRAW_LINE);
    SetIndexStyle(2, DRAW_LINE);
    
    int n = nAdx;
    if (nMaxBars > 0) {
	n += Bars - MathMin(Bars, nMaxBars);
    }
    
    SetIndexDrawBegin(0, n);
    SetIndexDrawBegin(1, n);
    SetIndexDrawBegin(2, n);
}

//----------------------------------------------------------------------
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, datetime ts, double ps, datetime te, double pe, color col, int width = 1, bool ray = false)
{
    sName = sPrefix + sName;
    
    ObjectCreate(sName, OBJ_TREND, g_window, 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_RAY, ray);
}

//----------------------------------------------------------------------
void start()
{
    g_window = WindowFind(sIndicatorName);
    
    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--) {
	BufferAdx[i]      = EMPTY_VALUE;
	BufferPlusDi[i]   = EMPTY_VALUE;
	BufferMinusDi[i]  = EMPTY_VALUE;
	BufferPlusSdi[i]  = 0;
	BufferMinusSdi[i] = 0;
	BufferTmp[i]      = 0;
    }
    
    double adx3, adx2, adx1, adx0;
    bool bFire;
    
    if (timeFrame != Period()) {
	// MTF
	int scale = timeFrame / Period();
	limit = MathMax(limit, scale);
	for (i = limit - 1; i >= 0; i--) {
	    int shift = iBarShift(NULL, timeFrame, Time[i]);
	    BufferAdx[i]     = iCustom(NULL, timeFrame, sIndSelf, 0, nAdx, bAlertOnIncrease, bAlertOnDecrease,
				       nMaxObjLines, colIncrease, wIncrease, window, nMaxBars, 0, shift);
	    BufferPlusDi[i]  = iCustom(NULL, timeFrame, sIndSelf, 0, nAdx, bAlertOnIncrease, bAlertOnDecrease,
				       nMaxObjLines, colIncrease, wIncrease, window, nMaxBars, 1, shift);
	    BufferMinusDi[i] = iCustom(NULL, timeFrame, sIndSelf, 0, nAdx, bAlertOnIncrease, bAlertOnDecrease,
				       nMaxObjLines, colIncrease, wIncrease, window, nMaxBars, 2, shift);
	}
	
	// check alert
	if (bAlertOnIncrease || bAlertOnDecrease) {
	    adx3 = BufferAdx[3 * scale];
	    adx2 = BufferAdx[2 * scale];
	    adx1 = BufferAdx[1 * scale];
	    bFire = ((bAlertOnIncrease && adx1 >= adx2 && adx2 < adx3) ||
		     (bAlertOnDecrease && adx1 < adx2 && adx2 >= adx3));
	    if (bFire && tAlertLast != Time[0]) {
		PlaySound("alert.wav");
		tAlertLast = Time[0];
	    }
	}
	return;
    }
    
    // timeFrame == Period()
    for (i = limit - 1; i >= 0; i--) {
	double high1 = High[i + 1];
	double high0 = High[i + 0];
	double low1 = Low[i + 1];
	double low0 = Low[i + 0];
	double close1 = Close[i + 1];
	
	double pdm = MathMax(high0 - high1, 0);
	double mdm = MathMax(low1 - low0, 0);
	
	if (pdm == mdm) {
	    pdm = 0;
	    mdm = 0;
	} else if (pdm < mdm) {
	    pdm = 0;
	} else {
	    mdm = 0;
	}
	
	double v1 = MathAbs(high0 - low0);
	double v2 = MathAbs(high0 - close1);
	double v3 = MathAbs(low0 - close1);
	
	double vMax = MathMax(MathMax(v1, v2), v3);
	
	if (vMax == 0) {
	    BufferPlusSdi[i] = 0;
	    BufferMinusSdi[i] = 0;
	} else {
	    BufferPlusSdi[i] = pdm / vMax * 100;
	    BufferMinusSdi[i] = mdm / vMax * 100;
	}
    }
    
    for (i = limit - 1; i >= 0; i--) {
	BufferPlusDi[i] = iMAOnArray(BufferPlusSdi, 0, nAdx, 0, MODE_EMA, i);
	BufferMinusDi[i] = iMAOnArray(BufferMinusSdi, 0, nAdx, 0, MODE_EMA, i);
	
	double t = MathAbs(BufferPlusDi[i] + BufferMinusDi[i]);
	if (t == 0) {
	    BufferTmp[i] = 0;
	} else {
	    BufferTmp[i] = MathAbs(BufferPlusDi[i] - BufferMinusDi[i]) / t * 100;
	}
    }
    
    for (i = limit - 1; i >= 0; i--) {
	BufferAdx[i] = iMAOnArray(BufferTmp, 0, nAdx, 0, MODE_EMA, i);
    }
    
    int iline = 0;
    for (i = 0; i < Bars; i++) {
	datetime ts = Time[i + 1];
	datetime te = Time[i + 0];
	adx1 = BufferAdx[i + 1];
	adx0 = BufferAdx[i + 0];
	double ps, pe;
	if (adx0 > adx1) {
	    ps = adx1;
	    pe = adx0;
	    objLine("line" + iline, ts, ps, te, pe, colIncrease, wIncrease);
	    iline++;
	    if (iline >= nMaxObjLines) {
		break;
	    }
	}
    }
    for (; iline < nMaxObjLines; iline++) {
	objLine("line" + iline, 0, 0, 0, 0, colIncrease, wIncrease);
    }
    
    // alert
    if (bAlertOnIncrease || bAlertOnDecrease) {
	adx3 = BufferAdx[3];
	adx2 = BufferAdx[2];
	adx1 = BufferAdx[1];
	bFire = ((bAlertOnIncrease && adx1 >= adx2 && adx2 < adx3) ||
		 (bAlertOnDecrease && adx1 < adx2 && adx2 >= adx3));
	if (bFire && tAlertLast != Time[0]) {
	    PlaySound("alert.wav");
	    tAlertLast = Time[0];
	}
    }
}
