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

 
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.
 

The engine is absolutely wonderful, thank you. It is the first OOP MQL5 engine I decided to switch to.

But Manager.OnTick() is unfortunately very slow. Tracing shows almost 100% on it. Testing is very slow on a minute timeframe and with OHLC M1. For 3 years - about 50 seconds. And at the same time the Expert Advisor itself does nothing for testing, I have commented out everything that loads it. That is, it just searches bars.

I really want to optimise the code in Manager.OnTick()

 
Edgar:

The engine is absolutely wonderful, thank you. It is the first OOP MQL5 engine I decided to switch to.

But Manager.OnTick() is unfortunately very slow. Tracing shows almost 100% on it. Testing is very slow on a minute timeframe and with OHLC M1. For 3 years - about 50 seconds. And at the same time the Expert Advisor itself does nothing for testing, I have commented out everything that loads it. That is, it just searches bars.

I really want to optimise the code in Manager.OnTick()


This is the function from which everything else is launched - of course it will be 100%. Look inside it to see what time is spent on and optimise it. You can publish a screenshot.

 
Edgar:

The engine is absolutely wonderful, thank you. It is the first OOP MQL5 engine I decided to switch to.

But Manager.OnTick() is unfortunately very slow. Tracing shows almost 100% on it. Testing is very slow on a minute timeframe and with OHLC M1. For 3 years - about 50 seconds. And at the same time the Expert Advisor itself does nothing for testing, I have commented out everything that loads it. That is, it just searches bars.

I really want to optimise the code in Manager.OnTick()

There is nothing surprising here. This speed is comparable to the idle running of a strategy tester. OnTick determines the occurrence of a new tick and opening of a new bar. These operations do not require a lot of resources.

 

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

 

The author has a lot of respect. once again I faced the fact that practically having done something, I found practically the same already done before) as they say everything was invented before us).

One moment I would like to note - in the work of signals to me from the very beginning was wild that takes the weighted average of signals to buy and sell, it does not fit with the logic of decision-making in the canonical form (decision tree, which is already mentioned here) and I did so - the Progenitor of signals contains in addition to the actual list of signals from which the direction is taken (from -100 to 100) slots for signals on AND, ANDNOT, XOR. in this case the usual is OR, not boolean only. All logic of processing of these slots is unambiguous and sewn in the progenitor class. I.e. to construct a strategy you only need to add the main signal to the Expert Advisor and signals to the corresponding logic slots, according to the same principle as originally, i.e. for each up to 64 additional filters. I see this solution as the simplest and easily realisable. If you are interested in the idea and do not understand something, please contact me and I will tell you more.

 

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);
                                    
  }