//
// "00-HeikinAshiSTF_v100.mq4" -- Heikin-Ashi Single Time Frame version
//
//    Ver. 1.00  2008/11/08(Sat)  initial version
// 
//
#property  copyright  "00 - 00mql4@gmail.com"
#property  link       "http://www.mql4.com/"

//---- indicator settings
#property indicator_chart_window

#property indicator_buffers  4

#property indicator_color1  0x1e0a6e
#property indicator_color2  0x80481e
#property indicator_color3  0x1e0a6e
#property indicator_color4  0x80481e

#property indicator_width1  1
#property indicator_width2  1
#property indicator_width3  3
#property indicator_width4  3

#property indicator_style1  STYLE_SOLID
#property indicator_style2  STYLE_SOLID
#property indicator_style3  STYLE_SOLID
#property indicator_style4  STYLE_SOLID

//---- indicator parameters
extern int    nGroupBar  = 3;    // number of bars in group
extern int    nMaxGroup  = 200;  // maximum number of groups
extern double yOffset    = 0;    // y offset (pips)

//      nGroupBar nMaxGroup yOffset
//  D1  288        10        150
//  H4   48        16        100
//  H1   12        48          0
//  M30   6        96        -90
//  M15   3       192       -175
//  M5    1       576       -225

//---- indicator buffers
double BufferHaLow[];    // 0: haLow
double BufferHaHigh[];   // 1: haHigh
double BufferHaOpen[];   // 2: haOpen
double BufferHaClose[];  // 3: haClose
double BufferHaDir[];    // 4: haClose

//---- vars
string sIndicatorName;
string sIndHeikinAshi = "00-HeikinAshiSTF_v100";
double g_open;
double g_high;
double g_low;
double g_close;
double g_ave;

//----------------------------------------------------------------------
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()
{
    sIndicatorName = sIndHeikinAshi + "(" + nGroupBar + ")";
    
    IndicatorShortName(sIndicatorName);
    
    IndicatorBuffers(5);

    SetIndexBuffer(0, BufferHaLow);
    SetIndexBuffer(1, BufferHaHigh);
    SetIndexBuffer(2, BufferHaOpen);
    SetIndexBuffer(3, BufferHaClose);
    SetIndexBuffer(4, BufferHaDir);
    
    SetIndexLabel(0, "haLow");
    SetIndexLabel(1, "haHigh");
    SetIndexLabel(2, "haOpen");
    SetIndexLabel(3, "haClose");
    SetIndexLabel(4, "dir");
    
    SetIndexStyle(0, DRAW_HISTOGRAM);
    SetIndexStyle(1, DRAW_HISTOGRAM);
    SetIndexStyle(2, DRAW_HISTOGRAM);
    SetIndexStyle(3, DRAW_HISTOGRAM);
    
    if (nMaxGroup == 0) {
	nMaxGroup = Bars / nGroupBar;
    }
    nMaxGroup = MathMax(nMaxGroup, 1);
    
    yOffset *= Point;
}

// // 
// //  H 10      +
// //          o | o
// //        o   |   o
// //  O 7 o-----+     o
// //      |     |       o
// //  C 5 |     |         o               o
// //      |     |           o           o |
// //      |     |             o       o   |
// //      |     |               o   o     |
// //  L 1 +-----+-----------------+-------+
// //      |H-O   H-L               C-L    |   H-O+H-L+C-L= 2H - 2L - (O - C)
// //      |                               |
// //    0 +-------------------------------+
// // 
// //     2H - 2L - O + C
// //   = 20 - 2  - 7 + 5
// //   = 16
// //
// //     (H-O)*(H-O)/2 + (O-L)*(H-O) + (H-L)*(H-L)/2 + (C-L)*(C-L)/2
// //   = HH/2 - OH + OO/2  + OH -OO -LH + LO + HH/2 - LH + LL/2 + CC/2 - CL + LL/2
// //   = HH + LL - OO/2 + CC/2 - 2HL + LO - CL + 2HL - 2LL - LO + LC
// //   = (HH - LL) - (OO - CC)/2
// //   = 100 - 1 - 49/2 + 25/2
// //   = 87
// //     87/16= 5.4375
// // 
// // 
// // 
// //  H 10                          +
// //                              o | o
// //                            o   |   o
// //  C 7                     o     +-----o
// //                        o       |     |
// //  O 5 o               o         |     |
// //      | o           o           |     |
// //      |   o       o             |     |
// //      |     o   o               |     |
// //  L 1 +-------+-----------------+-----+
// //      |O-L      H-L              H-C  |   O-L+H-L+H-C= 2H - 2L + (O - C)
// //      |                               |
// //    0 +-------------------------------+
// //
// //     (O-L)*(O-L)/2 + (H-L)*(H-L)/2 + (H-C)*(H-C)/2 + (H-C)*(C-L)
// //    = OO/2 - OL + LL/2 + HH/2 - HL + LL/2 + HH/2 - HC + CC/2 + HC - HL - CC + CL
// //    = OO/2 - OL + LL + HH - HL - CC/2 - HL + CL
// //    = HH + LL + OO/2 - CC/2 - 2HL - LO + CL +    LO - LL + LH - LL + LH - LC
// //    = HH - LL + (OO - CC)/2
// //    = 100 - 1 + 25/2 - 49/2
// //    = 87
// //      87/16= 5.4375

// x2 downer
// 
//  H 10      +
//          o | o
//        o4.5|   o
//  O 7 o-----+     o
//      |     |       o
//  C 5 | 18  |         o               o
//      |     | 9*4.5/2   o           o |
//      |     | =20.25      o       o   |
//      |     |               o   o  8  |
//  L 1 +-----+-----------------+-------+
//      |H-O   (H-L)/2           C-L    | = (H - L)3/2 - (O + C)
//      |(3)   (4.5)   11.5      (4)    | area= 54.25
//    0 +-------------------------------+
// 
//     (H-O)+(H-L)/2+(C-L)
//   = 3 + 4.5 + 4
//   = 11.5
//
//     (H-O)*(H-O)/2 + (O-L)*(H-O) + (H-L)*(H-L)/2/2 + (C-L)*(C-L)/2 + L*((H-O)+(H-L)/2+(C-L))
//   = HH/2 - OH + OO/2  + OH -OO -LH + LO + HH/4 - LH/2 + LL/4 + CC/2 - CL + LL/2   + LH3/2-LO-LL3/2+LC
//   = HH3/4 + LL3/4 - OO/2 + CC/2 - LH3/2 + LO - CL + LH3/2 - LO - LL3/2 + LC
//   = (HH - LL)3/4 - (OO - CC)/2
//   = 300/4 - 3/4 - 49/2 + 25/2
//   = 62.25
//     62.25 / 11.5= 5.41304347826086956521
// 
// 
//  H 10                          +
//                              o | o
//                            o   |4.5o
//  C 7                     o     +-----o
//                        o       |     |
//  O 5 o               o         |     |
//      | o           o  9*4.5/2  | 18  |
//      |   o       o   =20.25    |     |
//      | 8   o   o               |     |
//  L 1 +-------+-----------------+-----+
//      |O-L      (H-L)/2          H-C  | = (H - L)3/2 + (O - C)
//      |(4)      (4.5)    11.5    (3)  |
//    0 +-------------------------------+
//
//     (O-L)*(O-L)/2 + (H-L)*(H-L)/2/2 + (H-C)*(H-C)/2 + (H-C)*(C-L) + L*((O-L)+(H-L)/2+(H-C))
//    = OO/2 - OL + LL/2 + HH/4 - HL/2 + LL/4 + HH/2 - HC + CC/2 + HC - HL - CC + CL + LO - LL - HL/2 - LL/2 + LH - CL
//    = (HH - LL)3/4 + (OO  - CC)/2
//    = 300/4 - 3/4 + 25/2 - 49/2
//    = 62.25

//----------------------------------------------------------------------
double calcAve(double o, double h, double l, double c)
{
    double area = (h * h - l * l) * 0.75 - MathAbs(o * o - c * c) / 2.0;
    double len = (h - l) * 1.5 - MathAbs(o - c);
    double ave = o;
    if (len != 0) {
	ave = area / len;
    }
    
    return(ave);
}

// 
// |         |         |
// +-+-+-+-+-+-+-+-+-+-+
//  9 8 7 6 5 4 3 2 1 0    nGroupBar = 5
//            s       ibar
// 
//----------------------------------------------------------------------
void setupData(int ibar)
{
    int s = ibar + nGroupBar - 1;
    
    double open  = Open[s];
    double high  = High[s];
    double low   = Low[s];
    double close = Close[s];
    
    g_open  = open;
    g_high  = high;
    g_low   = low;
    g_close = Close[ibar];
    g_ave   = 0.0;
    
    for (int i = 0; i < nGroupBar; i++) {
	int x = s - i;
	open  = Open[x];
	high  = High[x];
	low   = Low[x];
	close = Close[x];
	g_ave += calcAve(open, high, low, close);
	
	if (high > g_high) {
	    g_high = high;
	}
	if (low < g_low) {
	    g_low = low;
	}
    }
    
    g_ave /= nGroupBar;
    
    if (yOffset != 0) {
	g_open  += yOffset;
	g_high  += yOffset;
	g_low   += yOffset;
	g_close += yOffset;
	g_ave   += yOffset;
    }
}

//----------------------------------------------------------------------
void start()
{
    int limit;
    int counted_bars = IndicatorCounted();
    
    if (counted_bars > 0) {
	counted_bars--;
    }
    
    limit = Bars - counted_bars;
    
//
//     |     |     | |
// +-+-+-+-+-+-+-+-+-+
//  8 7|6 5 4|3 2 1|0|   nGroupBar = 3
//          ^     ^
//          ibar1 ibar0
    
    // clear previous
    int nBars = nMaxGroup * nGroupBar;
    for (int i = MathMax(limit - 1, nBars + 1); i > nBars; i--) {
	BufferHaLow[i]   = 0;
	BufferHaHigh[i]  = 0;
	BufferHaOpen[i]  = 0;
	BufferHaClose[i] = 0;
	BufferHaDir[i]   = 0;
    }
    
    // calc
    int ibar0, ibar1;
    for (int g = nMaxGroup; g >= 0; g--) {
	if (g > 0) {
	    ibar0 = (g - 1) * nGroupBar + 1;
	    ibar1 = ibar0 + nGroupBar;
	} else {
	    ibar0 = 0;
	    ibar1 = 1;
	}
	
	setupData(ibar0);
	double haOpen  = (BufferHaOpen[ibar1] + BufferHaClose[ibar1]) * 0.5;
	double haClose = g_ave;
	if (g == nMaxGroup) {
	    haOpen = haClose;
	}
	double haHigh = MathMax(g_high, MathMax(haOpen, haClose));
	double haLow  = MathMin(g_low,  MathMin(haOpen, haClose));
	double haDir  = haClose - haOpen;
	
	if (haOpen < haClose) {
	    BufferHaLow[ibar0]  = haLow;
	    BufferHaHigh[ibar0] = haHigh;
	} else {
	    BufferHaLow[ibar0]  = haHigh;
	    BufferHaHigh[ibar0] = haLow;
	} 
	BufferHaOpen[ibar0]  = haOpen;
	BufferHaClose[ibar0] = haClose;
	BufferHaDir[ibar0]   = haDir;
	
	// copy
	haLow   = BufferHaLow[ibar0];
	haHigh  = BufferHaHigh[ibar0];
	haOpen  = BufferHaOpen[ibar0];
	haClose = BufferHaClose[ibar0];
	
	if (g > 0) {
	    for (i = nGroupBar - 1; i >= 0; i--) {
		BufferHaLow[ibar0 + i]   = haLow;
		BufferHaHigh[ibar0 + i]  = haHigh;
		BufferHaOpen[ibar0 + i]  = haOpen;
		BufferHaClose[ibar0 + i] = haClose;
		BufferHaDir[ibar0 + i]   = haDir;
	    }
	}
    }
}
