Обсуждение статьи "Универсальный торговый эксперт: Интеграция со стандартными модулями сигналов MetaTrader (часть 7)" - страница 3

 
Amy Liu:

Спасибо Василию за ваш вклад. Я узнал много нового. Скачал весь код, но в файле Panel.mqh ошибка компиляции:

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

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

Не могли бы вы проверить это?


Привет, Эми. Я только что закончил читать статьи Василия Соколова. Если вы все еще заинтересованы в поиске решения. Пожалуйста, опубликуйте здесь журнал ошибок. Я помню, как столкнулся с этой ошибкой и понял, что в декларациях в файле StrategiesList есть ".\Panel\Panel.mqh". Panel.mqh не существует. Вместо этого попробуйте зайти на сайт https://www.mql5.com/ru/articles/2411 и скачать оттуда файл Panel. Я полагаю, что там есть файл Panel.mqh.

Эта серия от Василия действительно хороша как основа. Я тоже многому научился, но когда возникают проблемы с библиотекой, если автор не предлагает поддержку, вы можете остаться в тупике, если вы не очень хороший программист. Именно об этом говорил Ален Верлейен в других ваших обсуждениях. Но те, кто тратит время на то, чтобы поделиться своими знаниями и умениями здесь, совершенно удивительны. Я бесконечно благодарен.

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.
 

Движок совершенно замечательный, спасибо. Первый ООП MQL5 движок, на который я решился перейти.

Но Manager.OnTick(), к сожалению, очень медленный. Трассировка показывает почти 100% на ней. Тестирование проходит очень медленно на минутном таймфрейме и с OHLC M1. За 3 года - примерно 50 секунд. И при этом для проверки сам эксперт ничего не делает, всё, что нагружает, я закомментировал. То есть идёт просто перебор баров.

Очень хочется оптимизации кода в Manager.OnTick()

 
Edgar:

Движок совершенно замечательный, спасибо. Первый ООП MQL5 движок, на который я решился перейти.

Но Manager.OnTick(), к сожалению, очень медленный. Трассировка показывает почти 100% на ней. Тестирование проходит очень медленно на минутном таймфрейме и с OHLC M1. За 3 года - примерно 50 секунд. И при этом для проверки сам эксперт ничего не делает, всё, что нагружает, я закомментировал. То есть идёт просто перебор баров.

Очень хочется оптимизации кода в Manager.OnTick()


Так это функция, из которой все остальное запускается - разумеется она будет 100%. Вот внутри неё смотрите, на что время уходит и оптимизируйте. Можете скрин опубликовать.

 
Edgar:

Движок совершенно замечательный, спасибо. Первый ООП MQL5 движок, на который я решился перейти.

Но Manager.OnTick(), к сожалению, очень медленный. Трассировка показывает почти 100% на ней. Тестирование проходит очень медленно на минутном таймфрейме и с OHLC M1. За 3 года - примерно 50 секунд. И при этом для проверки сам эксперт ничего не делает, всё, что нагружает, я закомментировал. То есть идёт просто перебор баров.

Очень хочется оптимизации кода в Manager.OnTick()

Ничего удивительного здесь нет. Эта скорость сопоставима с холостым ходом тестера стратегий. OnTick определяет наступление нового тика и открытие нового бара. Эти операции не требуют много ресурсов.

 

Здравствуйте, Василий.

Спасибо за все ваши статьи.

Универсальный советник действительно впечатляет своей сложностью и программной архитектурой.

Для данной конкретной версии я хотел бы обратить внимание на один момент в этом куске кода:

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

Обратите внимание, что после создания сигнала мы продолжили его настройку, задав собственный период индикатора MACD (15, 32, 6). Это легко сделать, так как метод CreateSignal вернул соответствующий объект.<br/ translate="no">

На самом деле, параметры MacD (15, 32 и 6) здесь не имеют никакого значения, так как метод CreateSignal() инициализирует сигнал MacD до обновления параметров.

В этом случае я бы предложил разделить метод CSignalAdapter::CreateSignal() на две части, где в первой части сигнал фактически создается и возвращается как есть, а вторая часть будет инициализацией сигнала, после установки всех параметров "Signal Dependent" (в данном случае PeriodFast, PeriodSlow и PeriodSignal):

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

И, конечно же, необходимо вызвать только что созданный метод Init:

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 */
}


Спасибо за отличную работу, а еще больше за то, что поделились ею, Василий!


Будьте здоровы,

Родриго Халлер

 

Толковая и профессиональная работа, автору респект. в очередной раз столкнулся с тем что практически сделав что-то, нашёл практически такое уже сделанное ранее) как говорится всё придумано до нас)

Один момент хотелось отметить - в работе сигналов мне с самого начала было дико что берётся средневзвешенное значение от сигналов на покупку и продажу, это не вяжется с логикой принятия решений в каноническом виде (дерево решений которое здесь уже упоминали) и я сделал так - Прародитель сигналов содержит помимо собственно списка сигналов, из которых берётся direction (от -100 до 100) слоты для сигналов по AND, ANDNOT, XOR. в данном случае обычный является OR, не булевым только. Вся логика обработки этих слотов однозначна и зашита в классе прародителе. Т.е. для конструирования стратегии надо только добавлять в эксперт основной сигнал и сигналы в соответствующие логические слоты, по тому же принципу что и изначально, т.е. для каждого до 64 доп.фильтров. Мне видится это решение самым простым и легкореализуемым. Если вдруг интересна идея и что-то непонятно обращайтесь расскажу подробнее.

 

Как можно использовать класс CSignalMACD в скрипте?

Я пытался получить результат сигнала просто на месте, но всегда получал 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());                                  // Инициализация объекта, представляющего торговый символ стратегии
   m_signal_macd.Init(GetPointer(m_info), Period(), 10);   // Инициализация модуля сигналов по торговому символу и таймфрейму
   m_signal_macd.InitIndicators(GetPointer(m_indicators)); // создание необходимых индикаторов в сигнальном модуле на основе пустого списка индикаторов m_indicators
   //m_signal_macd.EveryTick(true); // Тестовый режим
   m_signal_macd.Magic(42);                     // Магическое число
   m_signal_macd.PatternsUsage(8);                         // Маска узора
   m_open.Create(Symbol(), Period());                      // Инициализация временного ряда цен открытия
   m_high.Create(Symbol(), Period());                      // Инициализация временного ряда высоких цен
   m_low.Create(Symbol(), Period());                       // Инициализация временного ряда низких цен
   m_close.Create(Symbol(), Period());                     // Инициализация временного ряда цен закрытия
   m_signal_macd.SetPriceSeries(GetPointer(m_open),        // Инициализация сигнального модуля объектами временных рядов
                              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);
                                    
  }