//
// "00-RCI_v104.mq4" -- calculate RCI
//
//    Ver. 1.00  2008/10/13(Mon)  initial version
//    Ver. 1.01  2008/10/19(Sun)  added appliedPrice
//    Ver. 1.02  2008/10/20(Mon)  version sync
//    Ver. 1.03  2008/11/22(Sat)  PRICE_AVE
//    Ver. 1.04  2010/05/07(Fri)  (just for 00-RCICross_v104)
//
//
#property copyright  "00mql4@gmail.com"
#property link       "http://00mql4.blogspot.com/"

//---- indicator settings
#property indicator_separate_window

#property indicator_buffers  3

#property  indicator_color1  Yellow
#property  indicator_color2  DodgerBlue
#property  indicator_color3  Crimson

#property  indicator_width1  1

#property  indicator_style1  STYLE_SOLID

#property  indicator_minimum  -1
#property  indicator_maximum  1

//---- defines
//      PRICE_CLOSE     0     Close price
//      PRICE_OPEN      1     Open price
//      PRICE_HIGH      2     High price
//      PRICE_LOW       3     Low price
//      PRICE_MEDIAN    4     Median price, (high + low) / 2
//      PRICE_TYPICAL   5     Typical price, (high + low + close) / 3
//      PRICE_WEIGHTED  6     Weighted close price, (high + low + close + close) / 4
#define PRICE_MEDIAN2   7  // Median2 price, (open + high + low + close) / 4
#define PRICE_AVE       8  // 

//---- indicator parameters
extern int    nPeriod       = 9;          // period of RCI
extern int    appliedPrice  = PRICE_AVE;  // 0:CLOSE 1:OPEN 2:HIGH 3:LOW 4:MEDIAN 5:TYPICAL 6:WEIGHTED 7:MEDIAN 8:AVE
extern double levelLo       = -0.6;       // lower level of threshold
extern double levelHi       = 0.6;        // upper level of threshold
extern int    nMaxBar       = 2000;       // maximum number of bars, 0: no limit

//---- indicator buffers
double BufferRci[];    // 0: RCI value
double BufferLong[];   // 1: Long signal
double BufferShort[];  // 2: Short signal

//---- vars
string sIndicatorName  = "00-RCI_v103";
int    markLong      = 233;
int    markShort     = 234;
bool   bShowSignal   = true;

//----------------------------------------------------------------------
void init()
{
    sIndicatorName = sIndicatorName + "(" + nPeriod + ")";
    
    IndicatorShortName(sIndicatorName);
    
    SetIndexBuffer(0, BufferRci);
    SetIndexBuffer(1, BufferLong);
    SetIndexBuffer(2, BufferShort);
    
    SetIndexLabel(0, "RCI(" + nPeriod + ")");
    SetIndexLabel(1, "Long signal");
    SetIndexLabel(2, "Short signal");
    
    SetIndexStyle(0, DRAW_LINE);
    SetIndexStyle(1, DRAW_ARROW);
    SetIndexStyle(2, DRAW_ARROW);
    
    SetIndexArrow(1, markLong);
    SetIndexArrow(2, markShort);
    
    SetLevelValue(0, levelLo);
    SetLevelValue(1, levelHi);
    
    SetIndexDrawBegin(0, nPeriod);
    SetIndexDrawBegin(1, nPeriod);
    SetIndexDrawBegin(2, nPeriod);
    SetIndexDrawBegin(3, nPeriod);
}

//----------------------------------------------------------------------
void copyData(double &data[], int i, int n)
{
    double open[];
    double high[];
    double low[];
    
    if (appliedPrice >= PRICE_MEDIAN) {
	ArrayResize(open, n);
	ArrayResize(high, n);
	ArrayResize(low, n);
	ArrayCopy(open, Open,  0, i, n);
	ArrayCopy(high, High,  0, i, n);
	ArrayCopy(low,  Low,   0, i, n);
	ArrayCopy(data, Close, 0, i, n);
    }
    
    double o, h, l, c, area, len, ave;
    
    switch (appliedPrice) {
	
    case PRICE_CLOSE:
	ArrayCopy(data, Close, 0, i, n);
	break;
	
    case PRICE_OPEN:
	ArrayCopy(data, Open, 0, i, n);
	break;
	
    case PRICE_HIGH:
	ArrayCopy(data, High, 0, i, n);
	break;
	
    case PRICE_LOW:
	ArrayCopy(data, Low, 0, i, n);
	break;
	
    case PRICE_MEDIAN:
	for (i = 0; i < n; i++) {
	    data[i] = (high[i] + low[i]) / 2;
	}
	break;
	
    case PRICE_TYPICAL:
	for (i = 0; i < n; i++) {
	    data[i] = (high[i] + low[i] + data[i]) / 3;
	}
	break;
	
    case PRICE_WEIGHTED:
	for (i = 0; i < n; i++) {
	    data[i] = (high[i] + low[i] + data[i] * 2) / 4;
	}
	break;
	
    case PRICE_MEDIAN2:
	for (i = 0; i < n; i++) {
	    data[i] = (open[i] + high[i] + low[i] + data[i]) / 4;
	}
	break;
	
    case PRICE_AVE:
	for (i = 0; i < n; i++) {
	    o = open[i];
	    h = high[i];
	    l = low[i];
	    c = data[i];
	    area = (h * h - l * l) * 0.75 - MathAbs(o * o - c * c) / 2.0;
	    len = (h - l) * 1.5 - MathAbs(o - c);
	    ave = o;
	    if (len != 0) {
		ave = area / len;
	    }
	    data[i] = ave;
	}
	break;
	
    default:
	Print("Warning: illegal appliedPrice= ", appliedPrice);
	ArrayCopy(data, Close, 0, i, n);
	break;
    }
}

//----------------------------------------------------------------------
void start()
{
    int limit;
    int counted_bars = IndicatorCounted();
    
    if (counted_bars > 0) {
	counted_bars--;
    }
    
    limit = Bars - counted_bars;
    int limit0 = limit;
    if (nMaxBar > 0) {
	limit = MathMin(limit, nMaxBar);
    }
    
    double data[];
    ArrayResize(data, nPeriod);
    
    // clear beyond limits
    for (int i = limit0 - 1; i >= limit; i--) {
	BufferRci[i]   = 0;
	BufferLong[i]  = EMPTY_VALUE;
	BufferShort[i] = EMPTY_VALUE;
    }
    
    for (i = limit - 1; i >= 0; i--) {
	copyData(data, i, nPeriod);
	int total = 0;
	for (int j = 0; j < nPeriod; j++) {
	    int imax = ArrayMaximum(data);
	    total += (imax - j) * (imax - j);
	    data[imax] = 0;
	}
	BufferRci[i] = 1.0 - 6.0 * total / (nPeriod * (nPeriod * nPeriod - 1.0));
    }
    
    // check signal
    for (i = limit - 1; i >= 0; i--) {
	BufferLong[i] = EMPTY_VALUE;
	BufferShort[i] = EMPTY_VALUE;
	
	if (bShowSignal) {
	    double rci2 = BufferRci[i + 2];
	    double rci1 = BufferRci[i + 1];
	    
	    // long signal
	    if (rci2 <= levelLo && rci1 > levelLo) {
		BufferLong[i] = levelLo;
	    }
	    
	    // short signal
	    if (rci2 >= levelHi && rci1 < levelHi) {
		BufferShort[i] = levelHi;
	    }
	}
    }
}
