//
// "00-ShinNeAshi.mq4" -- draw ShinNeAshi
//
//    Ver. 1.00  2008/10/1(Wed)
// 
#property  copyright "00"
#property  link      "http://www.mql4.com/"

//---- indicator settings
#property  indicator_separate_window

#property  indicator_buffers  3

#property  indicator_color1  -1
#property  indicator_color2  -1
#property  indicator_color3  -1

#property  indicator_width1  1
#property  indicator_width2  1
#property  indicator_width3  1

// defines
#define N_CHECK_SHINNE  100

//---- indicator parameters
extern string symbol      = "";
extern int nShinNe        = 3;      // should be < N_CHECK_SHINNE
extern int nBar           = 1000;
extern string symTimeRef  = "";     // time reference
extern color cUpFrame     = Lime;
extern color cUpBody      = Black;
extern color cDownFrame   = Lime;
extern color cDownBody    = White;
extern int nBodyWidth     = 3;

//---- indicator buffers
double bufClose[];
double bufHigh[];
double bufLow[];

//---- vars
string sIndicatorName;
int    nChart;
string sVarChart       = "00-ShinNeAshi nChart";
string sVarCount       = "00-ShinNeAshi count";
string sUpFrameName    = "1upFrame";
string sUpBodyName     = "2upBody";
string sDownFrameName  = "1downFrame";
string sDownBodyName   = "2downBody";
double vOpen[N_CHECK_SHINNE];
double vClose[N_CHECK_SHINNE];
bool bUp[N_CHECK_SHINNE];

//----------------------------------------------------------------------
string getBarName(int i, string s)
{
    return(sIndicatorName + " bar" + i + " " + s);
}

//----------------------------------------------------------------------
void objInit(bool bInit)
{
    int win = WindowFind(sIndicatorName);
    
    for (int i = 0; i < nBar; i++) {
	string sUpFrame   = getBarName(i, sUpFrameName);
	string sUpBody    = getBarName(i, sUpBodyName);
	string sDownFrame = getBarName(i, sDownFrameName);
	string sDownBody  = getBarName(i, sDownBodyName);
	
	if (bInit) {
	    // create bars
	    // up bar
	    ObjectCreate(sUpFrame, OBJ_TREND, win, 0, 0);
	    ObjectSet(sUpFrame, OBJPROP_RAY, 0);
	    ObjectSet(sUpFrame, OBJPROP_WIDTH, nBodyWidth + 2);
	    ObjectSet(sUpFrame, OBJPROP_COLOR, cUpFrame);
	    
	    ObjectCreate(sUpBody,  OBJ_TREND, win, 0, 0);
	    ObjectSet(sUpBody, OBJPROP_RAY, 0);
	    ObjectSet(sUpBody, OBJPROP_WIDTH, nBodyWidth);
	    ObjectSet(sUpBody, OBJPROP_COLOR, cUpBody);
	    
	    // down bar
	    ObjectCreate(sDownFrame, OBJ_TREND, win, 0, 0);
	    ObjectSet(sDownFrame, OBJPROP_RAY, 0);
	    ObjectSet(sDownFrame, OBJPROP_WIDTH, nBodyWidth + 2);
	    ObjectSet(sDownFrame, OBJPROP_COLOR, cDownFrame);
	    
	    ObjectCreate(sDownBody,  OBJ_TREND, win, 0, 0);
	    ObjectSet(sDownBody, OBJPROP_RAY, 0);
	    ObjectSet(sDownBody, OBJPROP_WIDTH, nBodyWidth);
	    ObjectSet(sDownBody, OBJPROP_COLOR, cDownBody);
	} else {
	    // delete bars
	    ObjectDelete(sUpFrame);
	    ObjectDelete(sUpBody);
	    ObjectDelete(sDownFrame);
	    ObjectDelete(sDownBody);
	}
    }
}

//----------------------------------------------------------------------
void init()
{
    nChart = GlobalVariableGet(sVarChart) + 1;
    GlobalVariableSet(sVarChart, nChart);
    
    int count = GlobalVariableGet(sVarCount) + 1;
    GlobalVariableSet(sVarCount, count);
    
    if (symbol == "") {
	symbol = Symbol();
    }
    if (symTimeRef == "") {
	symTimeRef = Symbol();
    }
    if (nShinNe < 1) {
	nShinNe = 1;
    }
    
    sIndicatorName = "00-ShinNeAshi(" + nShinNe + ") " + symbol + " " + count;
    
    SetIndexStyle(0, DRAW_LINE);
    SetIndexStyle(1, DRAW_LINE);
    SetIndexStyle(2, DRAW_LINE);
    
    SetIndexBuffer(0, bufClose);
    SetIndexBuffer(1, bufHigh);
    SetIndexBuffer(2, bufLow);
    
    IndicatorShortName(sIndicatorName);
    
    SetIndexLabel(0, symbol + "Close");
    SetIndexLabel(1, symbol + "High");
    SetIndexLabel(2, symbol + "Low");
}

//----------------------------------------------------------------------
void deinit()
{
    objInit(false);
    
    nChart = GlobalVariableGet(sVarChart);
    GlobalVariableSet(sVarChart, nChart - 1);
    
    if (nChart == 1) {
	GlobalVariableDel(sVarChart);
	GlobalVariableDel(sVarCount);
    }
}

//----------------------------------------------------------------------
void barMove(int i, datetime t, double open, double close)
{
    string sUpFrame   = getBarName(i, sUpFrameName);
    string sUpBody    = getBarName(i, sUpBodyName);
    string sDownFrame = getBarName(i, sDownFrameName);
    string sDownBody  = getBarName(i, sDownBodyName);
    
    double upOpen = 0;
    double upClose = 0;
    double downOpen = 0;
    double downClose = 0;
    
    if (close >= open) {
	upOpen  = open;
	upClose = close;
    } else {
	downOpen  = open;
	downClose = close;
    }
    
    ObjectMove(sUpFrame, 0, t, upOpen);
    ObjectMove(sUpFrame, 1, t, upClose);
    ObjectMove(sUpBody,  0, t, upOpen);
    ObjectMove(sUpBody,  1, t, upClose);
    
    ObjectMove(sDownFrame, 0, t, downOpen);
    ObjectMove(sDownFrame, 1, t, downClose);
    ObjectMove(sDownBody,  0, t, downOpen);
    ObjectMove(sDownBody,  1, t, downClose);
}

//----------------------------------------------------------------------
void shift(double open, double close)
{
    for (int k = nShinNe; k > 0; k--) {
	vOpen[k]  = vOpen[k - 1];
	vClose[k] = vClose[k - 1];
    }
    vOpen[0]  = open;
    vClose[0] = close;
}

//----------------------------------------------------------------------
void start()
{
    int limit;
    int counted_bars = IndicatorCounted();
    
    if (counted_bars > 0) {
	counted_bars--;
    }
    
    limit = Bars - counted_bars;
    
    int i, x;
    datetime t;
    for (i = 0; i < limit; i++) {
	t = iTime(symTimeRef, 0, i);
	x = iBarShift(symbol, 0, t);
	bufClose[i] = iClose(symbol, 0, x);
    }
    
    objInit(true);
    
    int w = WindowBarsPerChart();
    int b = WindowFirstVisibleBar() + MathMax(0, (nBar - w) / 2);
    if (b < nBar) {
	b = nBar - 1;
    }
    if (b > Bars) {
	b = Bars;
    }
    
    double open, close;
    bool bTrendChanged = false;
    int k;
    
    for (i = 0; i < nBar; i++) {
	
	int iRef = b - i;
	
	if (iRef >= 0) {
	    t = iTime(symTimeRef, 0, iRef);
	    x = iBarShift(symbol, 0, t);
	} else {
	    t = iTime(symTimeRef, 0, 0);
	    x = -1;
	}
	
	close = iClose(symbol, 0, x);
	
	if (i == 0) {
	    for (k = 0; k <= nShinNe; k++) {
		vOpen[k]  = close;
		vClose[k] = close;
	    }
	} else if (i == 1) {
	    vOpen[0]  = close;
	    vClose[0] = close;
	} else {
	    double prevPeak;
	    
	    for (k = 0; k <= nShinNe; k++) {
		bUp[k] = (vClose[k] >= vClose[k + 1]);
	    }
	    
	    if (bUp[0]) {
		// up trend
		if (close > vClose[0]) {
		    shift(vClose[0], close);
		    bTrendChanged = false;
		} else {
		    prevPeak = vOpen[0];
		    for (k = 1; k < nShinNe; k++) {
			if (!bUp[k]) {
			    prevPeak = vOpen[k];
			    break;
			}
		    }
		    if (k == nShinNe) {
			prevPeak = vClose[nShinNe];
		    }
		    if (close < prevPeak) {
			shift(vOpen[0], close);
			bTrendChanged = true;
		    }
		}		    
	    } else {
		// down trend
		if (close < vClose[0]) {
		    shift(vClose[0], close);
		    bTrendChanged = false;
		} else {
		    prevPeak = vOpen[0];
		    for (k = 1; k < nShinNe; k++) {
			if (bUp[k]) {
			    prevPeak = vOpen[k];
			    break;
			}
		    }
		    if (k == nShinNe) {
			prevPeak = vClose[nShinNe];
		    }
		    if (close > prevPeak) {
			shift(vOpen[0], close);
			bTrendChanged = true;
		    }
		}
	    }
	}
	
	open = vOpen[0];
	close = vClose[0];
	
	if (x < 0) {
	    open = 0;
	    close = 0;
	}
	barMove(i, t, open, close);
	
	double ofst = Point * 3;
	bufHigh[iRef] = MathMax(open, close) + ofst;
	bufLow[iRef] = MathMin(open, close) - ofst;
    }
    
    WindowRedraw();
}
