Ok! Now lets tackle the OnInit. I will ignore the general structure and parameter inputs for now, but will come back to it later. I am currently focused on routing out problem areas. I am not trying to find your "bug" yet. My aim is to systematically improve the logic and remove future problems. The cleaner the code, the easier it will be to spot the actual bug. So ...
Currently in your OnInit code, you are doing the following in this sequence:
Assign buffers
Define plot settings
Obtain handles to other indicators
Test parameters
Test handles
Don't you think that something is wrong with that sequence?
Given that some of the operations will invalidate and force the indicator to terminate, don't you think you should follow a different sequence?
Ok! Now lets tackle the OnInit. I will ignore the general structure and parameter inputs for now, but will come back to it later. I am currently focused on routing out problem areas. I am not trying to find your "bug" yet. My aim is to systematically improve the logic and remove future problems. The cleaner the code, the easier it will be to spot the actual bug. So ...
Currently in your OnInit code, you are doing the following in this sequence:
Assign buffers
Define plot settings
Obtain handles to other indicators
Test parameters
Test handles
Don't you think that something is wrong with that sequence?
Given that some of the operations will invalidate and force the indicator to terminate, don't you think you should follow a different sequence?
Test parameters
Obtain handles to other indicators
Test handles
Assign buffers
Define plot settings
Ok, I see. Now, is this mainly a matter of efficiency? Like "Why have the computer do all this other work if it's possible that the tests might terminate the program anyway. Or is there a further reason aside from that?
New OnInit:
intOnInit(){
//--- indicator buffers mappingif( !( atrCrossLevel > 0 ) ) {
Print( "Error: Invalid ATR Cross Level" );
returnINIT_PARAMETERS_INCORRECT;
};
atrHandle = iATR(Symbol(), Period(),
atrPeriod);
rexHandle = iCustom(Symbol(), Period(), "REX",
confirmPeriod,
confirmPeriodMethod,
confirmSignal,
confirmSignalMethod);
if(rexHandle == INVALID_HANDLE || atrHandle == INVALID_HANDLE){
//--- tell about the failure and output the error codePrintFormat( "Failed to create handle of the iCustom indicator for the symbol %s/%s, error code %d",
Symbol(),
EnumToString(Period()),
GetLastError());
//--- the indicator is stopped early
initError = true;
return(INIT_FAILED);
}
SetIndexBuffer(0, sellBuffer, INDICATOR_DATA);
SetIndexBuffer(1, buyBuffer, INDICATOR_DATA);
SetIndexBuffer(2, atrBuffer, INDICATOR_CALCULATIONS);
SetIndexBuffer(3, rexPeriodBuffer, INDICATOR_CALCULATIONS);
SetIndexBuffer(4, rexSignalBuffer, INDICATOR_CALCULATIONS);
PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, 0.0);
PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, 0.0);
PlotIndexSetInteger(0, PLOT_ARROW, 159);
PlotIndexSetInteger(1, PLOT_ARROW, 159);
//---return(INIT_SUCCEEDED);
}
Tristen Shaw #: Ok, I see. Now, is this mainly a matter of efficiency? Like "Why have the computer do all this other work if it's possible that the tests might terminate the program anyway. Or is there a further reason aside from that? New OnInit:
Yes, and no! Yes, it is mainly the reason, but there is a second part which I am going to address now.
What do you think happens to the Indicator handles that you obtain?
Surely they need to be released when you no longer need them. One would assume that the terminal takes care of them when you terminate the indicator, but what if it does not?
Then we better make sure that our code does a proper clean-up. And we have to do it in two places. So, the sequence we follow in OnInit can be quite important.
One part, which you have not implemented, is during the OnDeinit() event handler and the other, is when you test the handles, when maybe one of them is invalid and you exit the OnInit() with a failed attempt.
To release the handles, you have to use IndicatorRelease. Have a look at the example code there. Also have a look at the example code for iATR, for the OnDeinit section and then also use the logic in your "testing handles" section.
This time I will wait for your attempt before I give you mine.
Yes, and no! Yes, it is mainly the reason, but there is a second part which I am going to address now.
What do you think happens to the Indicator handles that you obtain?
Surely they need to be released when you no longer need them. One would assume that the terminal takes care of them when you terminate the indicator, but what if it does not?
Then we better make sure that our code does a proper clean-up. And we have to do it in two places. So, the sequence we follow in OnInit can be quite important.
One part, which you have not implemented, is during the OnDeinit() event handler and the other, is when you test the handles, when maybe one of them is invalid and you exit the OnInit() with a failed attempt.
To release the handles, you have to use IndicatorRelease. Have a look at the example code there. Also have a look at the example code for iATR, for the OnDeinit section and then also use the logic in your "testing handles" section.
This time I will wait for your attempt before I give you mine.
Alright, here is what I came up with.
intOnInit(){
//--- indicator buffers mappingif( !( atrCrossLevel > 0 ) ) {
initError = true;
Print( "Error: Invalid ATR Cross Level" );
returnINIT_PARAMETERS_INCORRECT;
};
atrHandle = iATR(Symbol(), Period(),
atrPeriod);
rexHandle = iCustom(Symbol(), Period(), "REX",
confirmPeriod,
confirmPeriodMethod,
confirmSignal,
confirmSignalMethod);
if(rexHandle == INVALID_HANDLE || atrHandle == INVALID_HANDLE){
//--- tell about the failure and output the error codePrintFormat( "Failed to create handle of the iCustom indicator for the symbol %s/%s, error code %d",
Symbol(),
EnumToString(Period()),
GetLastError());
//--- the indicator is stopped early
initError = true;
return(INIT_FAILED);
}
if(initError){
if(!IndicatorRelease(atrHandle))
Print("IndicatorRelease() failed. Error ",GetLastError());
if(!IndicatorRelease(rexHandle))
Print("IndicatorRelease() failed. Error ",GetLastError());
}
//. . . other codevoidOnDeinit(constint reason){
if(!IndicatorRelease(atrHandle))
Print("IndicatorRelease() failed. Error ",GetLastError());
if(!IndicatorRelease(rexHandle))
Print("IndicatorRelease() failed. Error ",GetLastError());
}
Well, the first thing I notice that you didn't use the IndicatorRelease function at all in your code. I have to assume that there is a reason for this, but I can't say whether I agree or disagree with it since I don't know if there is some kind of advantage to doing it this way or not.
Otherwise, the function seems good. Easily expandable if new indicators where to be introduced later. Prevents the code from getting cluttered with lines and lines of the same error handling and such, replacing it with a simple function call.
I guess I would have to say that I agree with the differences. It's cleaner and more organized.
Ok, now I'm really off to sleep and tomorrow we will tackle the OnCalculate() and checking that the buffers are being filled correctly by CopyBuffer().
Next, some test code to simply copy and display the data obtained from iATR. Put up this indicator and the standard ATR indicator so as to compare the two.
Then look at the code and analyse, question and comment on it.
// Define indicator properties// Define plotting conditions#property indicator_separate_window#property indicator_buffers1#property indicator_plots1// Define properties for ATR plot#property indicator_label1"ATR"#property indicator_type1DRAW_LINE#property indicator_color1clrGreen#property indicator_style1STYLE_SOLID#property indicator_width11// Declare input variablesinputuint i_nAtrPeriod = 14; // Period for average true range// Declare buffer arraysdouble g_adbAtrBuffer[]; // Array for ATR buffer// Declare indicator handlesint g_hAtrHandle = INVALID_HANDLE; // Handle for ATR indicator// Support function to release indicator handlevoid ReleaseHandle( int &hHandle, string sName )
{
if( hHandle != INVALID_HANDLE )
{
ResetLastError();
if( IndicatorRelease( hHandle ) )
hHandle = INVALID_HANDLE;
elsePrint( "Error %d: Unable to release %s indicator handle", _LastError, sName );
};
};
// Support function to release all indicator handlesvoid ReleaseAllHandles( void )
{
ReleaseHandle( g_hAtrHandle, "iATR" );
};
// De-initialisation event handlervoidOnDeinit( constint reason )
{ ReleaseAllHandles(); };
// Initialisation event handlerintOnInit()
{
// Check parametersif( i_nAtrPeriod < 1 )
{
Print( "Error: Invalid ATR period" );
returnINIT_PARAMETERS_INCORRECT;
};
// Obtain indicator handlesResetLastError();
g_hAtrHandle = iATR( _Symbol, _Period, i_nAtrPeriod );
// Check validity of handlsif( g_hAtrHandle == INVALID_HANDLE )
{
PrintFormat( "Error %d: Failed to obtain indicator handles for symbol: %s, time-frame: %s",
_LastError, _Symbol, EnumToString( _Period ) );
ReleaseAllHandles();
returnINIT_FAILED;
};
// Set buffersSetIndexBuffer( 0, g_adbAtrBuffer, INDICATOR_DATA );
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// Obtain and check number of calculated bars for ATR indicatorResetLastError();
int nAtrBarsCalc = BarsCalculated( g_hAtrHandle );
if( nAtrBarsCalc < rates_total )
{
PrintFormat( "Error %d: Insufficient ATR indicator data available", _LastError );
return0;
};
// 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 ATR dataResetLastError();
int nAtrBarsCopied = CopyBuffer( g_hAtrHandle, 0, 0, nBarsUpdate, g_adbAtrBuffer );
if( nAtrBarsCopied < nBarsUpdate )
{
PrintFormat( "Error %d: Insufficient ATR data copied", _LastError );
return0;
};
return rates_total; // Return value for prev_calculated of next call
};
Don't worry. We will slowly build it up again to the full code you are developing.
Ok! Now lets tackle the OnInit. I will ignore the general structure and parameter inputs for now, but will come back to it later. I am currently focused on routing out problem areas. I am not trying to find your "bug" yet. My aim is to systematically improve the logic and remove future problems. The cleaner the code, the easier it will be to spot the actual bug. So ...
Currently in your OnInit code, you are doing the following in this sequence:
Don't you think that something is wrong with that sequence?
Given that some of the operations will invalidate and force the indicator to terminate, don't you think you should follow a different sequence?
Ok! Now lets tackle the OnInit. I will ignore the general structure and parameter inputs for now, but will come back to it later. I am currently focused on routing out problem areas. I am not trying to find your "bug" yet. My aim is to systematically improve the logic and remove future problems. The cleaner the code, the easier it will be to spot the actual bug. So ...
Currently in your OnInit code, you are doing the following in this sequence:
Don't you think that something is wrong with that sequence?
Given that some of the operations will invalidate and force the indicator to terminate, don't you think you should follow a different sequence?
Ok, I see. Now, is this mainly a matter of efficiency? Like "Why have the computer do all this other work if it's possible that the tests might terminate the program anyway. Or is there a further reason aside from that?
New OnInit:
Yes, and no! Yes, it is mainly the reason, but there is a second part which I am going to address now.
What do you think happens to the Indicator handles that you obtain?
Surely they need to be released when you no longer need them. One would assume that the terminal takes care of them when you terminate the indicator, but what if it does not?
Then we better make sure that our code does a proper clean-up. And we have to do it in two places. So, the sequence we follow in OnInit can be quite important.
One part, which you have not implemented, is during the OnDeinit() event handler and the other, is when you test the handles, when maybe one of them is invalid and you exit the OnInit() with a failed attempt.
To release the handles, you have to use IndicatorRelease. Have a look at the example code there. Also have a look at the example code for iATR, for the OnDeinit section and then also use the logic in your "testing handles" section.
This time I will wait for your attempt before I give you mine.
Yes, and no! Yes, it is mainly the reason, but there is a second part which I am going to address now.
What do you think happens to the Indicator handles that you obtain?
Surely they need to be released when you no longer need them. One would assume that the terminal takes care of them when you terminate the indicator, but what if it does not?
Then we better make sure that our code does a proper clean-up. And we have to do it in two places. So, the sequence we follow in OnInit can be quite important.
One part, which you have not implemented, is during the OnDeinit() event handler and the other, is when you test the handles, when maybe one of them is invalid and you exit the OnInit() with a failed attempt.
To release the handles, you have to use IndicatorRelease. Have a look at the example code there. Also have a look at the example code for iATR, for the OnDeinit section and then also use the logic in your "testing handles" section.
This time I will wait for your attempt before I give you mine.
Alright, here is what I came up with.
And here is my rendition ...
What do you see that is different?
Do you understand the differences?
Do you agree with the differences?
Remember that I can make mistakes too!
And here is my rendition ...
What do you see that is different?
Do you understand the differences?
Do you agree with the differences?
Remember that I can make mistakes too!
Well, the first thing I notice that you didn't use the IndicatorRelease function at all in your code. I have to assume that there is a reason for this, but I can't say whether I agree or disagree with it since I don't know if there is some kind of advantage to doing it this way or not.
Otherwise, the function seems good. Easily expandable if new indicators where to be introduced later. Prevents the code from getting cluttered with lines and lines of the same error handling and such, replacing it with a simple function call.
I guess I would have to say that I agree with the differences. It's cleaner and more organized.
Tristen Shaw #: Well, the first thing I notice that you didn't use the IndicatorRelease function at all in your code.
Look again ... OnDeinit() calls ReleaseAllHandles(), which calls ReleaseHandle() which calls IndicatorRelease().
Ok, here is continuing our saga ...
Next, some test code to simply copy and display the data obtained from iATR. Put up this indicator and the standard ATR indicator so as to compare the two.
Then look at the code and analyse, question and comment on it.
Don't worry. We will slowly build it up again to the full code you are developing.