//+------------------------------------------------------------------+
//|                                                         GR-1.mq4 |
//|                        Copyright 2014, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2014, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"
#property strict
#property indicator_chart_window
#include <ChartObjects\ChartObjectsTxtControls.mqh>
#define X_SP   30
#define Y_SP   15
#define BOOL_LBL "H-L / L-C"
#define BEAR_LBL "H-L / H-C"
//--- input parameters
input int      ar_period=20;
input int      x_off=500;
input int      y_off=30;
input color    txt_clr=clrBlack;

struct lbl
{
  string id;
  string dsc;
};

lbl lbls[] = {{"SIZE","ATR / H-L"},
              {"BODY","ADR / O-C"},
              {"SHADOWS","BDY / SHD"},
              {"CLOSE","H-L / C"}};
CChartObjectLabel* objs[][3];

bool g_tab_changed = true;
datetime g_last_time = 0;
double g_pt_scale = 1;
//+------------------------------------------------------------------+
void Arrange()
{
  for (int i=0; i < ArrayRange(objs,0); i++)
    for (int j=1; j < ArrayRange(objs,1); j++)
      objs[i,j].X_Distance(GetDistance(j-1)+X_SP);
  g_tab_changed=false;
}
//+------------------------------------------------------------------+
int GetDistance(int col)
{
  int result=0;
  for (int i=0; i < ArrayRange(objs,0); i++)
    if ((objs[i,col].X_Distance()+objs[i,col].X_Size()) > result)
      result=objs[i,col].X_Distance()+objs[i,col].X_Size();
  return(result);
}
//+------------------------------------------------------------------+
bool CreateLabels()
{
  bool result=true;

  ArrayResize(objs,ArraySize(lbls));
  for (int j=0; j < ArrayRange(objs,1); j++)
  {
    for (int i=0; i < ArraySize(lbls); i++)    
    {
      objs[i,j]=new CChartObjectLabel();
      objs[i,j].Corner(CORNER_LEFT_UPPER);
      result=objs[i,j].Create(0,lbls[i].id+(string)j,0,0,0);
      if (!result)
        break;
      objs[i,j].Color(txt_clr);
      if (j==0)
        objs[i,j].Description(lbls[i].dsc);
      else
        objs[i,j].Description("|");
      if (j==0)
      {
        objs[i,j].X_Distance(x_off);
        objs[i,j].Y_Distance(y_off+(objs[i,j].Y_Size()+Y_SP)*i);
      }
      else
      {
        objs[i,j].X_Distance(GetDistance(j-1)+X_SP);
        objs[i,j].Y_Distance(objs[i,j-1].Y_Distance());
      }
    }
    if (!result)
      break;
  }
  return(result);
}
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
//--- indicator buffers mapping
  if (!CreateLabels())
    return(INIT_FAILED);
  if ((Digits==5) || (Digits==3))
    g_pt_scale=10;
  else
    g_pt_scale=1;
  g_tab_changed=true;
//---
  return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
  for (int i=0; i < ArrayRange(objs,0); i++)
    for (int j=0; j < ArrayRange(objs,1); j++)
    {
      if (CheckPointer(objs[i,j]) == POINTER_DYNAMIC)
        delete objs[i,j];
      objs[i,j]=NULL;
    }
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
//---
  if (g_tab_changed)
    Arrange();
  ArraySetAsSeries(time,true);
  if (time[0] == g_last_time)
    return(rates_total);
  if (rates_total < ar_period+2)
    return(rates_total);
  ArraySetAsSeries(open,true);
  ArraySetAsSeries(close,true);
  ArraySetAsSeries(high,true);
  ArraySetAsSeries(low,true);
  
  double atr=0, adr=0, bdy=0, cndl=0, shd=0, cl=0;
  
  for (int i=2; i < ar_period+2; i++)
  {
    atr+=MathAbs(high[i]-low[i]);
    adr+=MathAbs(open[i]-close[i]);
  }
  atr/=ar_period*Point*g_pt_scale;
  adr/=ar_period*Point*g_pt_scale;
  cndl=MathAbs(high[1]-low[1])/Point/g_pt_scale;
  bdy=MathAbs(open[1]-close[1])/Point/g_pt_scale;
  objs[0,1].Description(DoubleToString(atr,1)+" / "+DoubleToString(cndl,1));
  objs[0,2].Description(DoubleToString(cndl/atr*100,1)+"%");
  objs[1,1].Description(DoubleToString(adr,1)+" / "+DoubleToString(bdy,1));
  objs[1,2].Description(DoubleToString(bdy/adr*100,1)+"%");
  shd=cndl-bdy;
  objs[2,1].Description(DoubleToString(bdy,1)+" / "+DoubleToString(shd,1));
  objs[2,2].Description(DoubleToString(shd/bdy*100,1)+"%");
  if (close[1] > open[1])
  {
    objs[3,0].Description(BOOL_LBL);
    cl=(close[1]-low[1])/Point/g_pt_scale;
  }
  else
  {
    objs[3,0].Description(BEAR_LBL);
    cl=(high[1]-close[1])/Point/g_pt_scale;
  }
  objs[3,1].Description(DoubleToString(cndl,1)+" / "+DoubleToString(cl,1));
  objs[3,2].Description(DoubleToString(cl/cndl*100,1)+"%");
  
  g_tab_changed=true;
  g_last_time=time[0];
//--- return value of prev_calculated for next call
  return(rates_total);
}
//+------------------------------------------------------------------+
