//
// "00-EPMA_v100.mq4" -- End Point Moving Average
//
//    Ver. 1.00  2009/01/11(Sun)  initial version
//
//
#property  copyright "00"
#property  link      "http://www.mql4.com/"

//---- defines

//---- indicator settings
#property  indicator_chart_window

#property  indicator_buffers  1

#property  indicator_color1  Yellow

#property  indicator_width1  1

#property  indicator_style1  STYLE_SOLID

//---- indicator parameters
extern int  timeFrame     = 0;     // time frame
extern int  period        = 20;    // EPMA period
extern int  appliedPrice  = 0;     // 0:CLOSE 1:OPEN 2:HIGH 3:LOW 4:MEDIAN 5:TYPICAL 6:WEIGHTED
extern int  nMaxBars      = 2000;  // maximum number of bars to calculate, 0: no limit

//---- indicator buffers
double BufferEpma[];            // 0: EPMA

//---- vars
string   sIndicatorName  = "";
string   sIndSelf        = "00-EPMA_v100";

//----------------------------------------------------------------------
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()
{
    period = MathMax(period, 1);
    
    if (timeFrame == 0) {
	timeFrame = Period();
    }
    
    string tf = TimeFrameToStr(timeFrame);
    sIndicatorName = sIndSelf + "(" + tf + "," + period + ")";
    
    IndicatorShortName(sIndicatorName);
    
    SetIndexBuffer(0, BufferEpma);
    
    SetIndexLabel(0, "EPMA");
    
    SetIndexStyle(0, DRAW_LINE);
    
    int n = period;
    SetIndexDrawBegin(0, period);
}

//----------------------------------------------------------------------
double getVal(int x)
{
    switch (appliedPrice) {
	
    case PRICE_CLOSE:
	return(Close[x]);
	
    case PRICE_OPEN:
	return(Open[x]);
	
    case PRICE_HIGH:
	return(High[x]);
	
    case PRICE_LOW:
	return(Low[x]);
	
    case PRICE_MEDIAN:
	return((High[x] + Low[x]) / 2.0);
	
    case PRICE_TYPICAL:
	return((High[x] + Low[x] + Close[x]) / 3.0);
	
    case PRICE_WEIGHTED:
	return((High[x] + Low[x] + Close[x] * 2.0) / 4.0);
    }
}

//----------------------------------------------------------------------
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--) {
	BufferEpma[i] = EMPTY_VALUE;
    }
    
    if (timeFrame != Period()) {
	// MTF
	limit = MathMax(limit, timeFrame / Period());
	for (i = limit - 1; i >= 0; i--) {
	    int x = iBarShift(NULL, timeFrame, Time[i]);
	    BufferEpma[i] = iCustom(NULL, timeFrame, sIndSelf, 0, period, appliedPrice, nMaxBars, 0, x);
	}
	
	return;
    }
    
    // timeFrame == Period()
    for (i = limit - 1; i >= 0; i--) {
	double tot = 0.0;
	for (int j = 0; j < period; j++) {
	    x = i + j;
	    tot += (2.0 * period - 3.0 * j - 1) * getVal(x);
	}
	double epma = 2.0 / (period * (period + 1.0)) * tot;
	BufferEpma[i] = epma;
    }
}
