Использование CExpert vs свой велосипед

 

Привет всем,

 

Решил таки еще раз взяться за МТ5, только теперь уже за написание/переписывание советника под MQL5. Первое что сделал, это сравнил исходный код примеров советников и автоматически сгенерированного советника.

Разница в том, что в примере советника многие вещи типа трейлинг стопа и еще кучу всего делаются вручную, в автоматически сгенерированном советнике объявляется объект унаследованный от CEXpert, добавляются фильтры и собственно все.

В принципе мне понравился подход используемый при генерации советника, но остались некоторые вопросы:

1) При поступлении сигнала на покупку/продаже советник не учитывает открыта ли позиция в противоположном направлении и открывает сделку в том направлении куда указывает сигнал, при этом если текущая позиция ушла в минус она закрывается с минусом. Можно ли как-то ограничить советник, чтобы он открывал сделку только если нет открытых сделок?

2) Если я хочу "долиться" (открыть еще одну сделку в том же направлении что уже есть), то где это лучше всего сделать в событии OnTick? Идея проанализировать насколько далеко рынок ушел и долиться в убыточную сделку, тем самым приблизив ее цены к рыночной цене (чтобы быстрее ее закрыть, как только она будет в плюсе). Я понимаю что это похоже на мартингейл, но понятие мани-менеджмента мне не чуждо, объемы будут рассчитаны исходя из размера депозита

 

1) При поступлении сигнала на покупку/продаже советник не учитывает открыта ли позиция в противоположном направлении и открывает сделку в том направлении куда указывает сигнал, при этом если текущая позиция ушла в минус она закрывается с минусом. Можно ли как-то ограничить советник, чтобы он открывал сделку только если нет открытых сделок?

Я так понимаю, необходимо дополнить функцию bool CExpert::CheckReverse(void).

Сейчас в этой функции проверяется только тип позиции, и далее - управление передается функциям реверса в лонг или в шорт.

А вам необходимо в вашем классе CMyExpert, пронаследованном от CExpert перегрузить эту функцию - сперва проверить, если текущая позиция в просаде - сразу вернуть управление с fals'ом, не вызывая реверса в шорт или лонг.

2) Если я хочу "долиться" (открыть еще одну сделку в том же направлении что уже есть), то где это лучше всего сделать в событии OnTick? Идея проанализировать насколько далеко рынок ушел и долиться в убыточную сделку, тем самым приблизив ее цены к рыночной цене (чтобы быстрее ее закрыть, как только она будет в плюсе). Я понимаю что это похоже на мартингейл, но понятие мани-менеджмента мне не чуждо, объемы будут рассчитаны исходя из размера депозита

Это в любом случае будет сделано в событии OnTick(). Если вы используете классы СБ, то величиной лота управляют класс, пронаследованные от CExpertMoney, вам нужно объявить своего наследника, и написать функцию, которая будет определять лот.
 

А можно для тех кто в танке, поподробнее как перегрузить функцию, документацию нашел - https://www.mql5.com/ru/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertcheckreverse

Но что-то воедино в голове все не укладывается, где именно перегружать (в коде). Обычно при создании класса это делал, а тут класс объявляется как переменная типа CExpert, это меня сбивает с толку (исходный код прилагается).

Как в OnTick доливку сделать буду позже ковырять, после того как  решу проблему с первым вопросом

Документация по MQL5: Стандартная библиотека / Классы торговых стратегий / Базовые классы экспертов / CExpert / CheckReverse
Документация по MQL5: Стандартная библиотека / Классы торговых стратегий / Базовые классы экспертов / CExpert / CheckReverse
  • www.mql5.com
Стандартная библиотека / Классы торговых стратегий / Базовые классы экспертов / CExpert / CheckReverse - Документация по MQL5
Файлы:
SOMA.mq5  9 kb
 
ITeXPert:
 

Но что-то воедино в голове все не укладывается, где именно перегружать (в коде). Обычно при создании класса это делал, а тут класс объявляется как переменная типа CExpert, это меня сбивает с толку (исходный код прилагается).

У вас в коде объявляется переменная типа CExpert. Это значит, что все функции будут взяты именно из этого класса.

Перегрузка функций - это ситуация, когда одна и та же функция в классах-наследниках выполняет разные действия.

То есть, вы должны объявить свой класс, наследни от CExpert. В нем вы объявляется необходимую функцию (В данном случае CheckReverse), и пишете код, работающий так, как вам требуется.

После этого, в основной функции вы будете использовать не переменную типа CExpert, а переменную вашего, только что описанного типа. И при вызове у нее функции CheckReverse(), будет вызвана не функция предка из СБ, а ваша функция.

Лично я обычно все классы, используемые в коде, описываю в отдельных файлах. А потом - в основном файле просто включаю их в листинг директивой #include

Имейте ввиду, советники, сегенерированные автоматически с помощью классов Стандартной Библиотеки, имеют довольно сложную структуру, и требуют довольно длительного изучения.

 
Laryx:

У вас в коде объявляется переменная типа CExpert. Это значит, что все функции будут взяты именно из этого класса.

Перегрузка функций - это ситуация, когда одна и та же функция в классах-наследниках выполняет разные действия.

То есть, вы должны объявить свой класс, наследни от CExpert. В нем вы объявляется необходимую функцию (В данном случае CheckReverse), и пишете код, работающий так, как вам требуется.

После этого, в основной функции вы будете использовать не переменную типа CExpert, а переменную вашего, только что описанного типа. И при вызове у нее функции CheckReverse(), будет вызвана не функция предка из СБ, а ваша функция.

Лично я обычно все классы, используемые в коде, описываю в отдельных файлах. А потом - в основном файле просто включаю их в листинг директивой #include

Имейте ввиду, советники, сегенерированные автоматически с помощью классов Стандартной Библиотеки, имеют довольно сложную структуру, и требуют довольно длительного изучения.

Не пугайте человека. Примитивные классы с примитивной логикой. Кстати - а неплохо бы создать действительно сложную систему классов сообща, а? Заведу новую тему, может разработчики нас поддержат, а?
 
YAndrey:
Не пугайте человека. Примитивные классы с примитивной логикой. Кстати - а неплохо бы создать действительно сложную систему классов сообща, а? Заведу новую тему, может разработчики нас поддержат, а?
В Стандартной Библиотеке МТ5 - вполне серьезная и достаточно сложная система классов. Она достаточно документирована, также имеется много статей с примерами кода. На мой взгляд, сейчас работа должна быть направлена на то, чтобы сделать СБ для МТ4, где полностью бы поддерживалась старая идеология. Увы, сейчас в СБ МТ4 нет торговых классов.
 

Написал свой класс 

class MyExpert : public CExpert
{
  bool CheckReverse()
  {
    if (PositionSelect(Symbol()))
      return false;
    else return true;
  } }; 

Вынес в отдельный файл

В советнике подключил его через include

Тип переменной CExpert заменил на MyExpert

Скомпилировал, запустил, тот же эффект, при поступлении сигнала в противоположном направлении советник открывает новую сделку, закрывая имеющуюся (даже если в минус).

Грешил на

input int  Signal_Expiration = 4;           // Expiration of pnding orders (in bars) 

Но установка значения в 1000 то не решила всю проблему, но сейчас хотя бы не закрываются сделки старше 4х баров

 

Сижу изучаю исходный код стандартной библиотеки классов, потихоньку приходит понимание. В общем нужно еще переопределить CheckOpenLong и CheckOpenShort. Еще довольно странно реализован трейлинг на фиксированном расстоянии. По умолчанию он трейлит только при формировании нового бара (а то я сразу не понял зачем в трейлинге понятие тейкпрофита).

По поводу классов для МТ4, да это было бы очень классно иметь такие же классы как и в МТ5. Конечно логика торговли отличается, но возможность использования классов дает абстраигироваться от имен предопределенных функций. Т.е. если не использовать хеджирование, можно было бы один и тот же код скомпилировать под МТ4 и МТ5 (конечно еще кучу ньюансов по поводу того же трейлинг стопа, или доливки в имеющуюся позицию). Эх городить еще можно кучу всего

 
ITeXPert:

Написал свой класс 

Все вроде верно. Я бы попробовал указать спецификацию virtual, а потом - поставил бы внутри функции точку останова (для прохождения в деббагере), или хотя бы Print, чтобы видеть, что управление вошло в ВАШУ функцию. Потому, что похоже на то, что управление по-прежнему вызывает функцию предка.
 
ITeXPert:

В общем нужно еще переопределить CheckOpenLong и CheckOpenShort.

Эти функции вызываются из ChekcOpen(), а если у вас открыта позиция - эта функция вызываться, вроде как не должна.

 

Странно то что если я в своем классе переопределяю функцию CheckOpenLong() и CheckOpenLong()

bool CheckOpenLong()
{
   if(PositionSelect(Symbol())) //если удалось выбрать позицию, возвращаем false, чтобы не доливаться и не открываться в противоположном направлении
      if (PositionGetDouble(POSITION_PROFIT) > 50) return (true);
   return (false);
};

bool CheckOpenShort()
{
   if(PositionSelect(Symbol())) //если удалось выбрать позицию, возвращаем false, чтобы не доливаться и не открываться в противоположном направлении
      if (PositionGetDouble(POSITION_PROFIT) > 50) return (true);
   return (false);
};

 то советник вообще не входит в рынок, притом второй if можно не указывать, т.е. вся логика ломается об первое условие

Причина обращения: