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_buffers4#property indicator_plots1// Define properties for REX plot#property indicator_label1"ATR Threshold Signal"#property indicator_type1DRAW_LINE#property indicator_color1clrGreen#property indicator_style1STYLE_SOLID#property indicator_width11// Macro definitions// Define macro for invalid parameter values#define MCheckParameter( _condition, _text ) if( _condition ) \
{ Print( "Error: Invalid ", _text ); returnINIT_PARAMETERS_INCORRECT; }
// Declare input variablesinput group "Parameters: ATR settings"inputuint
inpAtrPeriod = 14; // ATR Periodinputdouble
inpAtrTheshold = 0.0025; // ATR Thresholdinput group "Parameters: REX settings"inputuint
inpRexPeriod = 14, // REX Period
inpRexSignal = 14; // REX Signal PeriodinputENUM_MA_METHOD
inpRexMethod = MODE_SMA, // REX Method
inpRexSignalMethod = MODE_SMA; // REX Signal Method// Declare indicator handlesint
atrHandle = INVALID_HANDLE, // Handle for ATR indicator
rexHandle = INVALID_HANDLE; // Handle for REX indicator// Declare buffers arraysdouble
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 handlesvoid ReleaseAllHandles( void )
{
ReleaseHandle( atrHandle, "ATR" );
ReleaseHandle( rexHandle, "REX" );
};
// De-initialisation event handlervoidOnDeinit( constint reason ){
ReleaseAllHandles();
};
// Initialisation event handlerintOnInit(){
// 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 handlesResetLastError();
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 handlesreturnINIT_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 buffersSetIndexBuffer( iBuffer++, atrThresholdBuffer, INDICATOR_DATA );
SetIndexBuffer( iBuffer++, atrBuffer, INDICATOR_CALCULATIONS );
SetIndexBuffer( iBuffer++, rexBuffer, INDICATOR_CALCULATIONS );
SetIndexBuffer( iBuffer++, rexSignalBuffer, INDICATOR_CALCULATIONS );
returnINIT_SUCCEEDED; // Successful initialisation of indicator
};
// OnCalculate event handlerintOnCalculate( constint rates_total,
constint prev_calculated,
constdatetime &time[],
constdouble &open[],
constdouble &high[],
constdouble &low[],
constdouble &close[],
constlong &tick_volume[],
constlong &volume[],
constint &spread[] )
{
// Make sure we have rates dataif( rates_total < 1 ) return0; // No data available yet// Check number of calculated bars for indicatorsif( !CheckBarCount( atrHandle, "ATR", rates_total ) ||
!CheckBarCount( rexHandle, "REX", rates_total ) )
return0; // Bar count check failed// Calculate bar counting variablesint// 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 resultsif( !CheckBarCopy( atrHandle, "ATR", nBarsUpdate, 0, atrBuffer ) ||
!CheckBarCopy( rexHandle, "REX", nBarsUpdate, 0, rexBuffer ) ||
!CheckBarCopy( rexHandle, "REX Signal", nBarsUpdate, 1, rexSignalBuffer ) )
return0; // Indicator data collection failed// Loop through the buffer indices and update valuesfor( 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 handlebool ReleaseHandle( int &mHandle, string mName ) {
if( mHandle != INVALID_HANDLE ){
ResetLastError();
if( !IndicatorRelease( mHandle ) )
{
Print( "Error %d: Unable to release %s indicator handle", _LastError, mName );
returnfalse;
};
mHandle = INVALID_HANDLE;
};
returntrue;
};
// Support function to assigning indicator handlebool AssignHandle( int &mHandle, string mName, int mCustom ) {
if( ReleaseHandle( mHandle, mName ) ) { // First make sure handle is not currently in use
mHandle = mCustom; // Assign new handleif( mHandle != INVALID_HANDLE ) // Verify that it is validreturntrue; // Success
};
// Assignment failedPrintFormat( "Error %d: Failed to obtain %s indicator handle for symbol: %s, time-frame: %s",
_LastError, mName, _Symbol, EnumToString( _Period ) );
returnfalse;
};
// Support function to check bar count against total ratesbool CheckBarCount( int mHandle, string mName, int nRatesTotal ) {
ResetLastError();
if( BarsCalculated( mHandle ) < nRatesTotal ) {
PrintFormat( "Error %d: Insufficient %s indicator data available", _LastError, mName );
returnfalse;
};
returntrue;
};
// Support function to check bars copied against required countbool 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 );
returnfalse;
};
returntrue;
};
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.
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_buffers5#property indicator_plots1// Define properties for REX plot#property indicator_label1"ATR SignalSignal"#property indicator_type1DRAW_LINE#property indicator_color1clrGreen#property indicator_style1STYLE_SOLID#property indicator_width11// Macro definitions// Define macro for invalid parameter values#define MCheckParameter( _condition, _text ) { if( _condition ) \
{ Print( "Error: Invalid ", _text ); returnINIT_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 ) ); \
return0; }; }
// 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 ); \
return0; }; }
// Declare input variablesinput group "Parameters: ATR settings"inputuint
inpAtrPeriod = 14; // ATR Periodinputdouble
inpAtrTheshold = 0.0025; // ATR Thresholdinput group "Parameters: REX settings"inputuint
inpRexPeriod = 14, // REX Period
inpRexSignal = 14; // REX Signal PeriodinputENUM_MA_METHOD
inpRexMethod = MODE_SMA, // REX Method
inpRexSignalMethod = MODE_SMA; // REX Signal Method// Declare indicator handlesint
atrHandle = INVALID_HANDLE, // Handle for ATR indicator
rexHandle = INVALID_HANDLE; // Handle for REX indicator// Declare buffers arraysdouble
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 handlesvoid ReleaseAllHandles( void )
{
ReleaseHandle( atrHandle, "ATR" );
ReleaseHandle( rexHandle, "REX" );
};
// De-initialisation event handlervoidOnDeinit( constint reason ){
ReleaseAllHandles();
};
// Initialisation event handlerintOnInit(){
// 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 handlesResetLastError();
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 handlesreturnINIT_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 buffersSetIndexBuffer( iBuffer++, atrThresholdBuffer, INDICATOR_DATA );
SetIndexBuffer( iBuffer++, atrBuffer, INDICATOR_CALCULATIONS );
SetIndexBuffer( iBuffer++, rexBuffer, INDICATOR_CALCULATIONS );
SetIndexBuffer( iBuffer++, rexSignalBuffer, INDICATOR_CALCULATIONS );
returnINIT_SUCCEEDED; // Successful initialisation of indicator
};
// OnCalculate event handlerintOnCalculate( constint rates_total,
constint prev_calculated,
constdatetime &time[],
constdouble &open[],
constdouble &high[],
constdouble &low[],
constdouble &close[],
constlong &tick_volume[],
constlong &volume[],
constint &spread[] )
{
// Make sure we have rates dataif( rates_total < 1 ) return0; // No data available yet// Check number of calculated bars for indicators
MCheckBarsCalculated( atrHandle, "ATR", rates_total );
MCheckBarsCalculated( rexHandle, "REX", rates_total );
// Calculate bar counting variablesint// 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 valuesfor( 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 handlebool ReleaseHandle( int &mHandle, string mName ) {
if( mHandle != INVALID_HANDLE ){
ResetLastError();
if( !IndicatorRelease( mHandle ) )
{
Print( "Error %d: Unable to release %s indicator handle", _LastError, mName );
returnfalse;
};
mHandle = INVALID_HANDLE;
};
returntrue;
};
// Support function to assigning indicator handlebool AssignHandle( int &mHandle, string mName, int mCustom ) {
if( ReleaseHandle( mHandle, mName ) ) { // First make sure handle is not currently in use
mHandle = mCustom; // Assign new handleif( mHandle != INVALID_HANDLE ) // Verify that it is validreturntrue; // Success
};
// Assignment failedPrintFormat( "Error %d: Failed to obtain %s indicator handle for symbol: %s, time-frame: %s",
_LastError, mName, _Symbol, EnumToString( _Period ) );
returnfalse;
};
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.
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.
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):
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.
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.
Ok, no problem! This thread is turning into a tutoring session, so no worries.
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).
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.
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.
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.What does show up for you? Remember that I stated that I added the ATR with level for comparison with the coded indicator.
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?