Not getting correct results for indicators using iCustom and CopyBuffer

 

Hi. I am new to MQL5 so I apologise if I don't describe my issue well or use the correct terms. 

I am trying to get Indicator values using iCustom and CopyBuffer, but I am just getting zero values.

I am working on an Expert Advisor that uses three Indicators: TEMA (9), Vwap bands (9), and CCI (9).  The indicator files were given to me by a friend and I put the file in my Indicators folder: TEMA.ex5. vwap_bands,ex5, and CCI.ex5.

After some other false starts I have been following the instructions from here:

How to call indicators in MQL5 by KlimMalgin:  https://www.mql5.com/en/articles/43


Here are the globals:

// Global Indicator values
double TEMA_Value;
double VWAP_Value;
double CCI_Value;

// Global variables to store indicator handles
int TEMA_Handle;
int VWAP_Handle;
int CCI_Handle;


I get the Indicator handles using iCustom in OnInit:

int OnInit()
  {

         TEMA_Handle = iCustom(NULL,0,"TEMA",
                                TEMA_Period,          // Period
                                0,                    // Offset
                                MODE_SMA,             // Calculation method
                                PRICE_CLOSE           // Calculating on Close prices
                       );
   
      
         VWAP_Handle = iCustom(NULL,0,"vwap_bands",
                                VWAP_Period,          // Period
                                PRICE_CLOSE,           // Calculating on Close prices
                                0,                    // UseRealVolume
                                0,                    // DeviationSample
                                1.0,                // DeviationMuliplier1
                                2.0,                // DeviationMuliplier2
                                2.5                // DeviationMuliplier3
                       );
      
         CCI_Handle = iCustom(NULL,0,"CCI",
                                CCI_Period,           // Period
                                PRICE_TYPICAL         // Calculating on Typical prices
                       ); 
    
      U

...
}


I set up a method that is called to use the handles to get the current values:

void UpdateIndicators()
{
   //Update Indicators
   // Dynamic arrays to store indicators values
   double _tema[],
          _vwap[],
          _cci[];
   
   // Setting the indexing in arrays the same as in timeseries, i.e. array element with zero
   // index will store the values of the last bar, with 1th index - the last but one, etc.
      ArraySetAsSeries(_tema, true);
      ArraySetAsSeries(_vwap, true);
      ArraySetAsSeries(_cci, true);
   
   // Using indicators handles, let's copy the values of indicator
   // buffers to arrays, specially prepared for this purpose
      if (CopyBuffer(TEMA_Handle,0,0,20,_tema) < 0){Print("CopyBuffer TEMA error =",GetLastError());}
      if (CopyBuffer(VWAP_Handle,0,0,20,_vwap) < 0){Print("CopyBuffer VWAP error =",GetLastError());}
      if (CopyBuffer(CCI_Handle,0,0,20,_cci) < 0){Print("CopyBuffer CCI error =",GetLastError());}

}


Then call the method at the beginning of OnTick:

void OnTick()
{

   UpdateIndicators();     //Update Indicators
 ...
}


The log shows that the indicators were loaded successfully.

I was a bit puzzled why no code was changing states to reflect what the indicators were doing. (I also display them on a chart.)  Then when I started printing them as comments and to the log, I found they are all zero.

I am wondering whether the root cause is how I call iCustom initially. My understanding is that the arguments from #4 onwards should reflect the parameters that the indicator would have when it displays on the chart. This is what I have tried to use.


Thanks for any help.

Regards,

Dave

How to call indicators in MQL5
How to call indicators in MQL5
  • www.mql5.com
With new version of MQL programming language available not only the approach of dealing with indicators have changed, but there are also new ways of how to create indicators. Furthermore, you have additional flexibility working with indicator's buffers - now you can specify the desired direction of indexing and get exactly as many indicator's values as you want. This article explains the basic methods of calling indicators and retrieving data from the indicator's buffers.
 
David Anthony Waddington:
TEMA_Value

Oops! Looks like I worked out the main problem. I didn't assign the values from the arrays. Silly mistake.


      TEMA_Value = _tema[0];
      VWAP_Value = _vwap[0];
      CCI_Value = _cci[0];


At least I'm getting some values now, but they look way different from what's on the chart, and TEMA is still 0.

Looks like I'm not passing the correct parameters to iCustom. How should I find them?

 
David Anthony Waddington #:

Oops! Looks like I worked out the main problem. I didn't assign the values from the arrays. Silly mistake.



At least I'm getting some values now, but they look way different from what's on the chart, and TEMA is still 0.

Looks like I'm not passing the correct parameters to iCustom. How should I find them?

Are you sure TEMA indicator you are using is not repainiting?

Please test firstly with some simpler indicators, like MA, RSI, CCI.

I never found an issue in using iCustom and CopyBuffers for several different indicators, but of course if you are using a repainting indicator you need to be aware of potential consequences!

 

I also tried getting handles using the standard MQL5 calls for TEMA and CCI:

         TEMA_Handle = iTEMA(NULL, 0, TEMA_Period, 0, PRICE_CLOSE);
         CCI_Handle = iCCI(NULL, 0, CCI_Period, PRICE_TYPICAL);

Still not getting the right values from CopyBuffer.

 
David Anthony Waddington #:

I also tried getting handles using the standard MQL5 calls for TEMA and CCI:

Still not getting the right values from CopyBuffer.

Are you sure you are watching indicators on chart with same parameters of your handles inside the EA?
 
Fabio Cavalloni #:
Are you sure you are watching indicators on chart with same parameters of your handles inside the EA?

Thanks for your reply. Yes, as far as I can tell. I used the values from the properties of the indicators on the chart in the iCustom call, or at least I think I have. However, as I am new to this, I could have gotten something wrong.

Should I be passing all values from the properties, and in the same order?



 
Fabio Cavalloni #:

Are you sure TEMA indicator you are using is not repainiting?

Please test firstly with some simpler indicators, like MA, RSI, CCI.

I never found an issue in using iCustom and CopyBuffers for several different indicators, but of course if you are using a repainting indicator you need to be aware of potential consequences!

OK. I will try with some simpler indicators. Thank you for the suggestion.

 
Fabio Cavalloni #:

Are you sure TEMA indicator you are using is not repainiting?

Please test firstly with some simpler indicators, like MA, RSI, CCI.

I never found an issue in using iCustom and CopyBuffers for several different indicators, but of course if you are using a repainting indicator you need to be aware of potential consequences!

Actually, CCI is one of the indicators I am using. 

 

Without the full code, it's hard to tell what's going on. But there're two things you can do to debug your code and try to find some errors:


1 - whenever you create a handle to an indicator (iMA, iCCI, iCustom, etc.), compare the value the function returned to check if the handle is invalid (that will probably not be your case, since you said the log registered a successful indicator creation):


TEMA_Handle = iTEMA(NULL, 0, TEMA_Period, 0, PRICE_CLOSE);

if(TEMA_Handle == INVALID_HANDLE)
{
        Print("Couldn't load the TEMA indicator.");
        return INIT_FAILED;
}

Print("TEMA_Handle ", TEMA_Handle, "loaded successfully."); // this is not necessary and may reduce the code speed in optimizations, but may help you debugging errors like this sometimes


2 - the most important ability to find errors is to know how to debug your code. Setup breakpoints in points of interest where bugs may occur in your code (the calls to iCustom and the UpdateIndicators functions). Store any value returned by a MQL5 function (like CopyBuffer) and check line by line what the debug shows to the stored variables (and the parameters passed to it function before they are called) and, if there's any, what error does the functions return.

Just for instance: when debugging with breakpoints, Step Into (F11) makes you go inside a function it's currently about to be executed; Step Over (F12) executes the current line and jumps to the next one, not entering inside a function if it was possible; Step Out (Shift+F11) makes you go back to to the caller function, skipping all lines of the current function up to the return point.

By doing this, you can see if there's an error going on with your code (for example, some parameter used in the CopyBuffer may be changing somewhere else before the function is called, thus causing it to fail; since we don't have the code, that's something you'll have to figure out by yourself).


3 - If possible, and if you don't want to share your original code, create a new simple code where the bugs are reproducible so we can test and try to figure out where it is going wrong. 

 
Emanuel Cavalcante Amorim Filho #:

Without the full code, it's hard to tell what's going on. But there're two things you can do to debug your code and try to find some errors:


1 - whenever you create a handle to an indicator (iMA, iCCI, iCustom, etc.), compare the value the function returned to check if the handle is invalid (that will probably not be your case, since you said the log registered a successful indicator creation):



2 - the most important ability to find errors is to know how to debug your code. Setup breakpoints in points of interest where bugs may occur in your code (the calls to iCustom and the UpdateIndicators functions). Store any value returned by a MQL5 function (like CopyBuffer) and check line by line what the debug shows to the stored variables (and the parameters passed to it function before they are called) and, if there's any, what error does the functions return.

Just for instance: when debugging with breakpoints, Step Into (F11) makes you go inside a function it's currently about to be executed; Step Over (F12) executes the current line and jumps to the next one, not entering inside a function if it was possible; Step Out (Shift+F11) makes you go back to to the caller function, skipping all lines of the current function up to the return point.

By doing this, you can see if there's an error going on with your code (for example, some parameter used in the CopyBuffer may be changing somewhere else before the function is called, thus causing it to fail; since we don't have the code, that's something you'll have to figure out by yourself).


3 - If possible, and if you don't want to share your original code, create a new simple code where the bugs are reproducible so we can test and try to figure out where it is going wrong. 

Thanks for the great suggestions. I should have have added that code at the beginning to verify that the handles. I have done this and  I can now say that they are valid.

Also, while working through the code I did pick up another error. There was a mistake in my trace and I was choosing the indicators in the wrong order. I can now say that all three indicators are being assigned values, but they are still very different to what is on the chart.

I can't see how the parameters in CopyBuffer could change, as most are constants, the indicator handles are not changed, and the array is what is assigned to. However, I am very green at this, so please tell me if I am wrong.

You can probably understand why I am reluctant to share the whole code. I have created an EA that only tests the indicators, as per your suggestion. (Something else I should have done early on.)

Here is the full test code:

//+------------------------------------------------------------------+
//|                                              test_indicators.mq5 |
//|                    Copyright 2024, David Waddington.             |
//|                    https://www.mql5.com/en/users/davewaddington&nbsp; |
//+------------------------------------------------------------------+

#include <Trade\Trade.mqh>       // Standard library for trading operations
#include <Trade\SymbolInfo.mqh>  // Standard library for symbol information
#include <Expert\Money\MoneyFixedRisk.mqh>
#include <Indicators\Oscilators.mqh>
#include <Trade\PositionInfo.mqh>


// Global Input Variables
input int TEMA_Period = 9;        // TEMA period
input int VWAP_Period = 9;       // VWAP bands period
input int CCI_Period = 9;         // CCI period

// Global Indicator values
double TEMA_Value;
double VWAP_Value;
double CCI_Value;

// Global variables to store indicator handles
int TEMA_Handle;
int VWAP_Handle;
int CCI_Handle;


        

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {

         
         TEMA_Handle = iCustom(NULL,0,"TEMA",
                                TEMA_Period,          // Period
                                0,                    // Offset
                                MODE_SMA,             // Calculation method
                                PRICE_CLOSE           // Calculating on Close prices
                       );
                       
         if(TEMA_Handle == INVALID_HANDLE)
               {
                       Print("Couldn't load the TEMA indicator.");
                       return INIT_FAILED;
               }

         Print("TEMA_Handle ", TEMA_Handle, " loaded successfully."); // this is not necessary and may reduce the code speed in optimizations, but may help you debugging errors like this sometimes
      
         VWAP_Handle = iCustom(NULL,0,"vwap_bands",
                                VWAP_Period,          // Period
                                PRICE_CLOSE,           // Calculating on Close prices
                                0,                    // UseRealVolume
                                0,                    // DeviationSample
                                1.0,                // DeviationMuliplier1
                                2.0,                // DeviationMuliplier2
                                2.5                // DeviationMuliplier3
                       );

         if(VWAP_Handle == INVALID_HANDLE)
               {
                       Print("Couldn't load the VWAP indicator.");
                       return INIT_FAILED;
               }

         Print("VWAP_Handle ", VWAP_Handle, " loaded successfully."); // this is not necessary and may reduce the code speed in optimizations, but may help you debugging errors like this sometimes
   
         
         CCI_Handle = iCustom(NULL,0,"CCI",
                                CCI_Period,           // Period
                                PRICE_TYPICAL         // Calculating on Typical prices
                       ); 

         if(CCI_Handle == INVALID_HANDLE)
               {
                       Print("Couldn't load the CCI indicator.");
                       return INIT_FAILED;
               }

         Print("CCI_Handle ", CCI_Handle, " loaded successfully."); // this is not necessary and may reduce the code speed in optimizations, but may help you debugging errors like this sometimes

         UpdateIndicators();     //Update Indicators
      
         string debugComment = StringFormat("TEMA = %d, VWAP = %d, CCI = %d", TEMA_Value, VWAP_Value, CCI_Value);
         printf(debugComment);
         Comment(debugComment);
                             
         return INIT_SUCCEEDED;
  }
  
  
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{

   UpdateIndicators();     //Update Indicators
 
   string debugComment = StringFormat("TEMA = %d, VWAP = %d, CCI = %d", TEMA_Value, VWAP_Value, CCI_Value);
//   printf(debugComment);
   Comment(debugComment);
   

}

             


void UpdateIndicators()
{
   //Update Indicators
   // Dynamic arrays to store indicators values
   double _tema[],
          _vwap[],
          _cci[];
   
   // Setting the indexing in arrays the same as in timeseries, i.e. array element with zero
   // index will store the values of the last bar, with 1th index - the last but one, etc.
      ArraySetAsSeries(_tema, true);
      ArraySetAsSeries(_vwap, true);
      ArraySetAsSeries(_cci, true);
   
   // Using indicators handles, let's copy the values of indicator
   // buffers to arrays, specially prepared for this purpose
      if (CopyBuffer(TEMA_Handle,0,0,20,_tema) < 0){Print("CopyBuffer TEMA error =",GetLastError());}
      if (CopyBuffer(VWAP_Handle,0,0,20,_vwap) < 0){Print("CopyBuffer VWAP error =",GetLastError());}
      if (CopyBuffer(CCI_Handle,0,0,20,_cci) < 0){Print("CopyBuffer CCI error =",GetLastError());}
      
      TEMA_Value = _tema[0];
      VWAP_Value = _vwap[0];
      CCI_Value = _cci[0];
      

}


Here is a screen grab of the result:



Could it be that I am extracting from the arrays incorrectly?

      TEMA_Value = _tema[0];
      VWAP_Value = _vwap[0];
      CCI_Value = _cci[0];


Thanks again for all the great help, and your patience.

 

Although I could not test the exact code you provided, since I don't have the custom TEMA, CCI or VWAP you're using, I see you said that even using the built-in functions the errors still occured, so I just changed the TEMA and CCI iCustom calls to their respective built-in function and removed any reference to the VWAP indicator so my code could compile.


At first glance, I also didn't see anything wrong with your code - and I was also getting wrong results int the Comment function. So I proceeded and placed a breakpoint in many points of interest - to make it short, one of the breakpoints was set in the last line of the UpdateIndicators function and then ran the EA in the debug mode.


The first execution of the UpdateIndicators (which is called from inside the OnInit function) fills both buffers with 0, since there's no data ready to be read from the indicators handle.

The second call to the UpdateIndicators, however, fills both buffers with what looks like it's the correct data, as you can see:




These values correspond to the last bar where the breakpoint was triggered:



The only thing happening afterwards was that you were calling StringFormat and Comment to print the values - and here lies the error. The type specifier %d is only used for integers, not doubles (check the documentation for PrintFormat, to which the user is redirected from the StringFormat doc page). 

When you say

StringFormat("TEMA = %d, CCI = %d", TEMA_Value, CCI_Value)

you're actually telling the function that the TEMA_Value and CCI_Value variables addresses actually points to an integer value - it behaves just like the printf function in c/c++. The function then gets the addresses of these variables and then convert their bytes directly to integers, but the way doubles and integers are represented in memory is not the same. That's why Comment was printing some weird seemingly random values (they were not random, their bytes, if interpreted as a double, would show the correct values).

Just change the function to 

StringFormat("TEMA = %.2f, CCI = %.2f", TEMA_Value, CCI_Value)

and you're golden.


Also, if you allow me:


1 - the buffers arrays (_tema[] and _cci[]) can actually be created as global variables, and so ArraySetAsSeries can be called only once in the OnInit function (there's no need to call it every tick in the UpdateIndicators function.

2 - if there isn't a really good need to assign the value of the buffer to a variable, it may be better to work directly with the array passed to CopyBuffer. This reduces the amount of memory the EA uses (ofc today this is a small problem, but in bigger projects, using multiple EAs, this may become an issue) and makes your code less complex to debug, since you only need to take care of one variable instead of two.

3 - I assume you actually need the data of the last 20 bars for these indicators. If you don't, try to copy the amount of bars you need. Again, this is a small problem these days, but if you are work on a big project that checks and updates every buffer every tick from the past 5 years, imagine how much data you are actually copying and how much time you can save.

4 - if there're built-in indicators, prefer using them rather than custom indicators that do the same stuff (ofc, unless the custom indicators provide new functionalities the built-in ones don't). Custom indicators may be poorly written and also result in bugs (I had a big trouble finding a bug where CopyBuffer actually sometimes filled my indicator data correctly, sometimes not, until I realized the problem was in my indicator's code, so I had to rewrite it entirely).


I'll leave my code suggestion here (also note that there may be bugs with your custom indicators that we cannot test):


#include <Trade\Trade.mqh>       // Standard library for trading operations
#include <Trade\SymbolInfo.mqh>  // Standard library for symbol information
#include <Expert\Money\MoneyFixedRisk.mqh>
#include <Indicators\Oscilators.mqh>
#include <Trade\PositionInfo.mqh>


// Global Input Variables
input int TEMA_Period = 9;        // TEMA period
input int CCI_Period = 9;         // CCI period

// Global variables to store indicator handles
int TEMA_Handle;
int CCI_Handle;

double tema_buffer[], cci_buffer[];



//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{


    TEMA_Handle = iTEMA(NULL, 0, TEMA_Period, 0, PRICE_CLOSE);

    if(TEMA_Handle == INVALID_HANDLE)
    {
        Print("Couldn't load the TEMA indicator.");
        return INIT_FAILED;
    }

    Print("TEMA_Handle ", TEMA_Handle, " loaded successfully.");


    CCI_Handle = iCCI(NULL, 0, CCI_Period, PRICE_TYPICAL);

    if(CCI_Handle == INVALID_HANDLE)
    {
        Print("Couldn't load the CCI indicator.");
        return INIT_FAILED;
    }

    Print("CCI_Handle ", CCI_Handle, " loaded successfully.");

    ArraySetAsSeries(tema_buffer, true);
    ArraySetAsSeries(cci_buffer, true);

    return INIT_SUCCEEDED;
}


//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{

    if(UpdateIndicators()==false) return;     //Update Indicators

    string debugComment = StringFormat("TEMA = %.2f, CCI = %.2f", tema_buffer[0], cci_buffer[0]);
    Comment(debugComment);
}




//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool UpdateIndicators()
{
    if (CopyBuffer(TEMA_Handle, 0, 0, 20, tema_buffer) < 0)
    {
        Print("CopyBuffer TEMA error =", GetLastError());
        return false;
    }
    if (CopyBuffer(CCI_Handle, 0, 0, 20, cci_buffer) < 0)
    {
        Print("CopyBuffer CCI error =", GetLastError());
        return false;
    }
    
    return true;
}
Documentação sobre MQL5: Funções Comuns / PrintFormat
Documentação sobre MQL5: Funções Comuns / PrintFormat
  • www.mql5.com
Formata e entra conjuntos de símbolos e valores no log do Expert Advisor em concordância com um formato predefinido. Parâmetros...
Reason: