Вопрос по простейшему эксперту

 
Добрый день, буквально со вчерашнего дня изучаю MQL, потому не обессудьте, если что не так. Мне хочется научиться писать эксперты, поскольку я пока учусь, вопросы стратегии я пока не рассматриваю, а хочу просто научиться открывать и закрывать ордеры. Исключительно в учебных целях я написал эксперт, который должен по моему замыслу делать следующее:
  1. При запуске (инициализации) открывать два отложенных ордера, один на 10 пунктов выше текущей цены, а другой на 10 пунктов ниже текущей цены.
  2. Далее, стартуя после каждого тика, проверять, закрылся ли хотя бы один из этих ордеров, и если хотя бы один закрылся, удалять оставшийся открытый ордер и открывать новые два ордера по принципу пункта 1.

Здесь нет никакой логики, мне важно научиться делать хотя бы это. В перспективе эксперт должен будет брать данные из внешнего файла и на их основе открывать ордеры, поэтому текущее, лишенное логики поведение эксперта, получит осмысленное развитие.

В связи со всем изложенным у меня есть несколько вопросов, буду очень признателен за ответы.

  1. Почему не смотря на то, что эксперт как бы работает, в верхнем правом углу графика нарисован крестик, что по справке означает, что эксперт не работает?
  2. Почему-то при запуске эксперта открывается лишь один ордер (тот который выше). Почему так происходит?
  3. Везде в коде используется функция Print(), использовать которую я начал, подражая примерам из справки, но где можно увидеть выводимые этой функцией сообщения?
  4. Что означают зелёные стрелочки и красные и синие чёрточки, которые появились на графике после запуска эксперта? Вот эти:
  5. Что в этом коде не соответствует замыслу?

Вот код моего эксперта (прошу прощения за стиль оформления кода, я просто привык к такой нотации):

#property copyright "polecat"
#property link      ""
 
int    TicketUp;
int    TicketDown;
double JumpSize;
 
void SetTwoOrders() {
   //Открыть два отложенных ордера вверх на 10 пипсов и вниз на 10 пипсов
   TicketUp = OrderSend(Symbol(), OP_BUYSTOP, 0.1, Ask + JumpSize, 3, Ask, Ask + (2 * JumpSize), "", 0, 0, Green);
   if (TicketUp < 0) {
      Print("OrderSend failed with error #", GetLastError());
      return(0);
   }
   TicketDown = OrderSend(Symbol(), OP_SELLSTOP, 0.1, Bid - JumpSize, 3, Bid, Bid - (2 * JumpSize), "", 0, 0, Blue);
   if (TicketDown < 0) {
      Print("OrderSend failed with error #", GetLastError());
      return(0);
   }
}
  
int init() {
   JumpSize = 10 * Point; //Устанавливаем размер скачка вверх и вниз
   SetTwoOrders();        //Открываем отложенные ордеры
}
 
int deinit() {
   return(0);
}
 
int start() {
   //Если хотя бы один ордер закрыт, удалить другой и открыть ордеры заново
   bool OneOrderWasClose;
   bool OrderUpWasClose;
   bool OrderDownWasClose;
   //Проверяем закрыт ли ордер "вверх"
   if (OrderSelect(TicketUp, SELECT_BY_TICKET) == true) {
      if (OrderCloseTime() != 0) {OrderUpWasClose = true;} else {OrderUpWasClose = false;}
   } else Print("OrderSelect() вернул ошибку - ", GetLastError());
   //Проверяем закрыт ли ордер "вниз"
   if (OrderSelect(TicketDown, SELECT_BY_TICKET) == true) {
      if (OrderCloseTime() != 0) {OrderDownWasClose = true;} else {OrderDownWasClose = false;}
   } else Print("OrderSelect() вернул ошибку - ", GetLastError());
   //Узнаём закрыт ли хотя бы один ордер
   if (OrderUpWasClose || OrderDownWasClose) {OneOrderWasClose = true;} else {OneOrderWasClose = false;}
  
   //Если закрыт хотя бы один ордер
   if (OneOrderWasClose) {
      //Удаляем другой откртый ордер
      if (!OrderUpWasClose) {
         if (!OrderDelete(TicketUp, CLR_NONE)) Print("OrderDelete() вернул ошибку - ", GetLastError());
      }
      if (!OrderDownWasClose) {
         if (!OrderDelete(TicketDown, CLR_NONE)) Print("OrderDelete() вернул ошибку - ", GetLastError());
      }
      //Открываем два ордера вновь
      SetTwoOrders();
   }
   return(0);
}

Заранее благодарю за помощь.

 
Нашел ответ на вопрос 2. Между открытием ордеров нужно ставить вызов функции RefreshRates().
 
polecat:
Нашел ответ на вопрос 2. Между открытием ордеров нужно ставить вызов функции RefreshRates().

И проверять
IsTradeContextBusy( ) != True
 
PSmith:
И проверять
IsTradeContextBusy( ) != True
Это нужно делать перед каждым открытием ордера или только при двойном?

Если вас не затруднит, вы можете как-нибудь помочь по другим вопросам? :)
 



1. Крестик в правом углу означает, что функция start не вызывается.
Функции init и deinit в экспертах вызываются всегда. 
Чтобы начала работать start нужно разрешить советников - кнопка "Советники" в верхней панели терминала и при установке советника на график разрешить ему торговать - первая закладка свойств советника.
2. Один ордер ставится потому что для второго торговый поток занят и цены изменились. Так наверное более правильно. Хотя установка ордеров в init это в корне противоречит принципам написания советников (потому что init выполняется всегда).

   TicketUp = OrderSend(Symbol(), OP_BUYSTOP, 0.1, Ask + JumpSize, 3, Ask, Ask + (2 * JumpSize), "", 0, 0, Green);
   if (TicketUp < 0) {
      Print("OrderSend failed with error #", GetLastError());
      return(0);
   }
//
   while(IsTradeContextBusy() == True){ ; }   
   RefreshRates();
//
   TicketDown = OrderSend(Symbol(), OP_SELLSTOP, 0.1, Bid - JumpSize, 3, Bid, Bid - (2 * JumpSize), "", 0, 0, Blue);
   if (TicketDown < 0) {
      Print("OrderSend failed with error #", GetLastError());
      return(0);
   }
3. Весь вывод сообщений от советников идет на закладку "Эксперты" в окне "Терминал".
4. Зеленые стрелочки - результат вызова функции OrderSend. Синие штрих-линии - уровни stop-loss и take-profit указанные в функции OrderSend
Зеленая штрих-пунктирная линия - уровень открытия ордера, который установлен, красные линии уровни stop-loss и take-profit установленного ордера.
5. В соответствие замыслу не вчитывался.

 
PSmith:

Огромное спасибо за обстоятельный ответ!

PSmith:
Хотя установка ордеров в init это в корне противоречит принципам написания советников (потому что init выполняется всегда).

В принципе если я уберу из init() вызов SetTwoOrders() поведение этого эксперта не изменится. :) Но спасибо за замечание.

Ещё раз благодарю!

 
polecat:

В принципе если я уберу из init() вызов SetTwoOrders() поведение этого эксперта не изменится. :) Но спасибо за замечание.


Допустим вы еще не решили хотите сегодня торговать или нет. Запускаете терминал просто посмотреть обстановку, тут же запрещаете работу советников.
Но уже поздно, init отработал, запросы ушли на сервер и вы в торгах! Переключили login, а советники на графиках опять отработали свои init'ы!
Аналогично даже хуже с deinit. При закрытии терминала выполняется deinit всех советников, а результат можно узнать только из файла журнала.
 
PSmith:



2. Один ордер ставится потому что для второго торговый поток
занят и цены изменились.

даже если это отложенные ордера?

у меня на реале успешно выставляются два отложенных ордера подряд на одном тике
 
Loky:
PSmith:



2. Один ордер ставится потому что для второго торговый поток
занят и цены изменились.

даже если это отложенные ордера?

у меня на реале успешно выставляются два отложенных ордера подряд на одном тике

Во первых не в функции init().
Во вторых https://docs.mql4.com/ru/runtime/start

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

Так что все таки не на одном тике!
 
PSmith:
Loky:

Так что все таки не на одном тике!


все таки на одном!

Все пришедшие во время выполнения программы новые котировки программой игнорируются до тех пор, пока не завершится очередное выполнение функции start(). А очередное выполнение не завершится пока не будет выставленно 2 отложенных ордера, причем если один выставляется то всегда есть и второй! Функция старт выставляет либо сразу 2 ордера либо 0 т.к стоит проверка если отложенных ордеров 0 тогда выставлять
 
Я вот не знаю на одном или нет, но до вставки этого кода:
while (IsTradeContextBusy() == true) {}
RefreshRates();
между открытиями ордеров, открывался только первый ордер. Сейчас открываются оба...