Got my code going, but not like I was hoping.

 

Ok,

I'm working on a simplified indicator that I plan on using in my EA.

First off, I am not looking for it to be done for me. If you like, give me a hint and I'll try to figure it out.

What I have done:

I have watched the*** videos on making an indicator for MT5. In fact, the framework of my indicator is based on that.

I've read the documentation of all of the key functions and constants etc etc.

And I've Googled numerous issues.

I was having trouble with SetIndexBuffer altering the values I was getting from the buffers. But now I think I'm getting good values. Which I determined by printing out the variables and traced it back the the SetIndexBuffer. I took that function off of all but the arrow buffer and it seems like that did it for those issues.

It's printing out the dots, and even changing their locations, but not at the right points. And I can't figure out why.

Errors:

0 Errors on compile

The Goal:

The indicator is based on the Waddah Attar Explosion. Basically, when a bar rises above the deadzone level it's suppose to change the trend in that direction till a bar of the opposite color rises above the deadzone and changes it to the other direction.

I will be adding other filters later, but I just want to figure out the basics of how to get it all running smoothly first.

//+------------------------------------------------------------------+
//|                                                Phoenix Trend.mq5 |
//|                              Copyright 2022, Phoenix Investments |
//|                               https://www.phoenixinvestments.com |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Properties and Buffers                                           |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots 1

#property indicator_type1 DRAW_ARROW
#property indicator_label1 "Trend Indicator"
#property indicator_color1 clrRoyalBlue, clrCrimson
#property indicator_width1 5
//+------------------------------------------------------------------+
//| Indicator Settings                                               |
//+------------------------------------------------------------------+
input int
   macdFast = 20, // MACD Fast
   macdSlow = 40, //MACD Slow
   bbPeriod = 20, //BB Period
   bbDeviation = 2, // BB Deviation
   sensitive = 150, //Sensitivity
   deadZoneLevel = 400, //Deadzone Level
   explosionLevel = 15, //Explosion Level
   trendPower = 150; //Trend Power
//+------------------------------------------------------------------+
//| Global Variables                                                 |
//+------------------------------------------------------------------+
enum Status {UNSET, INVALID, LONG, SHORT};

double
   waeHandle;
   
double
   waeValueBuffer[],
   waeDZBuffer[],
   waeColorBuffer[],
   arrowBuffer[];
   
int 
   maxPeriod;
   
Status
   curTrend = UNSET;

bool
   once = false;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   Print("Initialized!");
   
   SetIndexBuffer(0, arrowBuffer, INDICATOR_DATA);
   //SetIndexBuffer(1, waeValueBuffer, INDICATOR_DATA);
   //SetIndexBuffer(2, waeDZBuffer, INDICATOR_DATA);
   //SetIndexBuffer(3, waeColorBuffer, INDICATOR_DATA);
   
   maxPeriod = (int)MathMax(MathMax(macdFast, macdSlow), bbPeriod);
   
   waeHandle = iCustom(_Symbol,_Period,"Waddah Attar Explosion",
                     macdFast,
                     macdSlow,
                     bbPeriod,
                     bbDeviation,
                     sensitive,
                     deadZoneLevel,
                     explosionLevel,
                     trendPower);  
                     
   PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, maxPeriod);
   
   return(INIT_SUCCEEDED);
  }
  
//+------------------------------------------------------------------+
//| Custom indicator Deinitialization function                       |
//+------------------------------------------------------------------+
  
int OnDeinit(){
   
   if(waeHandle != INVALID_HANDLE) IndicatorRelease(waeHandle);
   return(0);
}

//+------------------------------------------------------------------+
//| 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[])
  {
//---    
   if(IsStopped()) return(0);
   if(rates_total < maxPeriod) return(0);
   if(BarsCalculated(waeHandle) < rates_total)return(0);
   
   int copyBars = 0;
   int startBar = 0;   
   
   if(prev_calculated < rates_total || prev_calculated <= 0){
      copyBars = rates_total;
      startBar = maxPeriod;
   } else {
      copyBars = rates_total-prev_calculated;
      if(prev_calculated > 0) copyBars++;
      startBar = prev_calculated - 1;
   }   
   
   if(IsStopped()) return(0);
   for(int bar = startBar; bar < rates_total && !IsStopped(); bar++){
      if(CopyBuffer(waeHandle, 0, bar, 1, waeValueBuffer) <= 0) return(0);
      if(CopyBuffer(waeHandle, 1, bar, 1, waeColorBuffer) <= 0) return(0);
      if(CopyBuffer(waeHandle, 3, bar, 1, waeDZBuffer) <= 0) return(0);
      
      if(IsStopped()) return(0);
    
         //Print(waeValueBuffer[0], " || ", waeDZBuffer[0]);
         if(waeValueBuffer[0] > waeDZBuffer[0]){
            //Print(waeColorBuffer[0]);
            curTrend = (waeColorBuffer[0] == 1.0) ? LONG : SHORT;
            //Print(EnumToString(curTrend));
         }
         
         if(curTrend == LONG){
            arrowBuffer[bar] = low[bar];
         }else if (curTrend == SHORT){
            arrowBuffer[bar] = high[bar];
         }else{}
   }
   return(rates_total);
  }
//+------------------------------------------------------------------+

I'm willing to do the legwork (head work) but I need a pointer.

 
You need to get a few things straight: Does it compile without errors or not?
I am pretty sure it is not possible to run another iCustom inside a custom Indicator.
Yes, SetIndexBuffer and the way it works together with #property buffer properties is one of the most prominent sources of errors in Indicators.
You need to make sure you have the right amount of buffers and plots. If I am right the Waddah Attar has color changing bars so you should look into how many buffers you need for different drawing styles in reference.
 
Tobias Johannes Zimmer #:
You need to get a few things straight: Does it compile without errors or not?
I am pretty sure it is not possible to run another iCustom inside a custom Indicator.
Yes, SetIndexBuffer and the way it works together with #property buffer properties is one of the most prominent sources of errors in Indicators.
You need to make sure you have the right amount of buffers and plots. If I am right the Waddah Attar has color changing bars so you should look into how many buffers you need for different drawing styles in reference.

0 errors.

If I can't use iCustom in an indicator, would that means that I have no choice but to integrate it's functionality directly into my EA?

Yes, the WAE has color changing bars. If I have investigated the indexes properly, it's index 1 that contains the color. 1 for green bars and 2 for red ones. I don't draw any of these. However, I do want to change the color of my dots based on the trend.

 
Tristen Shaw #: If I can't use iCustom in an indicator, would that means that I have no choice but to integrate it's functionality directly into my EA?

Yes, you can use iCustom() within another custom indicator, so ignore that comment, please.

Also, you are not checking if the handle returned in the OnInit() is valid or not, and you are proceeding under the assumption that that it will work.

With the CopyBuffer, you are simply returning (with zero), when it fails, but not reporting the conditions to your log file, so how will you know what is happening?

Print out the results to the log, including any error codes when something fails, so that you can debug it.

 
Fernando Carreiro #:

Yes, you can use iCustom() within another custom indicator, so ignore that comment, please.

Also, you are not checking if the handle returned in the OnInit() is valid or not, and you are proceeding under the assumption that that it will work.

With the CopyBuffer, you are simply returning (with zero), when it fails, but not reporting the conditions to your log file, so how will you know what is happening?

Print out the results to the log, including any error codes when something fails, so that you can debug it.

Excellent points. At that point I was basically just following what the tutorial said. Here is my new code.

//+------------------------------------------------------------------+
//|                                                Phoenix Trend.mq5 |
//|                              Copyright 2022, Phoenix Investments |
//|                               https://www.phoenixinvestments.com |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Properties and Buffers                                           |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots 1

#property indicator_type1 DRAW_ARROW
#property indicator_label1 "Trend Indicator"
#property indicator_color1 clrRoyalBlue, clrCrimson
#property indicator_width1 5
//+------------------------------------------------------------------+
//| Indicator Settings                                               |
//+------------------------------------------------------------------+
input int
   macdFast = 20, // MACD Fast
   macdSlow = 40, //MACD Slow
   bbPeriod = 20, //BB Period
   bbDeviation = 2, // BB Deviation
   sensitive = 150, //Sensitivity
   deadZoneLevel = 400, //Deadzone Level
   explosionLevel = 15, //Explosion Level
   trendPower = 150; //Trend Power
//+------------------------------------------------------------------+
//| Global Variables                                                 |
//+------------------------------------------------------------------+
enum Status {UNSET, INVALID, LONG, SHORT};

double
   waeHandle;
   
double
   waeValueBuffer[],
   waeDZBuffer[],
   waeColorBuffer[],
   arrowBuffer[];
   
int 
   maxPeriod;
   
Status
   curTrend = UNSET;

bool
   once = false;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   Print("Initialized!");
   
   SetIndexBuffer(0, arrowBuffer, INDICATOR_DATA);
   //SetIndexBuffer(1, waeValueBuffer, INDICATOR_DATA);
   //SetIndexBuffer(2, waeDZBuffer, INDICATOR_DATA);
   //SetIndexBuffer(3, waeColorBuffer, INDICATOR_DATA);
   
   maxPeriod = (int)MathMax(MathMax(macdFast, macdSlow), bbPeriod);
   
   if(waeHandle = iCustom(_Symbol,_Period,"Waddah Attar Explosion",
                     macdFast,
                     macdSlow,
                     bbPeriod,
                     bbDeviation,
                     sensitive,
                     deadZoneLevel,
                     explosionLevel,
                     trendPower) == -1){ ResetLastError(); Print("Error: ", GetLastError()); }  
                     
   PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, maxPeriod);
   
   return(INIT_SUCCEEDED);
  }
  
//+------------------------------------------------------------------+
//| Custom indicator Deinitialization function                       |
//+------------------------------------------------------------------+
  
int OnDeinit(){
   
   if(waeHandle != INVALID_HANDLE) IndicatorRelease(waeHandle);
   return(0);
}

//+------------------------------------------------------------------+
//| 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[])
  {
//---    
   if(IsStopped()) return(0);
   if(rates_total < maxPeriod) return(0);
   if(BarsCalculated(waeHandle) < rates_total)return(0);
   
   int copyBars = 0;
   int startBar = 0;   
   
   if(prev_calculated < rates_total || prev_calculated <= 0){
      copyBars = rates_total;
      startBar = maxPeriod;
   } else {
      copyBars = rates_total-prev_calculated;
      if(prev_calculated > 0) copyBars++;
      startBar = prev_calculated - 1;
   }   
   
   if(IsStopped()) return(0);
   for(int bar = startBar; bar < rates_total && !IsStopped(); bar++){
      if(CopyBuffer(waeHandle, 0, bar, 1, waeValueBuffer) <= 0){ ResetLastError(); Print("Error: ", GetLastError()); return(0); }
      if(CopyBuffer(waeHandle, 1, bar, 1, waeColorBuffer) <= 0){ ResetLastError(); Print("Error: ", GetLastError()); return(0); }
      if(CopyBuffer(waeHandle, 3, bar, 1, waeDZBuffer) <= 0){ ResetLastError(); Print("Error: ", GetLastError()); return(0); }
      
      if(IsStopped()) return(0);
    
         //Print(waeValueBuffer[0], " || ", waeDZBuffer[0]);
         if(waeValueBuffer[0] > waeDZBuffer[0]){
            //Print(waeColorBuffer[0]);
            curTrend = (waeColorBuffer[0] == 1.0) ? LONG : SHORT;
            //Print(EnumToString(curTrend));
         }
         
         if(curTrend == LONG){
            arrowBuffer[bar] = low[bar];
         }else if (curTrend == SHORT){
            arrowBuffer[bar] = high[bar];
         }else{}
   }
   return(rates_total);
  }
//+------------------------------------------------------------------+
No errors printed
 
Tristen Shaw #: Excellent points. At that point I was basically just following what the tutorial said. Here is my new code.No errors printed

NO! If you reset the error AFTER it has occurs, obviously it will ALWAYS report there being "no error".

ResetLastError(); Print("Error: ", GetLastError());

Reset the error before executing the code that you want to trace, and identify what is being done in the log entry so you know where it occurred.

// Reset last error
   ResetLastError();

// Obtain handle to custom indicator
   waeHandle = iCustom( _Symbol, _Period, "Waddah Attar Explosion",
               macdFast, macdSlow, bbPeriod, bbDeviation, sensitive, deadZoneLevel, explosionLevel, trendPower );

// Check validity of indicator handle
   if( waeHandle == INVALID_HANDLE )
   {
      Print( "Invalid indicator handle! Error code: ", _LastError );
      return INIT_FAILED; // Initialisation has failed
   };

Also, add more log prints all over you code to detect how the code progresses and how each section is working. This is important, as you have so many "return(0)" in so many places, that one has no idea if any of your code is actually getting executed at all.

 
Fernando Carreiro #:

NO! If you reset the error AFTER it has occurs, obviously it will ALWAYS report there being "no error".

Reset the error before executing the code that you want to trace, and identify what is being done in the log entry so you know where it occurred.

Also, add more log prints all over you code to detect how the code progresses and how each section is working. This is important, as you have so many "return(0)" in so many places, that one has no idea if any of your code is actually getting executed at all.

The tutorial that I was following *** had a bunch of return(0) in his videos. Is this a bad idea?

I removed all of the ResetLastErrors from the different spots, and I still am not getting any errors anywhere.

 
Tristen Shaw #: The tutorial that I was following *** had a bunch of return(0) in his videos. Is this a bad idea?

Yes, it's a bad idea. Code should flow logicically, so that it can be followed and "read". Think about it this way — imagine writing a novel and at every negative decision in the story, it sent you to the last page of the book - The End -. This is just my personal opinion, but I have yet to see any Videos on coding that are worth while, but I digress.

For a beginner, learning is difficult enough, so trying to code something complex is even more difficult. There is a reason, why in programming lessons, they always start with simplest and most famous of tasks, namely to code the printing of "Hello World!" Unfortunately for MQL, everyone is so preoccupied in wanting to make "lots of money", that they throw away all sense of learning the language properly.

So, I suggest the following. Throw away this code for now. Start by coding the simplest of indicators. The task is basically so that you can learn the basics of how a custom indicator needs to be constructed. How to use the OnCalculate() event handler; how to declare and use buffers, how to use the "rates_total" and "prev_calculated", etc.

As you do this, you can come here and ask questions about what you don't understand, and slowly add more and more functionality to it, until you have reached a level good enough to start coding what you really need for your trading. In the beginning, code only with the aim of learning. Code only the simplest of tasks, even if they are useless. Then progress to more difficult stuff.

 
Fernando Carreiro #:

Yes, it's a bad idea. Code should flow logicically, so that it can be followed and "read". Think about it this way — imagine writing a novel and at every negative decision in the story, it sent you to the last page of the book - The End -. This is just my personal opinion, but I have yet to see any Videos on coding that are worth while, but I digress.

For a beginner, learning is difficult enough, so trying to code something complex is even more difficult. There is a reason, why in programming lessons, they always start with simplest and most famous of tasks, namely to code the printing of "Hello World!" Unfortunately for MQL, everyone is so preoccupied in wanting to make "lots of money", that they throw away all sense of learning the language properly.

So, I suggest the following. Throw away this code for now. Start by coding the simplest of indicators. The task is basically so that you can learn the basics of how a custom indicator needs to be constructed. How to use the OnCalculate() event handler; how to declare and use buffers, how to use the "rates_total" and "prev_calculated", etc.

As you do this, you can come here and ask questions about what you don't understand, and slowly add more and more functionality to it, until you have reached a level good enough to start coding what you really need for your trading. In the beginning, code only with the aim of learning. Code only the simplest of tasks, even if they are useless. Then progress to more difficult stuff.

I can understand what you are saying, but there are so few guides and tutorials for writing indicators and EAs. So, I wouldn't even know where to begin with such a thing. In all honesty, I didn't see my indicator as being all that complicated, all things considered.

I saw a guide on writing a simple moving average. But to be honest, I don't think it would teach me much by itself. That being said, I will happily go through it and do the tutorial. But it's about the only one I could find. Otherwise it seems like articles and videos on this topic are sadly lacking.

 
Tristen Shaw #: I didn't see my indicator as being all that complicated, all things considered.

It's not complicated, but it is "complicated" for you at your current skill level. I say this because one can clearly see that there are several basic level things that you don't quite comprehend yet.

Tristen Shaw #: I saw a guide on writing a simple moving average. But to be honest, I don't think it would teach me much by itself.

That is where I believe you are may misjudging the situation.

Tristen Shaw #: But it's about the only one I could find. Otherwise it seems like articles and videos on this topic are sadly lacking.

That is absolutely true. The reason being that most that are learning MQL, are being driven mostly by greed. And those teaching it in videos and books, are exploiting that greed.

I would recommend you follow resources aimed at learning C and C++. Start by first learning the basics of C/C++ without looking at MQL. Then once you understand the basics, then continue learning C/C++ at the same time as MQL.

 
Fernando Carreiro # :

***

I would recommend you follow resources aimed at learning C and C++. Start by first learning the basics of C/C++ without looking at MQL. Then once you understand the basics, then continue learning C/C++ at the same time as MQL.

This is the worst advice you can give to a beginner! If you are just starting to learn the MQL5 language, you are simply FORBIDDEN (as it will only harm you) to learn 'C/C++'!

Reason: