//
// "00-MultiPerfectOrder_v101.mq4" -- draw PerfectOrder of MN/W1/D1/H4/H1/M30/M15/M5/M1 simultaneously
//
//    Ver. 1.00  2008/10/12(Sun)   initial version
//    Ver. 1.01  2008/10/17(Fri)   EMA fibo step, use Open[] instead of Close[]
// 
#property  copyright "00 - 00mql4@gmail.com"
#property  link      "http://www.mql4.com/"

//---- indicator settings
#property  indicator_separate_window

#property  indicator_buffers  6

#property  indicator_color1  White
#property  indicator_color2  White
#property  indicator_color3  DarkGray
#property  indicator_color4  DarkGray
#property  indicator_color5  Gray
#property  indicator_color6  Gray

#property  indicator_width1  1
#property  indicator_width2  1
#property  indicator_width3  0
#property  indicator_width4  0
#property  indicator_width5  0
#property  indicator_width6  0

#property  indicator_style1  STYLE_SOLID
#property  indicator_style2  STYLE_SOLID
#property  indicator_style3  STYLE_SOLID
#property  indicator_style4  STYLE_SOLID
#property  indicator_style5  STYLE_DOT
#property  indicator_style6  STYLE_DOT

//---- defines
#define N_AVE        8
#define N_TIMEFRAME  9

//---- indicator parameters
extern string sIndPerfectOrder  = "00-PerfectOrder_v101";
extern int    nBar              = 2000;
extern bool   bPerfect          = true;
extern bool   bIgnoreM1         = true;
extern int    nAve0             = 21;
extern int    nAve1             = 34;
extern int    nAve2             = 55;
extern int    nAve3             = 89;
extern int    nAve4             = 144;
extern int    nAve5             = 233;
extern int    nAve6             = 377;
extern int    nAve7             = 610;
extern int    maMethod          = MODE_EMA;
extern int    appliedPrice      = PRICE_OPEN;
extern string g_fontName        = "Arial";
extern color  g_fontColor       = White;
extern int    g_fontSize        = 12;

//---- indicator buffers
double BufferBigLong[];     // 0: long, big
double BufferBigShort[];    // 1: short, big
double BufferSmallLong[];   // 2: long, small
double BufferSmallShort[];  // 3: short, small
double BufferTop[];         // 4: place holder
double BufferBottom[];      // 5: place holder

//---- vars
string   sIndicatorName  = "00-MultiPerfectOrder_v101";
string   sPrefix;
int      g_nAve[N_AVE];
int      g_timeFrame[N_TIMEFRAME]   = { 1, 5, 15, 30, 60, 240, 1440, 10080, 43200 };
string   g_sTimeFrame[N_TIMEFRAME]  = { "M1", "M5", "M15", "M30", "H1", "H4", "D1", "W1", "MN" };
int      g_window;
int      markBigLong     = 233;
int      markBigShort    = 234;
int      markSmallLong   = 233;
int      markSmallShort  = 234;

//----------------------------------------------------------------------
void init()
{
    sPrefix = sIndicatorName;
    
    IndicatorShortName(sIndicatorName);
    
    SetIndexBuffer(0, BufferBigLong);
    SetIndexBuffer(1, BufferBigShort);
    SetIndexBuffer(2, BufferSmallLong);
    SetIndexBuffer(3, BufferSmallShort);
    SetIndexBuffer(4, BufferTop);
    SetIndexBuffer(5, BufferBottom);
    
    SetIndexLabel(0, "Long, big");
    SetIndexLabel(1, "Short, big");
    SetIndexLabel(2, "Long, small");
    SetIndexLabel(3, "Short, small");
    SetIndexLabel(2, "PlaceHolder Top");
    SetIndexLabel(3, "PlaceHolder Bottom");
    
    SetIndexStyle(0, DRAW_ARROW);
    SetIndexStyle(1, DRAW_ARROW);
    SetIndexStyle(2, DRAW_ARROW);
    SetIndexStyle(3, DRAW_ARROW);
    SetIndexStyle(4, DRAW_LINE);
    SetIndexStyle(5, DRAW_LINE);
    
    SetIndexArrow(0, markBigLong);
    SetIndexArrow(1, markBigShort);
    SetIndexArrow(2, markSmallLong);
    SetIndexArrow(3, markSmallShort);
    
    g_nAve[0] = nAve0;
    g_nAve[1] = nAve1;
    g_nAve[2] = nAve2;
    g_nAve[3] = nAve3;
    g_nAve[4] = nAve4;
    g_nAve[5] = nAve5;
    g_nAve[6] = nAve6;
    g_nAve[7] = nAve7;
    
    SetIndexDrawBegin(0, g_nAve[N_AVE - 1]);
    SetIndexDrawBegin(1, g_nAve[N_AVE - 1]);
    SetIndexDrawBegin(2, g_nAve[N_AVE - 1]);
    SetIndexDrawBegin(3, g_nAve[N_AVE - 1]);
    SetIndexDrawBegin(4, 0);
    SetIndexDrawBegin(5, 0);
}

//----------------------------------------------------------------------
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 objRect(string sName, datetime ts, double ps, datetime te, double pe, color col)
{
    sName = sPrefix + sName;
    
    ObjectCreate(sName, OBJ_RECTANGLE, 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);
}

//----------------------------------------------------------------------
void objLine(string sName, datetime ts, double ps, datetime te, double pe, color col)
{
    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);
}

//----------------------------------------------------------------------
void drawLabel()
{
    int labelCorner = 3;
    int tx = 10;
    int ty = 5;
    for (int i = 0; i < N_TIMEFRAME; i++) {
	string sName = sPrefix + " label" + i;
    	string s = g_sTimeFrame[i];
	ObjectCreate(sName, OBJ_LABEL, g_window, 0, 0);
	ObjectSetText(sName, s, g_fontSize, g_fontName, g_fontColor);
	ObjectSet(sName, OBJPROP_CORNER, labelCorner);
	ObjectSet(sName, OBJPROP_XDISTANCE, tx);
	ObjectSet(sName, OBJPROP_YDISTANCE, ty);
	ty += g_fontSize + 2;
    }
}

//----------------------------------------------------------------------
double MathClip(double v, double min, double max)
{
    return(MathMax(MathMin(v, max), min));
}

//----------------------------------------------------------------------
color colScale(color col, double scale)
{
    int r = MathClip(MathRound(((col >> 0)  & 0xff) * scale), 0, 255);
    int g = MathClip(MathRound(((col >> 8)  & 0xff) * scale), 0, 255);
    int b = MathClip(MathRound(((col >> 16) & 0xff) * scale), 0, 255);
    
    return((b << 16) | (g << 8) | r);
}

//----------------------------------------------------------------------
int periodToIdx(int period)
{
    int idx = 0;
    
    for (int i = 0; i < N_TIMEFRAME; i++) {
	if (period == g_timeFrame[i]) {
	    idx = i;
	    break;
	}
    }
    
    return(idx);
}

//----------------------------------------------------------------------
void start()
{
    int limit = MathMin(Bars, nBar);
    
    g_window = WindowFind(sIndicatorName);
    if (g_window < 0) {
	g_window = 1;
    }
    
    datetime t1 = Time[limit - 1];
    datetime t0 = Time[0];
    double ps = periodToIdx(Period());
    double pe = ps + 1;
    objLine("line cur0" , t1, ps, t0, ps, DarkGray);
    objLine("line cur1" , t1, pe, t0, pe, DarkGray);
    
    double p;
    for (int i = limit - 1; i >= 0; i--) {
	t1 = Time[i + 1];
	t0 = Time[i];
	double pLongSignal[N_TIMEFRAME];
	double pShortSignal[N_TIMEFRAME];
	double pLongLevel[N_TIMEFRAME];
	double pShortLevel[N_TIMEFRAME];
	bool bValid[N_TIMEFRAME];
	for (int tf = 0; tf < N_TIMEFRAME; tf++) {
	    int timeFrame = g_timeFrame[tf];
	    int shift = iBarShift(NULL, timeFrame, t0, true);
	    if (shift < 0) {
		bValid[tf] = false;
	    } else {
		bValid[tf] = true;
		
		pLongSignal[tf]  = iCustom(NULL, timeFrame, sIndPerfectOrder, bPerfect, g_nAve[0], g_nAve[1], g_nAve[2], g_nAve[3],
					   g_nAve[4], g_nAve[5], g_nAve[6], g_nAve[7], maMethod, appliedPrice, 0, shift);
		pShortSignal[tf] = iCustom(NULL, timeFrame, sIndPerfectOrder, bPerfect, g_nAve[0], g_nAve[1], g_nAve[2], g_nAve[3],
					   g_nAve[4], g_nAve[5], g_nAve[6], g_nAve[7], maMethod, appliedPrice, 1, shift);
		pLongLevel[tf]   = iCustom(NULL, timeFrame, sIndPerfectOrder, bPerfect, g_nAve[0], g_nAve[1], g_nAve[2], g_nAve[3],
					   g_nAve[4], g_nAve[5], g_nAve[6], g_nAve[7], maMethod, appliedPrice, 2, shift);
		pShortLevel[tf]  = iCustom(NULL, timeFrame, sIndPerfectOrder, bPerfect, g_nAve[0], g_nAve[1], g_nAve[2], g_nAve[3],
					   g_nAve[4], g_nAve[5], g_nAve[6], g_nAve[7], maMethod, appliedPrice, 3, shift);
	    }
	    
	    // check
	    if (i == limit) {
		int x = shift * Period() / timeFrame;
		if (iClose(NULL, timeFrame, x) <= 0) {
		    Print("Warning: ", Symbol(), " ", g_sTimeFrame[tf], " ", TimeToStr(t0));
		}
	    }
	    
	    ps = tf;
	    pe = tf + 1.0;
	    color col;
	    if (!bValid[tf]) {
		// data not exists
		col = 0x404040 + 0x020202 * (tf & 1);
	    } else {
		double level = pLongLevel[tf] - pShortLevel[tf];
		if (level > 0) {
		    col = DodgerBlue + 0x000808 * (tf & 1);  // DodgerBlye= (30, 144, 255)= 0x1e90ff
		    col = colScale(col, level);
		} else if (level < 0) {
		    col = Crimson + 0x080810 * (tf & 1);  // Crimson= (220, 20, 60)= 0xdc143c
		    col = colScale(col, -level);
		} else {
		    col = 0x060606 * ((tf & 1) + 1);
		}
		if (bIgnoreM1 && tf == 0) {
		    col = colScale(col, 0.5);
		}
	    }
	    objRect("rect"  + i + " " + tf, t1, ps, t0, pe, col);
	}
	BufferTop[i] = N_TIMEFRAME;
	BufferBottom[i] = 0;
	
	// signal
	{
	    BufferBigLong[i] = EMPTY_VALUE;
	    BufferBigShort[i] = EMPTY_VALUE;
	    BufferSmallLong[i] = EMPTY_VALUE;
	    BufferSmallShort[i] = EMPTY_VALUE;
	    
	    // long
	    if ((bIgnoreM1 || (bValid[0] && pLongSignal[0] != EMPTY_VALUE)) &&
		bValid[1] && pLongSignal[1] != EMPTY_VALUE &&
		bValid[2] && pLongSignal[2] != EMPTY_VALUE &&
		bValid[3] && pLongSignal[3] != EMPTY_VALUE &&
		bValid[4] && pLongSignal[4] != EMPTY_VALUE &&
		bValid[5] && pLongSignal[5] != EMPTY_VALUE &&
		bValid[6] && pLongSignal[6] != EMPTY_VALUE) {
		
		BufferSmallLong[i] = 7;
		
		if (bValid[7] && pLongSignal[7] != EMPTY_VALUE &&
		    bValid[8] && pLongSignal[8] != EMPTY_VALUE) {
		    
		    BufferBigLong[i] = 9;
		}
	    }
		
	    // short
	    if ((bIgnoreM1 || (bValid[0] && pShortSignal[0] != EMPTY_VALUE)) &&
		bValid[1] && pShortSignal[1] != EMPTY_VALUE &&
		bValid[2] && pShortSignal[2] != EMPTY_VALUE &&
		bValid[3] && pShortSignal[3] != EMPTY_VALUE &&
		bValid[4] && pShortSignal[4] != EMPTY_VALUE &&
		bValid[5] && pShortSignal[5] != EMPTY_VALUE &&
		bValid[6] && pShortSignal[6] != EMPTY_VALUE) {
		
		BufferSmallShort[i] = 7;
		
		if (bValid[7] && pShortSignal[7] != EMPTY_VALUE &&
		    bValid[8] && pShortSignal[8] != EMPTY_VALUE) {
		    
		    BufferBigShort[i] = 9;
		}
	    }
	}
    }
    
    drawLabel();
    
    WindowRedraw();
}
