Pregunta

I am failing over and over trying to get this indicator to run quantised with 2 buffers in . After a long time reading I have put 2 extra buffers in to squish it :/ because:

the indicator is sitting between 0.1430-0.1427 at present but doesn't have a fixed top and bottom.

I can't seem to suss it; cool indicator but won't play fair!

#property indicator_separate_window
#property indicator_buffers   4
#property indicator_color1    Lime
#property indicator_color2    Red
#property indicator_color3    CLR_NONE
#property indicator_color4    CLR_NONE
//#property indicator_minimum 0
//#property indicator_maximum 100
extern int    P   =   13;
extern int    T   = 3000;
extern double P2  =    0.001;
//int         MIN =    0;
//int         MAX =  100;
double G[];
double R[];
double B3[];
double B4[];

int init(){
   IndicatorBuffers(4);
   SetIndexBuffer( 0, G  );SetIndexStyle( 0, DRAW_LINE, STYLE_SOLID, 1, Lime );
   SetIndexBuffer( 1, R  );SetIndexStyle( 1, DRAW_LINE, STYLE_SOLID, 1, Red  );
   SetIndexBuffer( 2, B3 );SetIndexStyle( 2, DRAW_NONE );
   SetIndexBuffer( 3, B4 );SetIndexStyle( 3, DRAW_NONE );
   return(0);
}
int start(){
      if (  T >= Bars ) T = Bars;

      SetIndexDrawBegin( 0, Bars - T + P + 1 );
      SetIndexDrawBegin( 1, Bars - T + P + 1 );
      SetIndexDrawBegin( 2, Bars - T + P + 1 );
      SetIndexDrawBegin( 3, Bars - T + P + 1 );

      int Z, C, Opt = IndicatorCounted();

      if (  Bars <= 38 ) return(0);

      if (  Opt  <  P ){
         for ( Z = 1; Z <= 0; Z++ ) G[T-Z] = 0.0;
         for ( Z = 1; Z <= 0; Z++ ) R[T-Z] = 0.0;
      }

      Z = T - P - 1;

      while( Z >= 0 ){
         double A, S1, S2;
         S1 = 0.0; for ( C = 0; C <= P - 1; C++ ){ S1 = S1 + (   High[Z+C] + Low[Z+C] ) / 2;}
         S2 = 0.0; for ( C = 0; C <= P - 1; C++ ){ S2 = S2 + ( ( High[Z+C] + Low[Z+C] ) * ( C+1 ) / 2 );}
         A  = S1 / S2;
         // if (  A < MIN ){ MIN = A;}
         // if (  A > MAX ){ MAX = A;}
         // A = ( MIN / MAX ) * 100;
         G[Z] = A;
         if (  Z > 0 ){ R[Z-1] = A;}
         Z--;
      }
      for ( int N = T-P-2; N >= 0; N-- ){
         if (  N > 0 ){
               if ( G[N-1] > G[N] ){ R[N] = EMPTY_VALUE; continue;}
               if ( G[N-1] < G[N] ){ G[N] = R[N];        continue;}
         }
         B3[0] = G[0] + P2;
         B4[0] = G[0] - P2; //forced quantise using 2 extra buffers
      }
      return(0);
   }
¿Fue útil?

Solución

Let´s split the task first

0) indicator logic
1) indicator quantisation step
2) indicator performance

MQL4 Custom Indicator programming relies on deeper understanding of underlying MetaTrader4 Terminal platform. Each external Market Event, changing a traded instrument price, is signalled to a lcoalhost by a network delivery of a QUOTE ... message from MetaTrader4 Server. This is aka Tick and it triggers a call to a function originally called start(), in newer New-MQL4.56789 renamed to OnTick().

The below modified MQL4 listing contains remarks for core-logic disambiguation, which must precede all the below listed steps.


1) indicator quantisation step

While the code is still very inefficient ( as per [2] below ) the logic does not include any straight hurdle form having the output quantised to any form thereof { binary | ternary | arbitrary-number-of-states }-quantised system. Whence the indicator core-logic is cleared, the quantisation step is just a trivial conversion from R(1) to I(1).


2) indicator performance

Any Tick arrival may, but need not modify either High[0] or Low[0], which are the only variable parts of the proposed Custom Indicator calculus.

This is the core idea on how to reduce the scope of re-calculations, that the MQL4 code has to realise per tick. In recent versions of MT4, all Custom Indicators share a single thread, the more stress has been put on efficient algorithmisation of Custom Indicators, at these may block the platform's trading decisions on poor, inefficient code-loops and convolution/recursion re-executions.

#property indicator_separate_window
#property indicator_buffers   4
#property indicator_color1    Lime
#property indicator_color2    Red
#property indicator_color3    CLR_NONE
#property indicator_color4    CLR_NONE

extern int    P   =   13;
extern int    T   = 3000;
extern double P2  =    0.001;

double G[];                                                         // 0: LINE
double R[];                                                         // 1: LINE
double B3[];                                                        // 2: BUT NEVER PAINTED, NEVER CONSUMED _?_
double B4[];                                                        // 3: BUT NEVER PAINTED, NEVER CONSUMED _?_

int init(){
   IndicatorBuffers(4);
   SetIndexBuffer( 0, G  );SetIndexStyle( 0, DRAW_LINE, STYLE_SOLID, 1, Lime );
   SetIndexBuffer( 1, R  );SetIndexStyle( 1, DRAW_LINE, STYLE_SOLID, 1, Red  );
   SetIndexBuffer( 2, B3 );SetIndexStyle( 2, DRAW_NONE );
   SetIndexBuffer( 3, B4 );SetIndexStyle( 3, DRAW_NONE );
   return(0);
}
int start(){

    if (  Bars <= 38 ) return(0);                                   // JIT/RET in case Bars < 39 --^ --^ --^ --^

    if (  T >= Bars ) T = Bars;                                     // (TRIM´d) T < Bars .OR. = Bars

    int aDrawBegins     = Bars - T + P + 1;                         // ( extern P = 13 ) + 1 + ( Bars - ( extern T = 3000 if T < Bars else Bars ) )
    //tIndexDrawBegin( 0, Bars - T + P + 1 );                       // PREF: ( reused 4x )
    SetIndexDrawBegin( 0, aDrawBegins );                            // Draw  14+ last candles -- PREF: why a per tick hard-coded SHIFTING / enforced re-draw?
    SetIndexDrawBegin( 1, aDrawBegins );                            // Draw  14+ last candles -- PREF: why a per tick hard-coded SHIFTING / enforced re-draw?
    SetIndexDrawBegin( 2, aDrawBegins );                            // Draw  14+ last candles -- PREF: why a per tick hard-coded SHIFTING / enforced re-draw?
    SetIndexDrawBegin( 3, aDrawBegins );                            // Draw  14+ last candles -- PREF: why a per tick hard-coded SHIFTING / enforced re-draw?

    double A, S1, S2;                                               // auxiliary var for bar-mid-price calculi
    int    Z;                                                       // auxiliary stepper
    int    Opt = IndicatorCounted();                                // Opt ( NEVER RE-USED )

    if (  Opt  <  P ){                                              // if ( ( extern P = 13 ) > IndicatorCounted() )
       // ----------------------- ??? ----------------------------------------------------- NEVER EXEC´d: for( Z = 1++ v/s Z <= 0 )
       for ( Z = 1; Z <= 0; Z++ ) G[T-Z] = 0.0;                     // .STO G[T-Z], 0., BUT NEVER EXEC´d: for( Z = 1++ v/s Z <= 0 )
       for ( Z = 1; Z <= 0; Z++ ) R[T-Z] = 0.0;                     // .STO R[T-Z], 0., BUT NEVER EXEC´d: for( Z = 1++ v/s Z <= 0 )
       // ----------------------- ??? ----------------------------------------------------- NEVER EXEC´d: for( Z = 1++ v/s Z <= 0 )
    }

    Z = T - P - 1;                                                  // .STO Z, ( T = Bars (TRIM´d) ) - ( extern P = 13 ) - 1

    while( Z >= 0 ){                                                // .DEC Z
       //        !!! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // PERF: very inefficient to RE-calc STATIC ( ( extern P = 13 ) - 1 )-DEEP CONVOLUTIONS per tick !!
       S1 = 0.0; for ( int C = 0; C <= P - 1; C++ ){ S1 = S1 + (   High[Z+C] + Low[Z+C] )           / 2;  }
       S2 = 0.0; for ( int C = 0; C <= P - 1; C++ ){ S2 = S2 + ( ( High[Z+C] + Low[Z+C] ) * ( C+1 ) / 2 );}
       //        !!! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // PERF: very inefficient to RE-calc STATIC ( ( extern P = 13 ) - 1 )-DEEP CONVOLUTIONS per tick !!
       A  = S1 / S2;
       G[Z] = A;                                                    // .STO G[Z],   A if Z >= 0
       if (  Z > 0 ){ R[Z-1] = A;}                                  // .STO R[Z-1], A if Z >  0
       Z--;
    }

    for ( int N = T - P - 2; N >= 0; N-- ){                         // .STO N, ( T = Bars (TRIM´d) ) - ( extern P = 13 ) - 2
       if (   N > 0 ){                                              // N > 0:
              if ( G[N-1] > G[N] ){ R[N] = EMPTY_VALUE; continue;}  // .BLNK R[N], EMPTY if G[N-1] > G[N]
              if ( G[N-1] < G[N] ){ G[N] = R[N];        continue;}  // .SET  G[N], R[N]  if G[N-1] < G[N]
       }
    // ?? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // WHY MANY-TIMES RE-ASSIGNED A CONST. VALUE HERE, INSIDE A FOR(){...}-loop body? -------------- ??
       B3[0] = G[0] + P2;                                           // .STO B3[0], G[0] + ( extern P2 = 0.001 )
       B4[0] = G[0] - P2;                                           // .STO B4[0], G[0] - ( extern P2 = 0.001 )
                                                                    // forced quantise using 2 extra buffers
    // ?? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // WHY MANY-TIMES RE-ASSIGNED A CONST. VALUE HERE, INSIDE A FOR(){...}-loop body? -------------- ??
    }
    return(0);
}

New-MQL4.56789 syntax

The OnCalculate() function is called only in custom indicators when it's necessary to calculate the indicator values by the Calculate event. This usually happens when a new tick is received for the symbol, for which the indicator is calculated. This indicator is not required to be attached to any price chart of this symbol.

The first rates_total parameter contains the number of bars, available to the indicator for calculation, and corresponds to the number of bars available in the chart.

We should note the connection between the return value of OnCalculate() and the second input parameter prev_calculated. During the OnCalculate() function call, the prev_calculated parameter contains a value returned by OnCalculate() during previous call. This allows for economical algorithms for calculating the custom indicator in order to avoid repeated calculations for those bars that haven't changed since the previous run of this function.

For this, it is usually enough to return the value of the rates_total parameter, which contains the number of bars in the current function call. If since the last call of OnCalculate() the price data has changed (a deeper history downloaded or history blanks filled), the value of the input parameter prev_calculated will be set to zero by the terminal.

//+------------------------------------------------------------------+ 
//| 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[]
                  )
  {
  // Get the number of bars available now for the current Symbol and chart period 
     int barsNow = Bars( _Symbol, PERIOD_CURRENT );

  // .RET value of prev_calculated for a next call
     return( rates_total );
  }
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top