Новая статья Кроссплатформенный советник: Сигналы опубликована:
Автор: Энрико Ламбино
Привет, Энрико. Я только что просмотрел вашу работу в поисках решения моей проблемы. При компиляции класса StopBase я получаю список ошибок, см. ниже.
implicit conversion from 'number' to 'string' OrderStopBase.mqh 395 25 implicit conversion from 'number' to 'string' OrderStopBase.mqh 467 26 implicit enum conversion OrderStopBase.mqh 468 33 implicit enum conversion OrderStop.mqh 37 33 implicit conversion from 'number' to 'string' OrderStop.mqh 44 43 'COrderBase' - import not defined OrderStop.mqh 54 7 'else' - semicolon expected OrderStop.mqh 81 4 ')' - unexpected token OrderStop.mqh 81 46 implicit conversion from 'number' to 'string' StopBase.mqh 767 22 implicit conversion from 'number' to 'string' StopBase.mqh 774 28 implicit conversion from 'number' to 'string' StopBase.mqh 796 22 implicit conversion from 'number' to 'string' StopBase.mqh 803 28 implicit conversion from 'number' to 'string' StopBase.mqh 698 36 'OrderType' - cannot convert enum Stop.mqh 227 52 'StopLossCustom' - no one of the overloads can be applied to the function call Stop.mqh 228 61 could be one of 2 function(s) Stop.mqh 228 61 double CStopBase::StopLossCustom(const string,const ENUM_ORDER_TYPE,const double) StopBase.mqh 136 22 bool CStopBase::StopLossCustom() StopBase.mqh 99 22 'OrderType' - cannot convert enum Stop.mqh 215 71 'TakeProfitCustom' - no one of the overloads can be applied to the function call Stop.mqh 215 98 could be one of 2 function(s) Stop.mqh 215 98 double CStopBase::TakeProfitCustom(const string,const ENUM_ORDER_TYPE,const double) StopBase.mqh 140 22 bool CStopBase::TakeProfitCustom() StopBase.mqh 111 22 implicit conversion from 'number' to 'string' Stop.mqh 250 39 implicit enum conversion Stop.mqh 291 31 implicit conversion from 'number' to 'string' Stop.mqh 292 36
Не обращая внимания на предупреждения, ошибки, похоже, возникают из-за проблем с типом заказа. Кроме того, компиляция вашего примера signal_ma приводит к следующим ошибкам
'GetPointer' - parameter conversion not allowed OrderStopVirtualBase.mqh 51 39 'GetPointer' - parameter conversion not allowed OrderStopVirtualBase.mqh 58 41 '=' - type mismatch OrderStopsBase.mqh 106 23 '=' - type mismatch OrderStopsBase.mqh 108 23 '=' - type mismatch OrderStopsBase.mqh 110 23 '=' - type mismatch OrderStopsBase.mqh 180 20 '=' - type mismatch OrderStopsBase.mqh 182 20 '=' - type mismatch OrderStopsBase.mqh 184 20
Откуда берутся эти ошибки и как я могу их решить? По смежному вопросу, насколько я понимаю, Лисковская подстановка предусматривает, что мы должны программировать на интерфейс, так как суперкласс может быть заменен на базовый класс. Почему вы решили передавать объекты в функции (которые сами по себе являются интерфейсами), а не использовать их базовые классы? Я могу ошибаться, но мне кажется, что это было бы лучшей практикой, не так ли?
Заранее спасибо за помощь и за отличную работу.Здравствуйте, Шепард, спасибо за ваш комментарий. Что касается ваших вопросов:
- К сожалению, на данный момент нет возможности скомпилировать StopBase.mqh самостоятельно. Хотя компиляторы MQL4 и MQL5 принимают прямое объявление, они выдают ошибку, если вы пытаетесь получить доступ к методу или члену класса, который был объявлен прямо. Вам придется скомпилировать StopBase.mqh с более крупным классом, таким как COrderManager или CExpertAdvisor (CStop и CStops являются компонентами этих двух классов).
- Что касается ошибок несоответствия типов, то я не обнаружил их в исходных файлах (были ли изменены исходники с вашей стороны?).
- Думаю, в большинстве случаев базовые классы можно без проблем передавать в методы классов. При кодировании экспертов, использующих библиотеку, проще считать, что базовых классов вообще не существует. Но у некоторых объектов есть новые виртуальные методы, а также невиртуальные методы. Эти два набора методов не могут быть доступны только базовому классу. Если вы используете производные классы вместо базовых, компилятор может выбрать правильную версию производных классов, поэтому использование производных классов является более полным, чем использование одних только базовых классов.
Здравствуйте, Шепард, спасибо за ваш комментарий. Что касается ваших вопросов:
- К сожалению, на данный момент нет возможности скомпилировать StopBase.mqh самостоятельно. Хотя компиляторы MQL4 и MQL5 принимают прямое объявление, они выдают ошибку, если вы пытаетесь получить доступ к методу или члену класса, который был объявлен прямо. Вам придется скомпилировать StopBase.mqh с более крупным классом, таким как COrderManager или CExpertAdvisor (CStop и CStops являются компонентами этих двух классов).
- Что касается ошибок несоответствия типов, то я не обнаружил их в исходных файлах (были ли изменены исходники с вашей стороны?).
- Думаю, в большинстве случаев базовые классы можно без проблем передавать в методы классов. При кодировании экспертов, использующих библиотеку, проще считать, что базовых классов вообще не существует. Но у некоторых объектов есть новые виртуальные методы, а также невиртуальные методы. Эти два набора методов не могут быть доступны только базовому классу. Если вы используете производные классы вместо базовых, компилятор может выбрать правильную версию производных классов, поэтому использование производных классов является более полным, чем использование только базовых классов.
Привет, Энрико,
Большое спасибо за быстрый ответ. Я понимаю, почему вы передаете конкретные классы вместо их базовых классов. Некоторые реализации, которые просты в C++, просто невозможны в MQL, но так уж сложилось.
Что касается несоответствия типов, то нет, я ничего не менял. Я просто скачал и скомпилировал. Я смотрел на вашу работу в поисках раздражающей проблемы, с которой я столкнулся в своей системе. Ваш подход действительно замечательный.
Я разработал свою систему следующим образом. Я рассматривал систему вывода сигналов как стратегию. Скажем, у меня есть система пересечения МА, если я создаю объект, скажем, EURUSD, то это уже стратегия. Я добавляю эту стратегию в список стратегий. Я могу создать еще одну стратегию и добавить ее в список. Но стратегии вызываются не по OnTick, скорее, они являются частью паттерна Observer. Они обновляются или вызываются, когда происходят определенные события, например, новый бар на 5 Minute, новый бар 10 Pip Renko и т.д. У меня были проблемы со стопами, что и послужило толчком для моего исследования.
Еще раз спасибо за то, что нашли время поделиться своими знаниями и умениями, а также за быстрый ответ.
Привет, Шепард,
Спасибо, что поделились своими предложениями и соображениями.
Я думаю, то, над чем вы работаете, - отличная идея. В настоящее время я работаю над последними статьями этой серии (остановки ордеров и стопы в том числе). Я не уверен, что классы Stops хорошо подходят (это зависит от вашей реализации). Если вы можете заставить их работать независимо от менеджера ордеров, это было бы хорошо, потому что это помогло бы упростить объекты вашего класса. Но я надеюсь, что вы найдете их полезными в своей работе.
Что касается компиляции:
- Без ошибок могут быть скомпилированы только основные файлы исходных текстов/заголовков и файлы базовых классов (за исключением тех, в которых используются прямые объявления). Именно поэтому в примерах я использовал директиву #include в заголовочных файлах для базовых файлов (а не в файлах, относящихся к конкретному языку).
- Необходимо использовать правильный компилятор (компиляция файла mq5 компилятором MQL4 приведет к ошибкам компилятора).
Привет, Энрико,
Я тестирую ваш модуль сигналов. У меня есть один сигнал SHORT и один сигнал NEUTRAL. Как получилось, что я получил CMD_VOID? Когда появляется CMD_VOID?
На самом деле это появляется в CSignalsBase::Check
if(signal.Entry()) { if(m_signal_open>CMD_VOID) { ENUM_CMD signal_open=signal.SignalOpen(); if(m_signal_open==CMD_NEUTRAL) { m_signal_open=signal_open; } else if(m_signal_open!=signal_open) { m_signal_open=CMD_VOID; } } }
Есть только 2 сигнала. Предыдущим сигналом был CMD_SHORT. Текущий сигнал - CMD_NEUTRAL. Можете ли вы подтвердить, что CMD_SHORT и CMD_NEUTRAL дают в результате CMD_VOID?
Если первый сигнал был CMD_NEUTRAL, а второй CMD_SHORT, то общий сигнал будет CMD_SHORT. Но если первый сигнал CMD_SHORT, а второй CMD_NEUTRAL, то это дает CMD_VOID.
Я полагаю, что это должно быть так:
if(signal.Entry()) { if(m_signal_open>CMD_VOID) { ENUM_CMD signal_open=signal.SignalOpen(); if(m_signal_open==CMD_NEUTRAL) { m_signal_open=signal_open; } else if(m_signal_open!=signal_open && signal_open!=CMD_NEUTRAL) { m_signal_open=CMD_VOID; } } }
if(m_new_signal) { if(m_signal_open==m_signal_open_last) m_signal_open = CMD_NEUTRAL; if(m_signal_close==m_signal_close_last) m_signal_close= CMD_NEUTRAL; }
Это не совсем верно с точки зрения близких сигналов. Почему не может быть двух последовательных сигналов закрытия в одном направлении?
Например, у меня есть сигнал входа Short, следующий сигнал выхода Long (закрытие короткой позиции), следующий сигнал входа Long, следующий сигнал входа Short, следующий сигнал выхода Long. Таким образом, последний сигнал на выход из короткой позиции не сработает, так как он того же направления, что и предыдущий сигнал на выход.
Это не совсем верно с точки зрения близких сигналов. Почему не может быть двух последовательных сигналов закрытия в одном направлении?
Например, у меня есть сигнал входа Short, следующий сигнал выхода Long (закрытие короткой позиции), следующий сигнал входа Long, следующий сигнал входа Short, следующий сигнал выхода Long. Таким образом, последний сигнал на выход из короткой позиции не сработает, так как он того же направления, что и предыдущий сигнал выхода.
Это зависит от того, чего вы хотите добиться, как должны оцениваться сигналы.
Последний код, который вы опубликовали, выполняется только тогда, когда член класса m_new_signal установлен в true. Это нужно только для торговли по новым сигналам. Вы можете установить этот защищенный член класса с помощью метода NewSignal, доступного в классе.
Это зависит от того, чего вы хотите добиться, как должны оцениваться сигналы.
Последний код, который вы опубликовали, выполняется только тогда, когда член класса m_new_signal установлен в true. Это нужно только для торговли по новым сигналам. Вы можете установить этот защищенный член класса с помощью метода NewSignal, доступного в классе.
Я знаю это. Но если я установлю false, это также повлияет на мои сигналы входа. Это нормально для сигнала входа, но не для выхода, поскольку правила выхода могут быть разными. Это может быть реверс или сигнал выхода, так что 2 сигнала выхода в одном направлении - это нормальное явление.
Привет, mbjen,
Привет, Энрико,
Я тестирую ваш модуль сигналов. У меня есть один сигнал SHORT и один сигнал NEUTRAL. Как получилось, что я получил CMD_VOID? Когда появляется CMD_VOID?
На самом деле это появляется в CSignalsBase::Check
Есть только 2 сигнала. Предыдущим сигналом был CMD_SHORT. Текущий сигнал - CMD_NEUTRAL. Можете ли вы подтвердить, что CMD_SHORT и CMD_NEUTRAL дают в результате CMD_VOID?
Если первый сигнал был CMD_NEUTRAL, а второй CMD_SHORT, то общий сигнал будет CMD_SHORT. Но если первый сигнал CMD_SHORT, а второй CMD_NEUTRAL, то это дает CMD_VOID.
Наверное, так и должно быть:
Извините, что пропустил ваш первый вопрос. Я не замечал его до сих пор. Это был очень хороший отзыв.
Спасибо, что указали на это. Да, вы правы. Я обновлю код и пересмотрю статью.
Я знаю это. Но если я установлю false, это также повлияет на мои сигналы входа. Это нормально для сигнала входа, но не для выхода, поскольку правила выхода могут быть разными. Это может быть реверсия или сигнал выхода, так что 2 сигнала выхода в одном направлении - это нормальное явление.
Здесь вы правы. Но, например, если я хочу подавать сигнал выхода только при пересечении МА, это будет необходимо. Я думаю, что их разделение было бы лучшим вариантом, чем текущий код:
if(m_new_signal) { if(m_signal_open==m_signal_open_last) m_signal_open = CMD_NEUTRAL; } if(m_new_signal_close) { if(m_signal_close==m_signal_close_last) m_signal_close= CMD_NEUTRAL; }
Похоже, что в m_signal_close сохраняется предыдущее значение сигнала в SignalBase.mqh. Например, у меня есть сигнал выхода. Если он проверяется и метод Calculate() возвращает false, то он выдает последнее значение сигнала, которое было при предыдущем выходе.
Метод Calculate является виртуальным методом. Если метод должен возвращать false, вы должны сбросить эти члены класса в нейтральное состояние из самого метода.
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Опубликована статья Кроссплатформенный торговый советник: Сигналы:
В статье обсуждаются классы CSignal и CSignals, которые будут использоваться в кроссплатформенных торговых советниках. Рассмотрены различия между MQL4 и MQL5 в организации данных, необходимых для оценки полученных торговых сигналов. Итог — код, совместимый с компиляторами обеих версий.
Наш последний пример — комбинация индикаторов MA и HA, включенная в советник. Отличий в этом примере немного. Мы просто добавляем определения классов, находящиеся во втором и третьем примерах, и затем добавляем указатели на экземпляры CSignalMA и CSignalHA в экземпляр CSignals. Ниже показан результат пробного использования эксперта.
(MT4)
Автор: Enrico Lambino