Discussion of article "Universal Expert Advisor: Integration with Standard MetaTrader Modules of Signals (Part 7)"

 

New article Universal Expert Advisor: Integration with Standard MetaTrader Modules of Signals (Part 7) has been published:

This part of the article describes the possibilities of the CStrategy engine integration with the signal modules included into the standard library in MetaTrader. The article describes how to work with signals, as well as how to create custom strategies on their basis.

The below diagram shows the general scheme of vertical inheritance of classes used in the process of automatic generation of strategies:

 

Fig. 1. Inheritance of standard classes of the strategy generator

The figure only shows basic and some derived classes. The scheme does not feature all indicators inherited from CIndicators. Separate trailing, money management and signal modules are not included into the scheme. Instead, only the basic relationships are outlined. One of the featured groups is of interest to us: the signal classes CExpertSignal and its child classes. In Figure 1, the group is highlighted by a green dotted line.

Author: Vasiliy Sokolov

 

Thank Vasiliy for your contribution. I learned a lot. I downloaded all the code but it has a compiling error in file Panel.mqh:

'At' - object pointer expected Panel.mqh 210 39

'At' - object pointer expected Panel.mqh 228 37

Can you please check it? 

 

 
Amy Liu:

Thank Vasiliy for your contribution. I learned a lot. I downloaded all the code but it has a compiling error in file Panel.mqh:

'At' - object pointer expected Panel.mqh 210 39

'At' - object pointer expected Panel.mqh 228 37

Can you please check it? 

 


Hi Amy. I have just completed reading through Vasiliy Sokolov articles. If you are still interested in finding out the solution. Please post the error log here. I recall coming across that error and realised that there is an ".\Panel\Panel.mqh" in declarations in StrategiesList file.  Panel.mqh does not exist. Instead, try going to https://www.mql5.com/en/articles/2411 and download the Panel File from there. I believe it has the Panel.mqh file.

This series by Vasiliy's is really good as a framework. I learn't a lot too,but when there are issues with a library, if the author does not offer support, you could be left stuck if you are not a good programmer. Which is the point Alain Verleyen made in your other discussions. But those spending time to share their knowledge and skill here are completely amazing. I am eternally grateful.

Universal Expert Advisor: A Custom Trailing Stop (Part 6)
Universal Expert Advisor: A Custom Trailing Stop (Part 6)
  • 2016.06.16
  • Vasiliy Sokolov
  • www.mql5.com
The sixth part of the article about the universal Expert Advisor describes the use of the trailing stop feature. The article will guide you through how to create a custom trailing stop module using unified rules, as well as how to add it to the trading engine so that it would automatically manage positions.
 

Hi, Vasily.

Thanks for all of your articles.

The Universal Expert Advisor is really impressive in terms of complexity and Software architecture.

For this particular version, I'd like to raise a point in this piece of code here:

CAdapterMACD::CAdapterMACD(void)
{
   m_params.symbol = Symbol();
   m_params.period = Period();
   m_params.every_tick = false;
   m_params.signal_type = SIGNAL_MACD;
   m_params.magic = 1234;
   m_params.point = 1.0;
   m_params.usage_pattern = 2;
   CSignalMACD* macd = m_signal.CreateSignal(m_params);
   macd.PeriodFast(15);
   macd.PeriodSlow(32);
   macd.PeriodSignal(6);
}

Note that after creating the signal, we continued to configure it by setting our own period of the MACD indicator (15, 32, 6). This is easy to do, because the CreateSignal method has returned the corresponding object.

Actually, the MacD parameters (15, 32 and 6) are taking no effect here, since CreateSignal() method initializes the MacD signal before the params are updated.

In this case, I'd suggest to split the CSignalAdapter::CreateSignal() method in two parts, where in the first one, the signal is in fact created and returned just like it is, and the second part would be the signal initialization, after all "Signal Dependant" parameters (in this case, PeriodFast, PeriodSlow and PeriodSignal) are set:

CExpertSignal* CSignalAdapter::CreateSignal(MqlSignalParams& params)
{
   DeleteSignal();
   switch(params.signal_type)
   {
      case SIGNAL_AO:
         m_signal = new CSignalAO();
         break;
      case SIGNAL_AC:
         m_signal = new CSignalAC();
         break;
      case SIGNAL_ADAPTIVE_MA:
         m_signal = new CSignalAMA();
         break;
      case SIGNAL_CCI:
         m_signal = new CSignalCCI();
         break;
      case SIGNAL_DeMARKER:
         m_signal = new CSignalDeM();
         break;
      case SIGNAL_DOUBLE_EMA:
         m_signal = new CSignalDEMA();
         break;
      case SIGNAL_ENVELOPES:
         m_signal = new CSignalEnvelopes();
         break;
      case SIGNAL_FRAMA:
         m_signal = new CSignalFrAMA();
         break;
      case SIGNAL_MA:
         m_signal = new CSignalMA();
         break;
      case SIGNAL_MACD:
         m_signal = new CSignalMACD();
         break;
      case SIGNAL_PARABOLIC_SAR:
         m_signal = new CSignalSAR();
         break;
      case SIGNAL_RSI:
         m_signal = new CSignalRSI();
         break;
      case SIGNAL_RVI:
         m_signal = new CSignalRVI();
         break;
      case SIGNAL_STOCHASTIC:
         m_signal = new CSignalStoch();
         break;
      case SIGNAL_TRIPLE_EA:
         m_signal = new CSignalTriX();
         break;
      case SIGNAL_TRIPLE_EMA:
         m_signal = new CSignalTEMA();
         break;
      case SIGNAL_WILLIAMS_PER_RANGE:
         m_signal = new CSignalWPR();
         break;
   }
   if(CheckPointer(m_signal)!= POINTER_INVALID)
      m_params = params;
   
   return m_signal;
}

bool CSignalAdapter::Init()
{
   if(m_params.symbol == "") /* CreateSignal method should be called first in order to update m_params */
      return false;
   m_info.Name(m_params.symbol);
   if(!m_signal.Init(GetPointer(m_info), m_params.period, m_params.point))
      return false;
   if(!m_signal.InitIndicators(GetPointer(m_indicators)))
      return false;
   m_signal.EveryTick(m_params.every_tick);
   m_signal.Magic(m_params.magic);
   
   m_open.Create(m_params.symbol, m_params.period);
   m_high.Create(m_params.symbol, m_params.period);
   m_low.Create(m_params.symbol, m_params.period);
   m_close.Create(m_params.symbol, m_params.period);
   
   m_times.Create(m_params.symbol, m_params.period);
   m_spread.Create(m_params.symbol, m_params.period);
   m_tik_vol.Create(m_params.symbol, m_params.period);
   m_real_vol.Create(m_params.symbol, m_params.period);
   
   m_signal.SetPriceSeries(GetPointer(m_open), GetPointer(m_high), GetPointer(m_low), GetPointer(m_close));
   //m_signal.SetOtherSeries(GetPointer(m_spread), GetPointer(m_times), GetPointer(m_tik_vol), GetPointer(m_real_vol));
   int mask = 1;
   mask = mask << m_params.usage_pattern;
   m_signal.PatternsUsage(mask);
   return true;
}

And of course, the newly created Init method needs to be called:

CAdapterMACD::CAdapterMACD(void)
{
   m_params.symbol = Symbol();
   m_params.period = Period();
   m_params.every_tick = false;
   m_params.signal_type = SIGNAL_MACD;
   m_params.magic = 1234;
   m_params.point = 1.0;
   m_params.usage_pattern = 2;
   CSignalMACD* macd = m_signal.CreateSignal(m_params);
   macd.PeriodFast(15);
   macd.PeriodSlow(32);
   macd.PeriodSignal(6);
   m_signal.Init(); /* This call is going to create the CSignalMACD object with the custom parameters */
}


Thank you for the great work, and even more for sharing it, Vasily!


Cheers,

Rodrigo Haller

 

How it is possible to use class CSignalMACD in script?

I've tried to get signal result just inplace, but always got 0:

void OnStart()
{
   CSignalMACD       m_signal_macd;
   CSymbolInfo       m_info;
   CiOpen            m_open;
   CiHigh            m_high;
   CiLow             m_low;
   CiClose           m_close;
   CIndicators       m_indicators;

   m_signal_macd.Pattern_0(0);
   m_signal_macd.Pattern_1(0);
   m_signal_macd.Pattern_2(0);
   m_signal_macd.Pattern_3(100);
   m_signal_macd.Pattern_4(0);
   m_signal_macd.Pattern_5(0);
   m_info.Name(Symbol());                                  // Initializing the object that represents the trading symbol of the strategy
   m_signal_macd.Init(GetPointer(m_info), Period(), 10);   // Initializing the signal module by the trading symbol and timeframe
   m_signal_macd.InitIndicators(GetPointer(m_indicators)); // creating required indicators in the signal module based on the empty list of indicators m_indicators
   //m_signal_macd.EveryTick(true);                          // Testing mode
   m_signal_macd.Magic(42);                     // Magic number
   m_signal_macd.PatternsUsage(8);                         // Pattern mask
   m_open.Create(Symbol(), Period());                      // Initializing the timeseries of Open prices
   m_high.Create(Symbol(), Period());                      // Initializing the timeseries of High prices
   m_low.Create(Symbol(), Period());                       // Initializing the timeseries of Low prices
   m_close.Create(Symbol(), Period());                     // Initializing the timeseries of Close prices
   m_signal_macd.SetPriceSeries(GetPointer(m_open),        // Initializing the signal module by timeseries objects
                              GetPointer(m_high),
                              GetPointer(m_low),
                              GetPointer(m_close));
                              
   m_indicators.Refresh();
   m_signal_macd.SetDirection();
   int power_sell = m_signal_macd.ShortCondition();
   int power_buy = m_signal_macd.LongCondition();
   printf("PowerSell: " + (string)power_sell + " PowerBuy: " + (string)power_buy);
                                    
  }
Reason: