//+------------------------------------------------------------------+
//|                                                  ay-DynValue.mq4 |
//|                      Copyright © 2011, MetaQuotes Software Corp. |
//|                                        http://www.metaquotes.net |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2011, MetaQuotes Software Corp."
#property link      "http://www.metaquotes.net"

#property indicator_chart_window
#property indicator_buffers 6
#property indicator_color1 C'20,20,65'
#property indicator_color3 Aqua
#property indicator_color4 Maroon
#property indicator_color5 Maroon
#property indicator_color6 Maroon
#property indicator_style1 STYLE_SOLID
#property indicator_style2 STYLE_SOLID


#define MAXCALCTIME  1500
#define IND_NAME     "ay-DynValue.dll.v2.2"
#define IDX_SBT      0
#define IDX_EBT      1
#define IDX_VAH      2
#define IDX_VAL      3
#define IDX_POC      4

/******************************************************************\\\
 * MP Library 
 * dont change anything in this mp library block, unless YKWYD.....
 ******************************************************************///
#include <ay-mplib.const.v103a.mqh> 

#import "p01.dll"
   void mt4MpGet
   (   
         double      dparam     [MPDPSIZE]
       , int         iparam     [MPIPSIZE]
       , double      arates     [][6]
       , double&     mpdatarow  [][MPSIZE]    //--result: data per row (price, tpo, vol, pir)     
       , int&			mplinesidx [MPLNSIZE]    //--result: lines index
       , double&		mptotal    [MPTSIZE]     //--result: total (tpo, vol)
       , int&			mpletter   [][MPLTSIZE]  //--result: letter per row 	
	    
   );   
   //void mt4CrashTest(int arr);
#import
/******************************************************************\\\
 * End MP Library 
 ******************************************************************///
 
//--- input parameters
extern int       LookBack         = 1000;
extern string    info1            = "240=H4, 1440=D1, 7200=5 Days etc..";
extern int       ProfileTf        = 1440;
extern string    info2            = "1=M1, 5=M5, 15=M15 etc..";
extern int       ProfileData      = 5;
extern int       AverageVA        = 1;
extern bool      LoadDataFromFile = true;

//---- buffers
double ExtMapBuffer1[];
double ExtMapBuffer2[];
double ExtMapBuffer3[];
double ExtMapBuffer4[];
double ExtMapBuffer5[];
double ExtMapBuffer6[];

double BuffVah[], BuffVal[];


double   gdPoint
       , gdRowtHeight
       , gdOneTick
       , gdaRates[][6];
       
int      giPeriod, giRowSize, giDigits;

int    LastCalcBar = -1, giRowHeight = 1;
double gdaIndiData     [/*LookBack*/][5/*starttime,endtime,vah,val,poc*/];
double gdaIndiDataSaved[/*LookBack*/][5/*starttime,endtime,vah,val,poc*/];
string gsIndiDataFN;
bool   gbDataNotFound = true;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
         
   ArrayResize(BuffVah, LookBack);
   ArrayResize(BuffVal, LookBack);
   
   ArraySetAsSeries(BuffVah, true);
   ArraySetAsSeries(BuffVal, true);
   
   SetIndexStyle(0,DRAW_HISTOGRAM, EMPTY, EMPTY);
   SetIndexStyle(1,DRAW_HISTOGRAM, EMPTY, EMPTY);
   SetIndexStyle(2,DRAW_ARROW); SetIndexArrow(2,158);
   SetIndexStyle(3,DRAW_LINE);
   SetIndexStyle(4,DRAW_LINE);
   SetIndexStyle(5,DRAW_LINE);
   
   
   SetIndexBuffer(0,ExtMapBuffer1);
   SetIndexBuffer(1,ExtMapBuffer2);
   SetIndexBuffer(2,ExtMapBuffer3);
   SetIndexBuffer(3,ExtMapBuffer4);
   SetIndexBuffer(4,ExtMapBuffer5);
   SetIndexBuffer(5,ExtMapBuffer6);
   
   SetIndexLabel(0, NULL);
   SetIndexLabel(1, NULL);
   SetIndexLabel(2, "POC");
   SetIndexLabel(3, "VAH AVG(" + AverageVA + ")");
   SetIndexLabel(4, "MIDVA AVG(" + AverageVA + ")");
   SetIndexLabel(5, "VAL AVG(" + AverageVA + ")");
   
   ArrayCopyRates(gdaRates, NULL, ProfileData);
   
   if (Point == 0.001 || Point == 0.00001) 
   { gdPoint = Point*10; giDigits = Digits - 1; }
   else 
   { gdPoint = Point; giDigits = Digits; }     
   
   gdOneTick = 1/MathPow(10, giDigits);   
   giRowSize = MathMax(1, giRowHeight);   
   giPeriod  = ProfileTf/Period();   
   
   string path = strReplace(TerminalPath(), ":", "");
          path = strReplace(path, " ", "");
          path = strReplace(path, "\\", ".");
      
   gsIndiDataFN = StringConcatenate(
        path
      , ".DV."
      , Symbol(), "."      
      , Period(), "."      
      , ProfileTf, "."
      , ProfileData, "."
      , giRowHeight, ".dat"
      );
      
   ArrayResize(gdaIndiData, LookBack); 
   ArrayResize(gdaIndiDataSaved, LookBack); 
   
   if (LoadDataFromFile) readIndiData();        

   //Print("Data File : ", gsIndiDataFN);

   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
  {
//----
   Comment("");
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
{
   static bool isbusy;
   
   if (isbusy || !isHystoryOK() ) return(0);   
   
   isbusy = true;
      
   int      i, j, limit
            , counted_bars = IndicatorCounted()
            , starttime    = GetTickCount()
            , calctime
            ;
   datetime dtsb, dteb;      
      
//---- last counted bar will be recounted
   if(counted_bars>0) counted_bars--;
   limit = Bars-counted_bars-1;
   
   limit = MathMin(limit, LookBack);
   limit = MathMax(LastCalcBar, limit);

   //-->MpGet Vars
   double     hh, ll
            , drowsize = (giRowSize/1.0) * gdOneTick
            , rhh  //round hh to giRowHeight
            , rll  //round ll to giRowHeight
            , rg = (giRowSize/1.0)/MathPow(10,giDigits)
            ; 
   int        startbar, endbar;    
   double     mpdata  [][MPSIZE];
   int        mplines   [MPLNSIZE];
   double     mptotal   [MPTSIZE];
   int        mpletter[][MPLTSIZE];   
   double     dparam  [MPDPSIZE];
   int        iparam  [MPIPSIZE];      
   int        ratessize = ArraySize(gdaRates)/6
            , rowcount; 
   //<--MpGet Vars        
      
   bool bardatafound;
   for(i=limit-1; i>=0; i--)
   {         
      dtsb     = Time[ i + (giPeriod-1) ];
      dteb     = Time[i] + (Period()*60 - 1);
      startbar = iBarShift(NULL, ProfileData, dtsb );      
      endbar   = iBarShift(NULL, ProfileData, dteb );

      bardatafound = false;
      
      if (i>0 && LoadDataFromFile && !gbDataNotFound )
      {         
         for (j=LookBack-1; j>0; j--) 
         {        
            if (  gdaIndiDataSaved[j][IDX_SBT] == dtsb
               && gdaIndiDataSaved[j][IDX_EBT] == dteb)
            {                 
               if (  gdaIndiDataSaved[j][IDX_VAH] > 0.0 
                  && gdaIndiDataSaved[j][IDX_VAL] > 0.0 
                  && gdaIndiDataSaved[j][IDX_POC] > 0.0)
               {
                  bardatafound = true;
                  ExtMapBuffer1[i] = gdaIndiDataSaved[j][IDX_VAH];
                  ExtMapBuffer2[i] = gdaIndiDataSaved[j][IDX_VAL];
                  ExtMapBuffer3[i] = gdaIndiDataSaved[j][IDX_POC];                  
               }
               break;                                    
            }      
         }                  
      }
      
      if (!bardatafound)
      {           
         //-->Prepare data for library fn call
         getHHLL
         (
              ProfileData     //int       tf
            , startbar        //int       sb
            , endbar          //int       eb
            , hh              //double&   hh
            , ll              //double&   ll
         );      
      
         rhh = MathCeil(hh/rg) * rg;
         rll = MathCeil(ll/rg) * rg;
         if (rhh < hh) rhh += rg;
         if (rll > ll) rll -= rg;            
      
         rowcount =  MathRound( (rhh - rll)/drowsize ) ;   
   
         dparam[MPDP_ONETICK]    = gdOneTick;
         dparam[MPDP_ROWSIZE]    = drowsize;
         dparam[MPDP_HH]         = rhh;
         dparam[MPDP_LL]         = rll;
         dparam[MPDP_VAPERCENT]  = 70.0;//VAPercent;

         iparam[MPIP_STARTBAR]   = startbar;
         iparam[MPIP_ENDBAR]     = endbar;
         iparam[MPIP_DIGITS]     = giDigits;   
         iparam[MPIP_ROWCOUNT]   = rowcount;
         iparam[MPIP_RATESIZE]   = ratessize;
         
         ArrayResize(mpdata, rowcount);
         ArrayResize(mpletter, rowcount);
   
         ArrayInitialize(mpdata, 0.0);
         ArrayInitialize(mpletter, MPNOIDX); 
         //<--Prepare data for library fn call
      
         //----      
         mt4MpGet(dparam, iparam, gdaRates, mpdata, mplines, mptotal, mpletter);  
         //----            
      
         ExtMapBuffer1[i] = mpdata[ mplines[MPL_TPOVAH] ][MP_PRICE];
         ExtMapBuffer2[i] = mpdata[ mplines[MPL_TPOVAL] ][MP_PRICE];
         ExtMapBuffer3[i] = mpdata[ mplines[MPL_TPOPOC] ][MP_PRICE];
      }
      
      gdaIndiData[i][IDX_SBT] = dtsb;
      gdaIndiData[i][IDX_EBT] = dteb;
      gdaIndiData[i][IDX_VAH] = ExtMapBuffer1[i];
      gdaIndiData[i][IDX_VAL] = ExtMapBuffer2[i];
      gdaIndiData[i][IDX_POC] = ExtMapBuffer3[i];
      
      BuffVah[i] = ExtMapBuffer1[i];
      BuffVal[i] = ExtMapBuffer2[i];   
              
      calctime    = GetTickCount() - starttime ;
      LastCalcBar = i;
      if (calctime > MAXCALCTIME && LastCalcBar > 0  )
      {         
         Comment (
              "\n\n", IND_NAME, ", Lazy Load Activated"
            , "\n============================================"
            , "\nMaxCalcTime(", MAXCALCTIME, ") Reached by ", calctime 
            , " msec, last calculated bar: ", LastCalcBar
            , "\nWaiting for next tick to resume....."
            , "\nor just run 7bit-TickUpdate script....."
            );            
         break;
      }            
   }   
   
   for(i=MathMin(limit-1, LookBack-AverageVA); i>=LastCalcBar; i--)
   {
      ExtMapBuffer4[i] = iMAOnArray(BuffVah, 0, AverageVA, 0, MODE_SMA, i); 
      ExtMapBuffer5[i] = iMAOnArray(BuffVal, 0, AverageVA, 0, MODE_SMA, i); 
      ExtMapBuffer6[i] = (ExtMapBuffer4[i]+ExtMapBuffer5[i])/2.0;
   }   
   
   if (LastCalcBar == 0 )
   {
      Comment(
        "\n\n", IND_NAME, " (", ProfileTf,"/",ProfileData,")"
      , "\n====================="
      , "\nLast Calculation\'s Time: ", calctime, " msec"
      );
      
      if (isNewBar()) saveIndiData();
   }

   isbusy = false;
            
   return(0);
}
      
/**
 *getHHLL                                                          
*/
void getHHLL
(
     int       tf
   , int       sb
   , int       eb
   , double&   hh
   , double&   ll
)
{
   hh = iHigh ( NULL, tf, iHighest(NULL, tf, MODE_HIGH, (sb-eb)+1, eb) );
   ll = iLow  ( NULL, tf, iLowest (NULL, tf, MODE_LOW,  (sb-eb)+1, eb) );
}   


bool isNewBar()
{
   static datetime LastBar;
   datetime CurrBar = Time[0];

   if(LastBar != CurrBar)
   {
      LastBar = CurrBar;
      return (true);
   }
   return(false);  
}

bool isHystoryOK()
{
   int bars, err, lasterr = GetLastError()/*reset last error value*/;

   bars = ArrayCopyRates(gdaRates, NULL, ProfileData);      
   err  = GetLastError();   
      
   if (err==0) return(true);
   else        return(false);
}

void saveIndiData()
{
   int size   = LookBack*5;
   int handle = FileOpen(gsIndiDataFN, FILE_BIN|FILE_WRITE);
      
   if(handle>0)
   {
      FileWriteArray(handle, gdaIndiData, 0, size); 
      FileClose(handle);
   } 
   
}

void readIndiData()
{
   
   int size   = LookBack*5;
   int handle = FileOpen(gsIndiDataFN, FILE_BIN|FILE_READ);     
    
   if(handle>0)
   {   
      ArrayResize(gdaIndiDataSaved, LookBack);
      FileReadArray(handle, gdaIndiDataSaved, 0, size);
      FileClose(handle);
      gbDataNotFound = false;
   } 
   else gbDataNotFound = true; 
}

string strReplace(string str, string csearch, string creplace)
{
   int pos, loop;

   for(;;)
   {
      pos = StringFind(str, csearch, 0);      
      if (pos == -1) return(str);
      
      str = StringConcatenate
       ( 
         StringSubstr(str, 0, pos)
         , creplace
         , StringSubstr(str, pos+StringLen(csearch), StringLen(str)-pos)
       );      
       
      //--safety :)
      if (loop>StringLen(str)) return(str);
      loop++;
   }
}       