iCustom giving unexpected values - page 5

 
Vladimir Karputov #:
What problems? Need my help?

I think we have it handled. I appreciate the assistance though. :)

 

Things are going to start to get more complicated, so here is the next instalment (TestRex) to reproduce the following (please note the ATR indicator with a level line for reference):


// Define indicator properties

   // Define plotting considitions
      #property indicator_separate_window
      #property indicator_buffers 4
      #property indicator_plots   1

   // Define properties for REX plot
      #property indicator_label1  "ATR Threshold Signal"
      #property indicator_type1   DRAW_LINE
      #property indicator_color1  clrGreen
      #property indicator_style1  STYLE_SOLID
      #property indicator_width1  1

// Macro definitions

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

// Declare input variables

   input group "Parameters: ATR settings"
      input uint
         inpAtrPeriod         = 14;                // ATR Period
      input double
         inpAtrTheshold       = 0.0025;            // ATR Threshold

   input group "Parameters: REX settings"
      input uint 
         inpRexPeriod         = 14,                // REX Period
         inpRexSignal         = 14;                // REX Signal Period
      input ENUM_MA_METHOD
         inpRexMethod         = MODE_SMA,          // REX Method
         inpRexSignalMethod   = MODE_SMA;          // REX Signal Method
   
// Declare indicator handles
   int 
      atrHandle               = INVALID_HANDLE,    // Handle for ATR indicator
      rexHandle               = INVALID_HANDLE;    // Handle for REX indicator

// Declare buffers arrays
   double
      atrThresholdBuffer[],                        // Array for ATR Theshold Signal
      atrBuffer[],                                 // Array for ATR buffer
      rexBuffer[],                                 // Array for REX buffer
      rexSignalBuffer[];                           // Array for REX signal buffer
   
// Support function to release all indicator handles
   void ReleaseAllHandles( void )
   {
      ReleaseHandle( atrHandle, "ATR" );
      ReleaseHandle( rexHandle, "REX" );
   };
   
// De-initialisation event handler
   void OnDeinit( const int reason ){ 
      ReleaseAllHandles(); 
   };
   
// Initialisation event handler
   int OnInit(){
      // Check parameters
         MCheckParameter( !( inpAtrTheshold > 0 ), "ATR Threshold"     );
         MCheckParameter(    inpAtrPeriod   < 1,   "ATR Period"        );
         MCheckParameter(    inpRexPeriod   < 1,   "REX Period"        );
         MCheckParameter(    inpRexSignal   < 1,   "REX Signal Period" );
   
      // Obtain and verify indicator handles
         ResetLastError();
         if( !AssignHandle( atrHandle, "ATR",
               iATR(    _Symbol, _Period, inpAtrPeriod                         ) ) ||
             !AssignHandle( rexHandle, "REX",
               iCustom( _Symbol, _Period, "REX",
                  inpRexPeriod, inpRexMethod, inpRexSignal, inpRexSignalMethod ) )    )
         {
            ReleaseAllHandles(); // Release all currently assigned indicator handles
            return INIT_FAILED;  // Initialisation has failed
         };
         
      // Set buffers (use autoindexing in case we need to reshuffle the sequence )
         int iBuffer = 0;  // Just to help to easily reshuffle buffers
         SetIndexBuffer( iBuffer++, atrThresholdBuffer, INDICATOR_DATA         );
         SetIndexBuffer( iBuffer++, atrBuffer,          INDICATOR_CALCULATIONS );
         SetIndexBuffer( iBuffer++, rexBuffer,          INDICATOR_CALCULATIONS );
         SetIndexBuffer( iBuffer++, rexSignalBuffer,    INDICATOR_CALCULATIONS );

      return INIT_SUCCEEDED;  // Successful initialisation of indicator
   };

// OnCalculate 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[] )
   {
      // Make sure we have rates data
         if( rates_total < 1 ) return 0; // No data available yet
         
      // Check number of calculated bars for indicators
         if( !CheckBarCount( atrHandle, "ATR", rates_total ) ||
             !CheckBarCount( rexHandle, "REX", rates_total )    )
            return 0; // Bar count check failed

      // Calculate bar counting variables
         int
            // Adjust number of previously calculated bars accounting for incomplete current bar
               nPrevCalc    =   prev_calculated > rates_total ? rates_total     - 1
                            : ( prev_calculated > 1           ? prev_calculated - 1 : 0 ),
            // Calculate how many bars need to be updated
               nBarsUpdate  = rates_total - nPrevCalc;
         
      // Collect indicator data and check results
         if( !CheckBarCopy( atrHandle, "ATR",        nBarsUpdate, 0, atrBuffer       ) ||
             !CheckBarCopy( rexHandle, "REX",        nBarsUpdate, 0, rexBuffer       ) ||
             !CheckBarCopy( rexHandle, "REX Signal", nBarsUpdate, 1, rexSignalBuffer )    )
            return 0; // Indicator data collection failed
            
      // Loop through the buffer indices and update values
         for( int iIndex = nPrevCalc; iIndex < rates_total; iIndex ++ ) {
            double atrValue = atrBuffer[ iIndex ];
            atrThresholdBuffer[ iIndex ]
               =   atrValue > inpAtrTheshold ? +1
               : ( atrValue < inpAtrTheshold ? -1
               : ( iIndex   > 0              ? atrBuffer[ iIndex - 1 ]
               : 0 ) );
            /* The above short-hand logic can be difficult to understand
               so here is the long version ...
               
               if( atrValue > inpAtrTheshold )
                  atrThresholdBuffer[ iIndex ] = +1;
               else {
                  if( atrValue < inpAtrTheshold )
                     atrThresholdBuffer[ iIndex ] = -1;
                  else {
                     if( iIndex > 0 )
                        atrThresholdBuffer[ iIndex ] = atrThresholdBuffer[ iIndex - 1 ];
                     else
                        atrThresholdBuffer[ iIndex ] = 0;
                  };
               }; */
         };

      return rates_total;  // Return value for prev_calculated of next call
   };
   
// Support function to release indicator handle
   bool ReleaseHandle( int &mHandle, string mName ) {
      if( mHandle != INVALID_HANDLE ){
         ResetLastError();
         if( !IndicatorRelease( mHandle ) )
         {
            Print( "Error %d: Unable to release %s indicator handle", _LastError, mName );
            return false;
         };
         mHandle = INVALID_HANDLE;
      };
      return true;
   };
   
// Support function to assigning indicator handle
   bool AssignHandle( int &mHandle, string mName, int mCustom ) {
      if( ReleaseHandle( mHandle, mName ) ) {   // First make sure handle is not currently in use
         mHandle = mCustom;                     // Assign new handle
         if( mHandle != INVALID_HANDLE )        // Verify that it is valid
            return true;                        // Success
      };

      // Assignment failed
         PrintFormat( "Error %d: Failed to obtain %s indicator handle for symbol: %s, time-frame: %s",
            _LastError, mName, _Symbol, EnumToString( _Period ) );
         return false;
   };

// Support function to check bar count against total rates
   bool CheckBarCount( int mHandle, string mName, int nRatesTotal ) {
      ResetLastError();
      if( BarsCalculated( mHandle ) < nRatesTotal ) {
         PrintFormat( "Error %d: Insufficient %s indicator data available", _LastError, mName );
         return false;
      };
      return true;
   };

// Support function to check bars copied against required count
   bool CheckBarCopy( int mHandle, string mName, int nCount, int iBuffer, double &aBuffer[] ) {
      ResetLastError();
      int nCopied = CopyBuffer( mHandle, iBuffer, 0, nCount, aBuffer );
      if( nCopied < nCount ) {
         PrintFormat( "Error %d: Insufficient %s indicator data copied", _LastError, mName );
         return false;
      };
      return true;
   };

Now, ask away, about any doubts you may have.

EDIT: Also, please note that I have introduced the concept of a Macro instead of a support function. Macros can be used to make code more readable, especially when you need less overhead of function calls in favour of execution speed.

 
Fernando Carreiro #:

Things are going to start to get more complicated, so here is the next instalment (TestRex) to reproduce the following (please note the ATR indicator with a level line for reference):


Now, ask away, about any doubts you may have.

EDIT: Also, please note that I have introduced the concept of a Macro instead of a support function. Macros can be used to make code more readable, especially when you need less overhead of function calls in favour of execution speed.

Oh wow. This is some next level stuff.

This one is going to take me a little longer to digest. Will post back then or when I have hit a wall I can't get past.

 
Tristen Shaw #: Oh wow. This is some next level stuff. This one is going to take me a little longer to digest. Will post back then or when I have hit a wall I can't get past.

Ok, no problem! This thread is turning into a tutoring session, so no worries.

 
Tristen Shaw #: Oh wow. This is some next level stuff. This one is going to take me a little longer to digest. Will post back then or when I have hit a wall I can't get past.

Here is an update ...

Given, that when an Indicator gets to be more complex or highly depends on data from other indicators, it can begin to slow down. So it is up to the coder, to improve its efficiency in terms of speed.

In these cases, one can opt for the use of macros instead of functions, even if macros are not so "easy on the eyes".

The following code is equivalent the the previous post, but uses macros instead of function calls in the OnCalculate event handler. Compare the two and see which of the two is your cup of tea (or coffee).

// Define indicator properties

   // Define plotting considitions
      #property indicator_separate_window
      #property indicator_buffers 5
      #property indicator_plots   1

   // Define properties for REX plot
      #property indicator_label1  "ATR SignalSignal"
      #property indicator_type1   DRAW_LINE
      #property indicator_color1  clrGreen
      #property indicator_style1  STYLE_SOLID
      #property indicator_width1  1

// Macro definitions

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

   // Define macro to check indicators calculated bar count
      #define MCheckBarsCalculated( _handle, _name, _count ) { ResetLastError();                         \
         if( BarsCalculated( ( _handle ) ) < ( _count ) ) {                                              \
            PrintFormat( "Error %d: Insufficient %s indicator data available", _LastError, ( _name ) );  \
            return 0; }; }

   // Define macro to check bars copied from indicator against required count
      #define MCheckBarsCopied( _handle, _name, _count, _index, _buffer ) { ResetLastError();            \
         if( CopyBuffer( ( _handle ), ( _index ), 0, ( _count ), _buffer ) < ( _count ) ) {              \
            PrintFormat( "Error %d: Insufficient %s indicator data copied", _LastError, _name );         \
            return 0; }; }

// Declare input variables

   input group "Parameters: ATR settings"
      input uint
         inpAtrPeriod         = 14;                // ATR Period
      input double
         inpAtrTheshold       = 0.0025;            // ATR Threshold

   input group "Parameters: REX settings"
      input uint 
         inpRexPeriod         = 14,                // REX Period
         inpRexSignal         = 14;                // REX Signal Period
      input ENUM_MA_METHOD
         inpRexMethod         = MODE_SMA,          // REX Method
         inpRexSignalMethod   = MODE_SMA;          // REX Signal Method
   
// Declare indicator handles
   int 
      atrHandle               = INVALID_HANDLE,    // Handle for ATR indicator
      rexHandle               = INVALID_HANDLE;    // Handle for REX indicator

// Declare buffers arrays
   double
      atrThresholdBuffer[],                        // Array for ATR Theshold Signal
      atrBuffer[],                                 // Array for ATR buffer
      rexBuffer[],                                 // Array for REX buffer
      rexSignalBuffer[];                           // Array for REX signal buffer
   
// Support function to release all indicator handles
   void ReleaseAllHandles( void )
   {
      ReleaseHandle( atrHandle, "ATR" );
      ReleaseHandle( rexHandle, "REX" );
   };
   
// De-initialisation event handler
   void OnDeinit( const int reason ){ 
      ReleaseAllHandles(); 
   };
   
// Initialisation event handler
   int OnInit(){
      // Check parameters
         MCheckParameter( !( inpAtrTheshold > 0 ), "ATR Threshold"     );
         MCheckParameter(    inpAtrPeriod   < 1,   "ATR Period"        );
         MCheckParameter(    inpRexPeriod   < 1,   "REX Period"        );
         MCheckParameter(    inpRexSignal   < 1,   "REX Signal Period" );
   
      // Obtain and verify indicator handles
         ResetLastError();
         if( !AssignHandle( atrHandle, "ATR",
               iATR(    _Symbol, _Period, inpAtrPeriod                         ) ) ||
             !AssignHandle( rexHandle, "REX",
               iCustom( _Symbol, _Period, "REX",
                  inpRexPeriod, inpRexMethod, inpRexSignal, inpRexSignalMethod ) )    )
         {
            ReleaseAllHandles(); // Release all currently assigned indicator handles
            return INIT_FAILED;  // Initialisation has failed
         };
         
      // Set buffers (use autoindexing in case we need to reshuffle the sequence )
         int iBuffer = 0;  // Just to help to easily reshuffle buffers
         SetIndexBuffer( iBuffer++, atrThresholdBuffer, INDICATOR_DATA         );
         SetIndexBuffer( iBuffer++, atrBuffer,          INDICATOR_CALCULATIONS );
         SetIndexBuffer( iBuffer++, rexBuffer,          INDICATOR_CALCULATIONS );
         SetIndexBuffer( iBuffer++, rexSignalBuffer,    INDICATOR_CALCULATIONS );

      return INIT_SUCCEEDED;  // Successful initialisation of indicator
   };

// OnCalculate 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[] )
   {
      // Make sure we have rates data
         if( rates_total < 1 ) return 0; // No data available yet
         
      // Check number of calculated bars for indicators
         MCheckBarsCalculated( atrHandle, "ATR", rates_total );
         MCheckBarsCalculated( rexHandle, "REX", rates_total );

      // Calculate bar counting variables
         int
            // Adjust number of previously calculated bars accounting for incomplete current bar
               nPrevCalc    =   prev_calculated > rates_total ? rates_total     - 1
                            : ( prev_calculated > 1           ? prev_calculated - 1 : 0 ),
            // Calculate how many bars need to be updated
               nBarsUpdate  = rates_total - nPrevCalc;
         
      // Collect indicator data and check results
         MCheckBarsCopied( atrHandle, "ATR",        nBarsUpdate, 0, atrBuffer       );
         MCheckBarsCopied( rexHandle, "REX",        nBarsUpdate, 0, rexBuffer       );
         MCheckBarsCopied( rexHandle, "REX Signal", nBarsUpdate, 1, rexSignalBuffer );
            
      // Loop through the buffer indices and update values
         for( int iIndex = nPrevCalc; iIndex < rates_total; iIndex ++ ) {
            double atrValue = atrBuffer[ iIndex ];
            atrThresholdBuffer[ iIndex ]
               =   atrValue > inpAtrTheshold ? +1
               : ( atrValue < inpAtrTheshold ? -1
               : ( iIndex > 0 ? atrBuffer[ iIndex - 1 ] : 0 ) );
         };

      return rates_total;  // Return value for prev_calculated of next call
   };
   
// Support function to release indicator handle
   bool ReleaseHandle( int &mHandle, string mName ) {
      if( mHandle != INVALID_HANDLE ){
         ResetLastError();
         if( !IndicatorRelease( mHandle ) )
         {
            Print( "Error %d: Unable to release %s indicator handle", _LastError, mName );
            return false;
         };
         mHandle = INVALID_HANDLE;
      };
      return true;
   };
   
// Support function to assigning indicator handle
   bool AssignHandle( int &mHandle, string mName, int mCustom ) {
      if( ReleaseHandle( mHandle, mName ) ) {   // First make sure handle is not currently in use
         mHandle = mCustom;                     // Assign new handle
         if( mHandle != INVALID_HANDLE )        // Verify that it is valid
            return true;                        // Success
      };

      // Assignment failed
         PrintFormat( "Error %d: Failed to obtain %s indicator handle for symbol: %s, time-frame: %s",
            _LastError, mName, _Symbol, EnumToString( _Period ) );
         return false;
   };
 
Fernando Carreiro #:

Here is an update ...

Given, that when an Indicator gets to be more complex or highly depends on data from other indicators, it can begin to slow down. So it is up to the coder, to improve its efficiency in terms of speed.

In these cases, one can opt for the use of macros instead of functions, even if macros are not so "easy on the eyes".

The following code is equivalent the the previous post, but uses macros instead of function calls in the OnCalculate event handler. Compare the two and see which of the two is your cup of tea (or coffee).

Wow, is it normal to be a little intimidated by that?

Ok, what I am going to do is write these out by hand both for this and also replacing parts of my other project. Hopefully between the two I can start to wrap my head around it.

I'm more or less understanding them individually, but putting it all together in my head is a little harder since I didn't write them myself.

 
Tristen Shaw #: Wow, is it normal to be a little intimidated by that? Ok, what I am going to do is write these out by hand both for this and also replacing parts of my other project. Hopefully between the two I can start to wrap my head around it. I'm more or less understanding them individually, but putting it all together in my head is a little harder since I didn't write them myself.

It's totally OK not to use macros and only use functions. Most coders don't really worry too much much about code efficiency, so there is no need to feel overwhelmed. Stick to what you know and understand.

 
Fernando Carreiro #:

It's totally OK not to use macros and only use functions. Most coders don't really worry too much much about code efficiency, so there is no need to feel overwhelmed. Stick to what you know and understand.

Ok, I'm back on the job. Had a busy day or so but now I'm on it. Hope to have a post for you in a few hours. :)

I just realized that the picture in one of your last posts doesn't show up for me.
 
Tristen Shaw #: I just realized that the picture in one of your last posts doesn't show up for me.

What does show up for you? Remember that I stated that I added the ATR with level for comparison with the coded indicator.

 
Fernando Carreiro #:

What does show up for you? Remember that I stated that I added the ATR with level for comparison with the coded indicator.

Just a white square.

So I'm putting the ATR on the same window as the Rex together with a line for the threshold?

Reason: