//+------------------------------------------------------------------+
//|                                                  ay-mplib100.mq4 |
//|                      Copyright © 2011, MetaQuotes Software Corp. |
//|                                        http://www.metaquotes.net |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2011, MetaQuotes Software Corp."
#property link      "http://www.metaquotes.net"
#property library
//+------------------------------------------------------------------+
//| My function                                                      |
//+------------------------------------------------------------------+
// int MyCalculator(int value,int value2)
//   {
//    return(value+value2);
//   }
//+------------------------------------------------------------------+
#include <ay-mplib.const.mqh> 

//RATE INFO
#define _TIME                    0
#define _OPEN                    1
#define _LOW                     2
#define _HIGH                    3
#define _CLOSE                   4
#define _VOL                     5

void MpGet
   (
   
        double    dparam[4]
      , int       iparam[2]
      , double    arates[][6]
      , double&   mpdata[][MPSIZE]        //result: data
      , int&      mplinesidx[MPLNSIZE]    //result: lines index
      , double&   mptotal[MPTSIZE]        //result: total (tpo, vol)
      , int&      mpletter[][MPLTSIZE]    //result: letter  
   )
{

   //-->extract params
   double     hh           = dparam[MPDP_HH]
            , ll           = dparam[MPDP_LL]
            , onetick      = dparam[MPDP_ONETICK]
            , vapercent    = dparam[MPDP_VAPERCENT]
            ;
            
   int        startbar     = iparam[MPIP_STARTBAR]
            , endbar       = iparam[MPIP_ENDBAR]            
            ;
   //<--extract params   
    
   double   sp = hh;    //start price      
   double   midrangeprice = hh - (hh-ll)/2.0;     
   double   price; 
   double   barhp;         // bar high price
   double   barlp;         // bar low price
   double   barrange;      // bar range
   double   pipvol;        // volume per pip in bar range
   double   totaltpo, totalvol, maxtpo, maxvol;
   int      i, j; 
   int      maxtpoidx, maxvolidx;       
   int      datasize = MathRound((hh - ll)/onetick) + 1;  
         
   ArrayResize(mpdata, datasize);
   ArrayInitialize(mpdata, 0.0);
   
   ArrayResize(mpletter, datasize);
   ArrayInitialize(mpletter, MPNOIDX);
   
   ArrayInitialize(mplinesidx, MPNOIDX);
   
   ArrayInitialize(mptotal, 0.0);
   
   
   //-->profile price level
   for (i=0; i<datasize; i++)
   {
      mpdata[i][MP_PRICE] = sp;
      sp -= onetick;
   }
   //<--profile price level   
   
   //-->calculate profile tpo, vpo, letter
   for (i=0; i<datasize; i++)
   {
      price = mpdata[i][MP_PRICE];

      int letteridx=0;
      int barnum=0;
      
      for (j=startbar; j>=endbar; j--)
      {
         barhp    = arates[j][_HIGH];
         barlp    = arates[j][_LOW];
         barrange = MathMax( barhp - barlp, onetick ) / onetick;
         pipvol   = MathMax( arates[j][_VOL] / barrange, 0.000001 ); 
         //-->tpo, vpo, totaltpo, totalvol, letter         
         if ( price <= barhp && price >= barlp )   
         {
            mpdata[i][MP_TPO] += 1.0;
            mpdata[i][MP_VOL] += pipvol;
            totaltpo += 1.0; 
            totalvol += pipvol;
                        
            if (letteridx < MPLTSIZE) mpletter[i][letteridx] = barnum;
            
            letteridx++;
         }
         barnum++;
         //<--tpo, vpo, totaltpo, totalvol, letter
         
         // save maxtpo
         if ( mpdata[i][MP_TPO] > maxtpo) 
         {
            maxtpo    = mpdata[i][MP_TPO];
            maxtpoidx = i;               
         }
            
         if (mpdata[i][MP_VOL] == maxtpo) 
         {
            // take the closes to the middle of profile range
            if (  MathAbs(midrangeprice - mpdata[i][MP_PRICE]) 
                  < MathAbs(midrangeprice - mpdata[maxtpoidx][MP_PRICE]) 
               )
            {
               maxtpo    = mpdata[i][MP_VOL];
               maxtpoidx = i;
            }
         }
         // end save maxtpo
            
         // save maxvol
         if (mpdata[i][MP_VOL] > maxvol) 
         {
            maxvol    = mpdata[i][MP_VOL];
            maxvolidx = i;               
         }
            
         if (mpdata[i][MP_VOL] == maxvol) 
         {
            // take the closes to the middle of profile range
            if (   MathAbs(midrangeprice - mpdata[i][MP_PRICE]) 
                  < MathAbs(midrangeprice - mpdata[maxvolidx][MP_PRICE]) 
               )
            {
               maxvol    = mpdata[i][MP_VOL];
               maxvolidx = i;
            }
         }
         // end save maxvol   
         
      }
   }

   mplinesidx[MPL_TPOPOC] = maxtpoidx;
   mplinesidx[MPL_VOLPOC] = maxvolidx;

   mptotal[MPT_TPO] = totaltpo;
   mptotal[MPT_VOL] = totalvol;   
   
   //<--calculate profile tpo, vpo, letter      
   
   //-->calculate value area
   bool usevol = false;
   int vahidx, validx;
   for (i=0; i<2; i++)
   {                     
      vahidx=0; validx=0;
      if (i==1) usevol = true;
      
      _MPGetValueArea
      (        
           usevol
         , vapercent
         , datasize
         , mpdata
         , maxtpo
         , maxtpoidx      
         , totaltpo
         , maxvol
         , maxvolidx
         , totalvol
         , vahidx
         , validx
      );
      
      if (usevol)
      {
         mplinesidx[MPL_VOLVAH] = vahidx;
         mplinesidx[MPL_VOLVAL] = validx;    
              
      }
      else
      {
         mplinesidx[MPL_TPOVAH] = vahidx;
         mplinesidx[MPL_TPOVAL] = validx;   
      }
   }
   //<--calculate value area
               
}

/**
 * MPGetValueArea                                                   |
 * Private func                                             
 */
void _MPGetValueArea
(
     bool         usevolprofile
   , double       vapercent
   , int          datasize
   , double       mpdata[][3]
   , double       maxtpo
   , int          maxtpoidx      
   , double       totaltpo
   , double       maxvol
   , int          maxvolidx
   , double       totalvol
   , int          &vahidx
   , int          &validx
)
{

   int    idx     = maxtpoidx; if(usevolprofile) idx = maxvolidx;   
   double total   = totaltpo;  if(usevolprofile) total = totalvol;
   double vatvpo  = (vapercent/100.0) * total;      
   double tvpo    = mpdata[idx][MP_TPO]; if (usevolprofile) tvpo = mpdata[idx][MP_VOL];   

   int     upperidx_dp     = idx //dual prices(2 steps), upper poc 
         , loweridx_dp     = idx //dual prices(2 steps), lower poc   
         , lastupperidx    = idx
         , lastloweridx    = idx;    
         
   bool ontop=false, onbottom=false;
   //int    loop=0;
   
   while (tvpo <= vatvpo)   
   {      
      //if (loop >= datasize) break;

      //new dual prices idx
      if ( lastupperidx >= 1)                  upperidx_dp = lastupperidx - 2;
      if ( lastloweridx <= (datasize-1) - 1 )  loweridx_dp = lastloweridx + 2;          
      //end new dual prices idx

      double utvpo1 = mpdata[ upperidx_dp+1 ][MP_TPO]; 
      if (usevolprofile) utvpo1 = mpdata[ upperidx_dp+1 ][MP_VOL]; 
      
      double ltvpo1 = mpdata[ loweridx_dp-1 ][MP_TPO]; 
      if (usevolprofile) ltvpo1 = mpdata[ loweridx_dp-1 ][MP_VOL]; 

      double utvpo2 = mpdata[ upperidx_dp ][MP_TPO]; 
      if (usevolprofile) utvpo2 = mpdata[ upperidx_dp ][MP_VOL];
      
      double ltvpo2 = mpdata[ loweridx_dp ][MP_TPO]; 
      if (usevolprofile) ltvpo2 = mpdata[ loweridx_dp ][MP_VOL];     
      
      //-->check if vatvo reached by single step 
      
      if ( (tvpo + utvpo1) >= vatvpo || (tvpo + ltvpo1) >= vatvpo )
      {
         if (  utvpo1 >= ltvpo1 )
         {
            lastupperidx = upperidx_dp+1;
            tvpo += utvpo1;      
            break;
         }
         else         
         {
            lastloweridx = loweridx_dp-1;
            tvpo += ltvpo1;
            break;
         }                     
      }
      
      //<--check if vatvo reached by single step      

      //override if...      
      if (ontop)    {utvpo1=0;utvpo2=0;}
      if (onbottom) {ltvpo1=0;ltvpo2=0;}      

      //2 step prices
      double tvpo2upper = utvpo1 + utvpo2;
      double tvpo2lower = ltvpo1 + ltvpo2;
      
      if (  tvpo2upper > tvpo2lower 
         )
      {
         lastupperidx = upperidx_dp;
         tvpo += tvpo2upper;
      }
      else
      if (  tvpo2upper < tvpo2lower )
      {
         lastloweridx = loweridx_dp;
         tvpo += tvpo2lower;
      }
      else 
      if ( tvpo2upper == tvpo2lower )
      {
         if (idx - upperidx_dp >= loweridx_dp - idx)
         {
            lastloweridx = loweridx_dp;
            tvpo += tvpo2lower;   
         }
         else
         {     
            lastupperidx = upperidx_dp;
            tvpo += tvpo2upper;
         }
      
      }

      if (lastupperidx <= 1) ontop = true;
      if (lastloweridx >= (datasize-1) - 1 ) onbottom = true;

      //loop++;
   }//end  while (tvpo <= vatvpo)
   
   vahidx = lastupperidx;
   validx = lastloweridx;

}

