//+------------------------------------------------------------------+
//|                                      VSA Teacher Volume v03.2mq4 |
//|                                      Copyright © 2009, Chief1Oar |
//|                                            Chief1Oar@hotmail.com |
//+------------------------------------------------------------------+

//--------------------------------------------------
// Messages
//    1. "Ultra Low Volume "
//    2. "Low Volume"
//    3. "Low Volume > Prev 2 "
//    4. "Low Volume < Prev 2 "
//    5. "Normal Volume"
//    6. "Normal Volume > Prev 2 "
//    7. "Normal Volume < Prev 2 "
//    8. "HigH Volume"
//    9. "High Vol > Prev 2"
//   10. "High Vol < Prev 2"
//   11. "Very High Volume"
//   12. "Very High Vol > Prev 2"
//   13. "Very High Vol < Prev 2"
//   14. "Ultra High Volume - CAUTION"
//
//--------------------------------------------------
#property copyright "Copyright © 2009, Chief1Oar"
#property link      "Chief1Oar@hotmail.com"


#property indicator_separate_window
#property indicator_minimum 0
#property indicator_buffers 8

#property indicator_color1 Yellow
#property indicator_style1 DRAW_HISTOGRAM
#property indicator_width1 3

#property indicator_color2 Orange
#property indicator_style2 DRAW_HISTOGRAM
#property indicator_width2 3

#property indicator_color3 Blue 
#property indicator_style3 DRAW_HISTOGRAM
#property indicator_width3 3

#property indicator_color4 Teal
#property indicator_style4 DRAW_HISTOGRAM
#property indicator_width4 3

#property indicator_color5 Red
#property indicator_style5 DRAW_HISTOGRAM
#property indicator_width5 3

//*************************************

//----   User Inputs
//extern   bool  blackBackground = false;

extern   int   CurrVolumeFont = 12;
extern   string a1 = "  To disable Text select False";
extern   bool  ShowText = true;
extern   int   LastVolumeFont=12;
extern   int   TextFont=9;
extern   int   TextSpacing=20;
extern   string a2 = "  Number of Bars to Display";
extern   int   Show_Bars = 200;
extern   int   SampleSize=1000;

//*********************************

//---- Drawing buffers
double VeryLowVol_Bar[];
double LessThanVol_Bar[];
double NormalVol_Bar[];
double MoreThanVol_Bar[];
double VeryHighVol_Bar[];

//-----  Message Arrays
int      msgNumber[];   //Contains number for each message, used to index msgArray[]
string   msgArray[];    //Contains text for each different message
color    clrArray[];    //Contains Color number for each message,
int      maxMsgs=30;    //Maximum  Msgs on screen, max array size for msgNumbr[]

//----------------- Variable Declarations -----

string objprefix = "VSAT_"; //Prefix for this indicators objects

double   verylowvolzone;
double   lowvolzone;
double   highvolzone;
double   veryhighvolzone; 
double   ultrahighvolzone=99999999.99;

int      intboxnumb;
double   highestvol;
color    currVolcolor;
string   currVolLabel;
string   lastVolLabel;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
//-----      
      Clear_Objects(StringLen(objprefix),objprefix);  //Delete any leftover objects
      
      InitializeIndicatorBuffers();
      IndicatorShortName("VSA Teacher Volume v3.2" );

//-----------------   
      ArrayResize(msgNumber,maxMsgs) ; //Set message array to size
//----      
   
     return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
  {
//----
   Clear_Objects(StringLen(objprefix),objprefix);  //Delete created objects
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {
   int counted_bars=IndicatorCounted();
   int i=Bars-counted_bars;
   
   while (i>0)
      {
         i--;
         //--------
         if(i == Show_Bars)  CalculateZones(i);   //Calculate VolZones,CreateBoxes
         
         if(i <= Show_Bars && NewBar(i))          //Only Update Arrays & Objects on a new bar, keep overhead low
            {
               SetZoneBoxLength(i,intboxnumb); 
               if(ShowText)   LoadMsgNumbr(i,GetMsgNumber(i+1));
               if(ShowText)   PrintMessages(i);
            }            
         
         //Determine appropiate volume bar & color, runs every tick
         VeryLowVol_Bar[i]=0;LessThanVol_Bar[i]=0;NormalVol_Bar[i]=0;MoreThanVol_Bar[i]=0;VeryHighVol_Bar[i]=0;

         if(Volume[i]<= verylowvolzone && verylowvolzone > 0)  //Very Low Volume
            {
               VeryLowVol_Bar[i]=Volume[i];  currVolcolor=clrArray[1];
               continue;
            }
         if(Volume[i] > ultrahighvolzone)    //Ultra High Volume
            {
               VeryHighVol_Bar[i]=Volume[i]; currVolcolor=clrArray[14];
               continue;
            }
         if(GreaterThanPrev(i))     //Vol Greater than Prev 2
            {
               MoreThanVol_Bar[i]=Volume[i]; currVolcolor=clrArray[3];
               continue;
            }
         if(LessThanPrev(i))     //Vol Less Than Prev 2
            {
               LessThanVol_Bar[i]=Volume[i]; currVolcolor=clrArray[4];
               continue;
            }
           else
            {
               NormalVol_Bar[i]=Volume[i];    currVolcolor=clrArray[2];     //Normal Vol Bar (None of the Above)
               continue;
            }  
      }
//----
      ObjectSetText(currVolLabel,"Vol.  "+DoubleToStr(Volume[0],0),CurrVolumeFont,"Arial",currVolcolor);      
   return(0);
  }
//+-------------------------    End of Start Routine  Functions Follow     -----------------------------------------+
//
//
int  GetMsgNumber(int i)   //Determine type of Last Volume bar, return msg#; only called on start of new bar
{
         if(Volume[i]<= verylowvolzone && verylowvolzone > 0) return(1); //Very Low Volume
         if(Volume[i]>verylowvolzone && Volume[i]<=lowvolzone) //Low Volume 
            {
               if(GreaterThanPrev(i))  return(3);
               if(LessThanPrev(i))return(4);
               return(2);
            }                      
         if(Volume[i] > lowvolzone && Volume[i]<=highvolzone)  //Normal Vol 
            {
               if(GreaterThanPrev(i))  return(6);
               if(LessThanPrev(i))  return(7);
               return(5);     
            }                      
         if(Volume[i]>highvolzone && Volume[i]<=veryhighvolzone) //High Volume
            {
               if(GreaterThanPrev(i))  return(9);
               if(LessThanPrev(i))  return(10);
               return(8);     
            }
         if(Volume[i]>veryhighvolzone && Volume[i]<ultrahighvolzone) //Very high Volume
            {
               if(GreaterThanPrev(i))  return(12);
               if(LessThanPrev(i))  return(13);
               return(11);     
            }                      
         if(Volume[i] > ultrahighvolzone)  return(14);   //Ultra High Volume
   return(0);
}
//-----------------------------------
bool   GreaterThanPrev(int i) //is Volume greater than previous 2 bars?
{
   if(Volume[i]>Volume[i+1] && Volume[i]>Volume[i+2]) return(true);
   return(false);
}
//---------------
bool   LessThanPrev(int i) //is Volume less than previous 2 bars?
{
   if(Volume[i]<Volume[i+1] && Volume[i]<Volume[i+2]) return(true);
   return(false);
}
//---------

bool  PrintMessages(int cnt)           //Print messages to screen
{
   if(cnt>maxMsgs) return(false);      //Only print # of msgs created
   for(int j=1;j<=maxMsgs+1;j++)         //Start @ zero & work up to maxMsgs, NOTE:add 1 to index, as msgbox(0) doesn't exist
      {
         ObjectSetText(StringConcatenate(objprefix,"Msg",j),StringConcatenate(j,". ",msgArray[msgNumber[j-1]]),
                                                                     TextFont,"Arial",clrArray[msgNumber[j-1]]);//display msg to screen
      }
   ObjectSetText(lastVolLabel,StringConcatenate(" Last Vol  ",DoubleToStr(Volume[1],0))
                                                       ,LastVolumeFont,"Arial",clrArray[msgNumber[0]]);
   return(true);
}
//------------------   
bool  LoadMsgNumbr(int cnt,int numbr)  //Load msgNumbr array with msg #'s
{
   if(cnt>maxMsgs) return(false);      //Limit number of elements in array    
   for(int j=maxMsgs;j>0;j--)          //Start at top of array & work down to zero
      {
         msgNumber[j]=msgNumber[j-1];  //Move each msgNumbr up 1 element
      }
   msgNumber[0]=numbr;                 //put newest msgNumbr into slot zero
   return(true);
}
//-----
bool  CalculateZones(int i)
{
   double level618=0.618;double level382=0.382;double level236=0.236;double level118=0.118;double level138=1.382;
   double median = Calc_Median(SampleSize);
   //-----  volum
   verylowvolzone =     MathRound(median*level236);                     //top of verylow vol zone - zero to here
   lowvolzone =         MathRound(median*level618);                     //top of lowvol zone - 23.6 to here - normal range starts here
   highvolzone =        MathRound(median+(median-(median*level618)));   //bottom of highvol zone
   veryhighvolzone =    MathRound(median+(median-(median*level236)));   //bottom of veryhigh vol zone
   ultrahighvolzone =   MathRound(median+(median*level138));
   
   //------ Highest Volume in Samplesize
   highestvol = MathRound(Volume[iHighest(NULL,0,MODE_VOLUME,SampleSize,Show_Bars)]);  //top of veryhigh volzone
   
   //Create Boxes
   intboxnumb = CreateZoneBoxes(Show_Bars,median,lowvolzone,verylowvolzone,highvolzone,veryhighvolzone,highestvol,ultrahighvolzone);
   
   //Set Box length
   SetZoneBoxLength(i,intboxnumb);
   
   if(ShowText)   
      {
         CreateLastVolLabel(i);   CreateMsgBoxes();  
      }
   LoadMsgArray();   //Load Messages needed for CurrVolcolor when ShowText(false)
   CreateCurrentVolLabel(i);
   WindowRedraw();
   //--------
   Print("Show ",Show_Bars," Bars    Starting ",TimeToStr(Time[Show_Bars])," -  Sample Size = ",SampleSize,"  Highest Vol = ",highestvol);
   Print("Very Low Vol zone ",verylowvolzone,"  Low Vol zone ",lowvolzone," High Vol zone ",highvolzone," Ultra High Vol zone ",ultrahighvolzone);
   //********
   return(true);
}
//------------
//---------------------------------------
bool LoadMsgArray()  //Load msgs into array
{
   ArrayResize(msgArray,14);  //MT4 Text Handling is all f***ked up!!!  Makes absolutely no sense!
   ArrayResize(clrArray,14);
    
   msgArray[1]  = "Ultra Low Volume";              clrArray[1] = Red;
   msgArray[2]  = "Low Volume";                    clrArray[2] = Blue;
   msgArray[3]  = "Low Volume > Prev 2";           clrArray[3] = Teal;
   msgArray[4]  = "Low Volume < Prev 2";           clrArray[4] = DarkOrange;
   msgArray[5]  = "Normal Volume";                 clrArray[5] = Blue;
   msgArray[6]  = "Normal Volume > Prev 2";        clrArray[6] = Teal;
   msgArray[7]  = "Normal Volume < Prev 2";        clrArray[7] = DarkOrange;
   msgArray[8]  = "HigH Volume";                   clrArray[8] = Blue;
   msgArray[9]  = "High Vol > Prev 2";             clrArray[9] = Teal;
   msgArray[10] = "High Vol < Prev 2";             clrArray[10] = DarkOrange;
   msgArray[11] = "Very High Volume";              clrArray[11] = Blue;
   msgArray[12] = "Very High Vol > Prev 2";        clrArray[12] = Teal;
   msgArray[13] = "Very High Vol < Prev 2";        clrArray[13] = DarkOrange;
   msgArray[14] = "CAUTION - Ultra High Volume";   clrArray[14] = Red;
   
   return(true);
}
//--------------------
bool CreateMsgBoxes()   //Create Boxes for messages string ObjName
{
   for(int i=1;i<=maxMsgs;i++)
   {
      string objName = StringConcatenate(objprefix,"Msg",i);
      ObjectCreate(objName,OBJ_LABEL,1,0,0);
      ObjectSet(objName,OBJPROP_CORNER,0);
      ObjectSet(objName,OBJPROP_XDISTANCE,1100);
      ObjectSet(objName,OBJPROP_YDISTANCE,i*TextSpacing);
   }
   return(true);
}

//**************************************  Boxes ******************************************
bool CreateCurrentVolLabel(int i)
{
   //Current Bars Volume, changes with each tick
   currVolLabel = StringConcatenate(objprefix,"CurrVol");   //CURR VOL xxxx - screen label
   ObjectCreate(currVolLabel,OBJ_LABEL,1,0,0,0,0);
   ObjectSet(currVolLabel,OBJPROP_CORNER,0);         //anchor left corner,will expand to the right
   ObjectSet(currVolLabel,OBJPROP_XDISTANCE,1050);   //set position from left side of screen,leave room for large #'s
   ObjectSet(currVolLabel,OBJPROP_YDISTANCE,1);
   ObjectSetText(currVolLabel,"Vol.  "+DoubleToStr(Volume[i],0),CurrVolumeFont,"Arial",Blue);
   return(true);
}
//-----------------------------
bool CreateLastVolLabel(int i)
{
   //Previous Bars Volume
   lastVolLabel = StringConcatenate(objprefix,"LastVol");   //LAST VOL xxxx - screen label
   ObjectCreate(lastVolLabel,OBJ_LABEL,1,0,0,0,0);
   ObjectSet(lastVolLabel,OBJPROP_CORNER,1);         //anchor right corner, will expand to the left
   ObjectSet(lastVolLabel,OBJPROP_XDISTANCE,5);      //set position from right side of screen
   ObjectSet(lastVolLabel,OBJPROP_YDISTANCE,1);
   ObjectSetText(lastVolLabel," Last Vol.  "+DoubleToStr(Volume[i+1],0),LastVolumeFont,"Arial",Blue);
   return(true);
}
bool  SetZoneBoxLength(int cnt,int boxcnt)
{
   if(cnt>Show_Bars) return(false);
   ObjectSet(StringConcatenate(objprefix,"LowVolZone",boxcnt),OBJPROP_TIME2,Time[cnt]+(Period()*60) );
   ObjectSet(StringConcatenate(objprefix,"VeryLowVolZone",boxcnt),OBJPROP_TIME2,Time[cnt]+(Period()*60) );
   ObjectSet(StringConcatenate(objprefix,"HighVolZone",boxcnt),OBJPROP_TIME2,Time[cnt]+(Period()*60) );
   ObjectSet(StringConcatenate(objprefix,"VeryHighVolZone",boxcnt),OBJPROP_TIME2,Time[cnt]+(Period()*60) );
   ObjectSet(StringConcatenate(objprefix,"UltraHighVolZone",boxcnt),OBJPROP_TIME2,Time[cnt]+(Period()*60) );
   return(true);
}
//----------------
int CreateZoneBoxes(int iStartBar,double imedian,double ilowvolzone,double iverylowvolzone,double ihighvolzone,
                                                         double iveryhighvolzone,double ihighestvol,double iultrahighvolzone)
{
   static int boxcnt=0; //Future revision to plot moving boxes
   boxcnt++;

   ObjectCreate(StringConcatenate(objprefix,"VeryLowVolZone",boxcnt),OBJ_RECTANGLE,1,Time[iStartBar],iverylowvolzone,Time[iStartBar]+(Period()*60),0.0);
   ObjectCreate(StringConcatenate(objprefix,"LowVolZone",boxcnt),OBJ_RECTANGLE,1,Time[iStartBar],ilowvolzone,Time[iStartBar]+(Period()*60),iverylowvolzone);  
   ObjectCreate(StringConcatenate(objprefix,"HighVolZone",boxcnt),OBJ_RECTANGLE,1,Time[iStartBar],ihighvolzone,Time[iStartBar]+(Period()*60),iveryhighvolzone);
   ObjectCreate(StringConcatenate(objprefix,"VeryHighVolZone",boxcnt),OBJ_RECTANGLE,1,Time[iStartBar],iveryhighvolzone,Time[iStartBar]+(Period()*60),iultrahighvolzone);
   ObjectCreate(StringConcatenate(objprefix,"UltraHighVolZone",boxcnt),OBJ_RECTANGLE,1,Time[iStartBar],iultrahighvolzone,Time[iStartBar]+(Period()*60),ihighestvol);
   
   ObjectSet(StringConcatenate(objprefix,"VeryLowVolZone",boxcnt),OBJPROP_COLOR,Red); //  //Crimson);Red);Red);
   ObjectSet(StringConcatenate(objprefix,"LowVolZone",boxcnt),OBJPROP_COLOR,Khaki);     //PaleGoldenrod);
   ObjectSet(StringConcatenate(objprefix,"HighVolZone",boxcnt),OBJPROP_COLOR,Khaki);  //LemonChiffon);
   ObjectSet(StringConcatenate(objprefix,"VeryHighVolZone",boxcnt),OBJPROP_COLOR,DarkSalmon);  //PaleGoldenrod);
   ObjectSet(StringConcatenate(objprefix,"UltraHighVolZone",boxcnt),OBJPROP_COLOR,OrangeRed);    //Crimson); 

   return(boxcnt);
}
//**************
bool InitializeIndicatorBuffers()
   {
//---- indicators
      SetIndexBuffer(0,VeryLowVol_Bar);
      SetIndexStyle(0,DRAW_HISTOGRAM);
      SetIndexLabel(0,"Very Low Vol");
      
      
      SetIndexBuffer(1,LessThanVol_Bar);
      SetIndexStyle(1,DRAW_HISTOGRAM);
      SetIndexLabel(1,"Vol<Prev 2");
      
      SetIndexBuffer(2,NormalVol_Bar);
      SetIndexStyle(2,DRAW_HISTOGRAM);
      SetIndexLabel(2,"Normal Vol");
      
      
      SetIndexBuffer(3,MoreThanVol_Bar);
      SetIndexStyle(3,DRAW_HISTOGRAM);
      SetIndexLabel(3,"Vol>Prev 2");
      
      SetIndexBuffer(4,VeryHighVol_Bar);
      SetIndexStyle(4,DRAW_HISTOGRAM);
      SetIndexLabel(4,"Ultra High Vol");
      return(true);
   }


//************
double Calc_Median(int intBars)  //
{
   double imedian=0;
   for(int i2=0;i2<=intBars;i2++) 
      {
         imedian += Volume[i2];
      }         
   imedian=imedian/intBars;   
   
   return(imedian);
}
//******************
bool NewBar(int dtcnt)
   {
      static datetime dt;
      
      if (dt ==Time[dtcnt] )
         {
            return(false);
         }
      else
         {
            dt = Time[dtcnt];
            return(true);
         }
       
   }
//----------------+
bool PrintErr(string callFunc)
{
   int intErr = GetLastError();
   if(intErr > 0)
      {
         Print("Error in ",callFunc,"  Error # = ",intErr);
         return(true);
      }
   return(false);
}
//+----------------------------- Delete selected objects from window-----------------------------------------/+
//
// Routine to delete only objects created within indicator and leave other objects created outside of indicator untouched.
// Must insert a "NamePrefix" in variable declaration as follow -> string objprefix="xxx"; where xxx=any characters
// Must add to all objects created -> ObjectCreate( objprefix + string name, int type, etc.,etc.)
// Will delete ONLY objects with specified prefix
// Function call is -->  Clear_Objects(StringLen(objprefix),objprefix);
//
//-----------------------------------------------------------------------------------------------------------/+
bool  Clear_Objects(int stringlength,string objprefix)
   {
      if(ObjectsTotal()==0) return(false);
      Print("Total Objects = ",ObjectsTotal(OBJ_RECTANGLE));
      for(int i=ObjectsTotal();i >= 0;i--)
          {
            if(StringSubstr(ObjectName(i),0,stringlength)==objprefix) ObjectDelete(ObjectName(i));
          }
      Print("Objects Remaining = ",ObjectsTotal(OBJ_RECTANGLE),"  ObjectsCount = ",i);
      return(true);
   }

//+----------------------------     END OF PROGRAM    ----------------------------------------------------