Time Segmented Volume

0 Views
0 Downloads
0 Favorites
Time Segmented Volume
//---------------------------------------------------------------------------------------------------------------------
#define     MName          "Time Segmented Volume (TSV)"
#define     MVersion       "1.01"
#define     MBuild         "2023-03-27 21:02 WET"
#define     MCopyright     "Copyright \x00A9 2023, Fernando M. I. Carreiro, All rights reserved"
#define     MProfile       "https://www.mql5.com/en/users/FMIC"
//---------------------------------------------------------------------------------------------------------------------
#property   strict
#property   version        MVersion
#property   description    MName
#property   description    "MetaTrader Indicator (Build "MBuild")"
#property   copyright      MCopyright
#property   link           MProfile
//---------------------------------------------------------------------------------------------------------------------

//--- Setup

   #property indicator_separate_window

   // Define number of buffers and plots
      #define MPlots    3
      #define MBuffers  7
      #ifdef __MQL4__
         #property indicator_buffers   ( MPlots + 1 )
      #else
         #property indicator_buffers   MBuffers
         #property indicator_plots     MPlots
      #endif

   // Define plot colours and respective indices
      #define     MClrCandleNone    C'239,166,117'
      #define     MClrCandleUp      C'38,166,154'
      #define     MClrCandleDown    C'239,83,80'

   // Display properties for plots
      #ifdef __MQL4__
         // Summation plots
            #property   indicator_label1  "Summation (positive)"
            #property   indicator_type1   DRAW_HISTOGRAM
            #property   indicator_style1  STYLE_SOLID
            #property   indicator_width1  3
            #property   indicator_color1  MClrCandleUp
            #property   indicator_label2  "Summation (negative)"
            #property   indicator_type2   DRAW_HISTOGRAM
            #property   indicator_style2  STYLE_SOLID
            #property   indicator_width2  3
            #property   indicator_color2  MClrCandleDown
         // Simple averaging plot
            #property   indicator_label3  "Averaging (simple)"
            #property   indicator_type3   DRAW_LINE
            #property   indicator_style3  STYLE_SOLID
            #property   indicator_width3  2
            #property   indicator_color3  MClrCandleNone
         // Exponential averaging plot
            #property   indicator_label4  "Averaging (exponential)"
            #property   indicator_type4   DRAW_LINE
            #property   indicator_style4  STYLE_SOLID
            #property   indicator_width4  1
            #property   indicator_color4  MClrCandleNone
      #else
         // Define colour index for plots
            #define     MIdxCandleNone    0.0
            #define     MIdxCandleUp      1.0
            #define     MIdxCandleDown    2.0
         // Summation plot
            #property   indicator_label1  "Summation"
            #property   indicator_type1   DRAW_COLOR_HISTOGRAM
            #property   indicator_style1  STYLE_SOLID
            #property   indicator_width1  5
            #property   indicator_color1  MClrCandleNone, MClrCandleUp, MClrCandleDown
         // Simple averaging plot
            #property   indicator_label2  "Averaging (simple)"
            #property   indicator_type2   DRAW_LINE
            #property   indicator_style2  STYLE_SOLID
            #property   indicator_width2  2
            #property   indicator_color2  MClrCandleNone
         // Exponential averaging plot
            #property   indicator_label3  "Averaging (exponential)"
            #property   indicator_type3   DRAW_LINE
            #property   indicator_style3  STYLE_SOLID
            #property   indicator_width3  1
            #property   indicator_color3  MClrCandleNone
      #endif

//--- Enumarations

   // Volume weight enumaraton
      enum EVolumeWeight
      {
         EVW_None = 0,        // No volume weighting
         EVW_TickVolume,      // Tick volume
         #ifndef __MQL4__
            EVW_RealVolume,   // Real volume
         #endif
         EVW_PriceRange       // True price range (pseudo volume)
      };

//--- Parameter settings

   input uint                 i_nSummationPeriod   = 13,             // Summation period
                              i_nAveragingPeriod   = 7;              // Averaging period
   input ENUM_APPLIED_PRICE   i_ePriceApplied      = PRICE_CLOSE;    // Applied price
   input EVolumeWeight        i_eVolumeWeight      = EVW_TickVolume; // Applied volume

//--- Macro definitions

   // Define OnCalculate loop sequencing macros
      #define MOnCalcPrevTest ( prev_calculated < 1 || prev_calculated > rates_total )
      #ifdef __MQL4__   // for MQL4 (as series)
         #define MOnCalcNext(  _index          ) ( _index--             )
         #define MOnCalcBack(  _index, _offset ) ( _index + _offset     )
         #define MOnCalcCheck( _index          ) ( _index >= 0          )
         #define MOnCalcValid( _index          ) ( _index < rates_total )
         #define MOnCalcStart \
            ( rates_total - ( MOnCalcPrevTest ? 1 : prev_calculated ) )
      #else             // for MQL5 (as non-series)
         #define MOnCalcNext(  _index          ) ( _index++             )
         #define MOnCalcBack(  _index, _offset ) ( _index - _offset     )
         #define MOnCalcCheck( _index          ) ( _index < rates_total )
         #define MOnCalcValid( _index          ) ( _index >= 0          )
         #define MOnCalcStart \
            ( MOnCalcPrevTest ? 0 : prev_calculated - 1 )
      #endif

   // Define applied price macro
      #define MSetAppliedPrice( _type, _where, _index ) { switch( _type ) {                                \
         case PRICE_WEIGHTED: _where = ( high[ _index ] + low[ _index ] + close[ _index ]                  \
                                                                        + close[ _index ] ) * 0.25; break; \
         case PRICE_TYPICAL:  _where = ( high[ _index ] + low[ _index ] + close[ _index ] ) / 3.0;  break; \
         case PRICE_MEDIAN:   _where = ( high[ _index ] + low[ _index ]                   ) * 0.5;  break; \
         case PRICE_HIGH:     _where = high[  _index ];                                             break; \
         case PRICE_LOW:      _where = low[   _index ];                                             break; \
         case PRICE_OPEN:     _where = open[  _index ];                                             break; \
         case PRICE_CLOSE:                                                                                 \
         default:             _where = close[ _index ];                                                 }; }

   // Define macro for invalid parameter values
      #define MCheckParameter( _condition, _text ) if( _condition ) \
         { Print( "Error: Invalid ", _text ); return INIT_PARAMETERS_INCORRECT; }

//--- Global variable declarations

   // Indicator buffers
      double      g_adbPriceApplied[],             // Buffer for applied price
                  g_adbVolumePriceDelta[],         // Buffer for volume weight price delta change
                  g_adbSummation[],                // Buffer for summation of volume weighte price change
                  g_adbSummationSimple[],          // Buffer for summation of summation for simple averaging
                  g_adbAveragingSimple[],          // Buffer for simple averaging
                  g_adbAveragingExponential[];     // Buffer for exponential averaging
      #ifdef __MQL4__
         double   g_adbSummationPositive[],        // Buffer for positive summation of volume weighte price change
                  g_adbSummationNegative[];        // Buffer for negative summation of volume weighte price change
      #else
         double   g_adbSummationColour[];          // Buffer for summation colourisation
      #endif

   // Miscellaneous global variables
      double      g_dbEmaWeight;                   // Weight to be used for exponential moving averages

//--- Event handling functions

   // Initialisation event handler
      int OnInit(void) {
         // Validate input parameters
            MCheckParameter( i_nSummationPeriod < 1,                  "summation period" );
            MCheckParameter( i_nAveragingPeriod < 1 ||
                             i_nAveragingPeriod > i_nSummationPeriod, "averaging period" );

         // Calculate parameter variables
            g_dbEmaWeight = 2.0 / ( i_nAveragingPeriod + 1.0 );

         // Set number of significant digits (precision)
            IndicatorSetInteger( INDICATOR_DIGITS, _Digits );

         // Set buffers
            int iBuffer = 0;
            #ifdef __MQL4__
               IndicatorBuffers( MBuffers + 1 ); // Set total number of buffers (MQL4 Only)
               SetIndexBuffer( iBuffer++, g_adbSummationPositive,    INDICATOR_DATA         );
               SetIndexBuffer( iBuffer++, g_adbSummationNegative,    INDICATOR_DATA         );
            #else
               SetIndexBuffer( iBuffer++, g_adbSummation,            INDICATOR_DATA         );
               SetIndexBuffer( iBuffer++, g_adbSummationColour,      INDICATOR_COLOR_INDEX  );
            #endif
            SetIndexBuffer(    iBuffer++, g_adbAveragingSimple,      INDICATOR_DATA         );
            SetIndexBuffer(    iBuffer++, g_adbAveragingExponential, INDICATOR_DATA         );
            SetIndexBuffer(    iBuffer++, g_adbPriceApplied,         INDICATOR_CALCULATIONS );
            SetIndexBuffer(    iBuffer++, g_adbVolumePriceDelta,     INDICATOR_CALCULATIONS );
            SetIndexBuffer(    iBuffer++, g_adbSummationSimple,      INDICATOR_CALCULATIONS );
            #ifdef __MQL4__
               SetIndexBuffer( iBuffer++, g_adbSummation,            INDICATOR_CALCULATIONS );
            #endif

         // Set indicator name
            IndicatorSetString( INDICATOR_SHORTNAME, StringFormat(
               MName " ( %d, %d )", i_nSummationPeriod, i_nAveragingPeriod ) );

         return INIT_SUCCEEDED;  // Successful initialisation of indicator
      };

   // Calculation event handler
      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[]
         )
      {
         // Main loop — fill in the arrays with data values
            for( int iCur     = MOnCalcStart,
                     iPrev    = MOnCalcBack( iCur, 1                        ),
                     iSumPrev = MOnCalcBack( iCur, (int) i_nSummationPeriod ),
                     iAvgPrev = MOnCalcBack( iCur, (int) i_nAveragingPeriod );
                 !IsStopped() && MOnCalcCheck( iCur );
                 MOnCalcNext( iCur ), MOnCalcNext( iPrev ), MOnCalcNext( iSumPrev ), MOnCalcNext( iAvgPrev ) )
            {
               // Calculate volume to apply
                  double dbVolume = 1.0;
                  switch( i_eVolumeWeight ) {
                     #ifndef __MQL4__
                        case EVW_RealVolume: dbVolume = (double) volume[      iCur ]; break;
                     #endif
                     case EVW_TickVolume:    dbVolume = (double) tick_volume[ iCur ]; break;
                     case EVW_PriceRange:    if( MOnCalcValid( iPrev ) ) {
                                                double dbClosePrev = close[ iPrev ];
                                                       dbVolume    = fmax( high[ iCur ], dbClosePrev )
                                                                   - fmin( low[  iCur ], dbClosePrev );
                                             } else    dbVolume    = high[ iCur ] - low[ iCur ];
                  };

               // Calculate price to apply
                  double dbPriceCur;
                  MSetAppliedPrice( i_ePriceApplied, dbPriceCur, iCur );

               // Calculate volume weighted price delta and sum
                  double dbPricePrev            = MOnCalcValid( iPrev ) ? g_adbPriceApplied [ iPrev ] : open[ iCur ],
                         dbPriceDelta           = dbPriceCur - dbPricePrev,
                         dbVolumePriceDelta     = dbPriceDelta * dbVolume,
                         dbSummation            = dbVolumePriceDelta
                                                + ( MOnCalcValid( iPrev    ) ? g_adbSummation[        iPrev    ] : 0.0 )
                                                - ( MOnCalcValid( iSumPrev ) ? g_adbVolumePriceDelta[ iSumPrev ] : 0.0 );
               // Define colourasation
                  #ifdef __MQL4__
                     double dbSummationPositive = dbSummation > 0.0 ? dbSummation : 0.0,
                            dbSummationNegative = dbSummation < 0.0 ? dbSummation : 0.0;
                  #else
                     double dbSummationColour   =   dbSummation > 0.0 ? MIdxCandleUp
                                                : ( dbSummation < 0.0 ? MIdxCandleDown
                                                :                       MIdxCandleNone );
                  #endif

               // Calculate simple summation and averaging
                  double dbSumSimpleCur        = dbSummation
                                               + ( MOnCalcValid( iPrev    ) ? g_adbSummationSimple[ iPrev    ] : 0.0 )
                                               - ( MOnCalcValid( iAvgPrev ) ? g_adbSummation[       iAvgPrev ] : 0.0 ),
                         dbAverageSimpleCur    = dbSumSimpleCur / i_nAveragingPeriod;

               // Calculate exponential averaging
                  double dbAverageExponentialPrev = MOnCalcValid( iPrev ) ? g_adbAveragingExponential[ iPrev ] : dbSummation,
                         dbAverageExponentialCur  = dbAverageExponentialPrev
                                                   + ( dbSummation - dbAverageExponentialPrev )
                                                   * g_dbEmaWeight;

               // Set buffer values
                  g_adbPriceApplied[         iCur ] = dbPriceCur;
                  g_adbVolumePriceDelta[     iCur ] = dbVolumePriceDelta;
                  g_adbSummation[            iCur ] = dbSummation;
                  g_adbSummationSimple[      iCur ] = dbSumSimpleCur;
                  g_adbAveragingSimple[      iCur ] = dbAverageSimpleCur;
                  g_adbAveragingExponential[ iCur ] = dbAverageExponentialCur;
                  #ifdef __MQL4__
                     g_adbSummationPositive[ iCur ] = dbSummationPositive;
                     g_adbSummationNegative[ iCur ] = dbSummationNegative;
                  #else
                     g_adbSummationColour[   iCur ] = dbSummationColour;
                  #endif
            };

         return rates_total;  // Return value for prev_calculated of next call
      };

//---------------------------------------------------------------------------------------------------------------------

Comments