// =================== ParamOrdera() =============================================================== // Функция возвращает цену стопа, тейка, открытия и закрытия указанного ордера // Параметры переменных: // - Ticket - тикет ордера. Его нужно предварительно узнать с помощью функции TicketOrdera() // - Param может принимать значения: "OPENPRICE", "CLOSEPRICE", "STOPLOSS", "TAKEPROFIT", "LOT" // значение "CLOSEPRICE" может указываться только для закрытых ордеров // - Type может принимать значения: "BUY", "SELL", "BUYSTOP", "SELLSTOP", "BUYLIMIT", "SELLLIMIT", // "HISTBUY", "HISTSELL", "HISTBUYSTOP", "HISTSELLSTOP", "HISTBUYLIMIT", "HISTSELLLIMIT" // --------- // Если на вход функции будет подано значение Param=="CLOSEPRICE" и при этом указан тикет ордера,ещё // не закрытого, то функция выдаст сообщение об ошибке и вернёт значение = (-1), так как ордера, // которые ещё не находятся в истории, не имеют цены закрытия // ------------------------------------------------------------------------------------------------- double ParamOrdera(int Ticket,string Param,string Type){ string NameFunction="ParamOrdera()"; int DGS=MarketInfo(SMB,MODE_DIGITS); double PRC=-1; // ------------- обработка ошибок ------------------ if(Param=="CLOSEPRICE"){ if(Type=="BUY" || Type=="SELL" || Type=="BUYSTOP" || Type=="SELLSTOP" || Type=="BUYLIMIT" || Type=="SELLLIMIT"){ Print("На вход функции подано значение CLOSEPRICE, а тип ордера - не ордер истории - Type = ",Type); Print("Ошибка возникла в функции ",NameFunction); return(-1); } } if(Param!="OPENPRICE" && Param!="CLOSEPRICE" && Param!="STOPLOSS" && Param!="TAKEPROFIT" && Param!="LOT"){ Print("некорректное значение переменной Param = ",Param); Print("Ошибка возникла в функции ",NameFunction); return(-1); } if(Type!="BUY" && Type!="SELL" && Type!="BUYSTOP" && Type!="SELLSTOP" && Type!="BUYLIMIT" && Type!="SELLLIMIT" && Type!="HISTBUY" && Type!="HISTSELL" && Type!="HISTBUYSTOP" && Type!="HISTSELLSTOP" && Type!="HISTBUYLIMIT" && Type!="HISTSELLLIMIT"){ Print("Некорректное значение переменной Type = ",Type); Print("Ошибка возникла в функции ",NameFunction); return(-1); } // ---------------------------------------------------------------------- // --------- Для ордеров из рынка --------------------------- if(Type=="BUY" || Type=="SELL" || Type=="BUYSTOP" || Type=="SELLSTOP" || Type=="BUYLIMIT" || Type=="SELLLIMIT"){ for (int i=OrdersTotal()-1;i>=0;i--) { if (!OrderSelect(i,SELECT_BY_POS,MODE_TRADES)) { WriteError(i); Print("Ошибка возникла в функции ",NameFunction); } else { if(OrderSymbol()!= SMB || OrderMagicNumber()!= MAGIC){continue;} if(OrderTicket()==Ticket){ if(Param=="LOT"){ PRC=NormalizeDouble(OrderLots(),DGS); return(PRC); } if(Param=="OPENPRICE"){ PRC=NormalizeDouble(OrderOpenPrice(),DGS); return(PRC); } if(Param=="STOPLOSS"){ PRC=NormalizeDouble(OrderStopLoss(),DGS); return(PRC); } if(Param=="TAKEPROFIT"){ PRC=NormalizeDouble(OrderTakeProfit(),DGS); return(PRC); } } } } } // --------- Для ордеров из истории торгов --------------------------- if(Type=="HISTBUY" || Type=="HISTSELL" || Type=="HISTBUYSTOP" || Type=="HISTSELLSTOP" || Type=="HISTBUYLIMIT" || Type=="HISTSELLLIMIT"){ for (int ii=OrdersHistoryTotal()-1;ii>=0;ii--) { if (!OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)) { WriteError(ii); Print("Ошибка возникла в функции ",NameFunction); } else { if(OrderSymbol()!= SMB || OrderMagicNumber()!= MAGIC){continue;} if(OrderTicket()==Ticket){ if(Param=="LOT"){ PRC=NormalizeDouble(OrderLots(),DGS); return(PRC); } if(Param=="OPENPRICE"){ PRC=NormalizeDouble(OrderOpenPrice(),DGS); return(PRC); } if(Param=="CLOSEPRICE"){ PRC=NormalizeDouble(OrderClosePrice(),DGS); Print("Параметр CLOSEPRICE ордера № ",Ticket," = ",PRC); return(PRC); } if(Param=="STOPLOSS"){ PRC=NormalizeDouble(OrderStopLoss(),DGS); return(PRC); } if(Param=="TAKEPROFIT"){ PRC=NormalizeDouble(OrderTakeProfit(),DGS); return(PRC); } } } } } if(Param=="CLOSEPRICE"){ Print("Ордера № ",Ticket," в истории не существует"); } return(PRC); }Понимаю, что можно и как обойти эту пролбему. Но всё же интересен ответ на вопрос, почему одна подпрограмма возвращает нам тикет последнего ордера истории, а другая не видит его в той же самой истории?
Хочу ещё пояснить, почему я выбрал вычисление последнего уровня через точку закрытия последнего ордера истории. Дело в том, что можно было бы поступить следующим образом: сбрасываем лот, запоминаем цену сброса. НО! При отключении электопитания, когда советник снова включится в работу, он эту предыдущую, запоменную цену сброса уже не увидит - переменная будет обнулена. Поэтому можно просто пройтись по истории, найти последний закрытый ордер и посмотреть цену его закрытия - это будет лучше, чем запоминать эту цену в переменную и дальше опираться исключительно на значение, хранящееся в этой переменной.
Почему я разбил цену ти тикет на две разные функции, становится понятно, если посмотреть на сами функции - получение тикета последнего ордера позволяет впоследствии запросить не только цену его закрытия, но и другие параметры, которые нам могут понадобиться.
P.S.
Да, и вот ещё что. Я отказался выбирать ордер через OrderSelect(Ticket,SELECT_BY_TICKET) так как это почему-то не всегда работает. Неоднократно уже приходилось из-за этого переделывать собственные подпрограммы.
Попробуйте поискать этот тикет на следующем тике. Обновление базы истории не происходит мгновенно, видимо дело в этом.
Попробуйте поискать этот тикет на следующем тике. Обновление базы истории не происходит мгновенно, видимо дело в этом.
Спасибо за оперативность!
Поначалу так и было - сбрасывался лот и на текущем тике отыскивался тикет ордера по-новой, так как при сбросе лотов тикет меняется. Отыскивался для следующего участка кода - для трала стопа. Далее, поскольку я столкнулся с проблемой, я закомментировал полностью блок трала стопа и оставил в работе только блок сброса лотов. Итак, что получилось в результате - советник увидел, что в рынке появился ордер, он проверяет, ни пора ли сбросить лот. Если пора, то лот сбрасывается и ни каких запросов больше не происходит - советник ждёт следующего тика чтоб снова проверить, а ни пора ли снова сбросить лот. На следующем тике всё происходит по-новой. Проблема в том, что после первого сброса всё нормально отыскивается. После второго сброса тикета ордера нет уже на следующем и других тиках.
Я нашёл способ обойти глюк через проверку времени закрытия ордера - но проблема-то остаётся.
1. Функция TicketLastHistOrdera возвращает не последний ордер, соответствующий запросу, а первый! После того, как ордер найден, надо бы выйти из цикла (поставить break)
2. А почему Вы не представили функцию, которая возвращает ответ "Ордера № 2 в истории не существует"?
1. Функция TicketLastHistOrdera возвращает не последний ордер, соответствующий запросу, а первый! После того, как ордер найден, надо бы выйти из цикла (поставить break)
2. А почему Вы не представили функцию, которая возвращает ответ "Ордера № 2 в истории не существует"?
Функция TicketLastHistOrdera() проходит по списку ордеров. Поскольку изначально переменная CloseTime=0, то встретив первый попавшийся, скажем,Бай-ордер, она в эту переменную запомнит время его закрытия. Далее, проходя по всем прочим бай-ордерам, в этой перемнной кажется время закрытия, которое самое большое. Понятно, что у последнего ордера время закрытия будет самым большим. Попутно в другую переменную будет запомнен тикет ордера. Так что функция написана верно и возвращать она должна тикет ПОСЛЕДНЕГО ордера. Вникните. Что касается брека, то он тут ни к селу ни к городу (простите за прямоту). Если поставить брек, то мы рискуем пройти не по всему списку ордеров и прерваться раньше времени. Я вообще не представляю, из каких соображений Вы посоветовали сунуть сюда брек.
>> 2. А почему Вы не представили функцию, которая возвращает ответ "Ордера № 2 в истории не существует"?
Отвечаю, в функции ParamOrdera() предпоследняя строка: " Print("Ордера № ",Ticket," в истории не существует");" Она будет выполнена только если ордера с заданным тикетом не существует. Если такой существует, то функция прервётся раньше и это сообщение попросту не выстрелит в журнал.
Без полного кода трудно сказать. Попробуйте написать в Сервисдеск - https://www.mql5.com/ru/users/drknn
Код смоделировать не сложно - хотите я это сделаю? Там ведь нужно всего-навсего поставить условие, мол, если ордеров в рынке нет, то открываем бай и селл в обоих направлениях. Не важно, что не будет профита, важно что мы сможем отследить глюк тестера. Далее блок сброса лотов. Тож не сложно сделать.
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Столкнулся сегодня с прелюбопытнейшим явлением и так и не понял что это - ошибка у меня в коде, или глюк тестера в терминале.
Суть в следующем. Приходит сигнал, открываем ордер. Цена поехала в профит и прошла расстояние = некоему шагу. Сбрасываем небольшой лот. Далее цена проходит ещё в профит и ещё расстояние = шагу. Чтобы не вычислять сколько раз был сброшен маленький лот и действительно ли цена снова прошла нужный нам шаг, я поступил следующим образом.
1. Пишем функцию, которая возвращает тикет последнего закрытого ордера истории.
2. Найденный только что тикет передаём в другую функцию, которая возвращает нужный нам параметр ордера - нам нужна цена закрытия, поэтому помимо тикета передаём в эту функцию спецпараметр.
3. Цена закрытия последнего ордера + шаг = уровень, на котором нужно сбросить очередной лот.
Такое построение кода куда более проще, чем запоминать время старта ордера, вычислять сколько же раз уже были сброшены лоты и просчитывать расстояние, которое цена прошла для сброса очередного лота.
Ну так вот, что любопытно. Перед первым сбросом лота функция возврата тикета ордера истории возвращает (-1) - ну оно и понятно - ведь тест только что стартонул и пока что ещё не закрыто не одного ордера. Советник понимает, что нужно отследить растояние = шагу сброса. Далее происходит сброс (цена прошла нужный шаг), и на следующем тике функция возврататикета возвращает нам 1 - это тоже понятно - в тестере первый закрытый ордер будет иметь тикет = 1. Функция возврата цены закрытия прекрасно видит в истории ордер №1 и прекрасно возвращает цену его закрытия. До этих пор всё прекрасно работает. Длее цена снова едет в профит и достигает уровня = цена закрытия ордера + шаг сроса лотов. Как только это случилось, у позиции сбрасывается второй маленький лот. Скажу сразу, ордер открывается с лотом = 1, а сбрасывается каждый раз лот = 0,1. Ну так вот. Как только произошёл сброс второго лота, функция поиска тикета последнего закрытого ордера возвращает нам тикет = 2. Всё верно - после второго сброса ордер 2 в истории и функция его видит. Передача этого тикета в функцию, которая может вернуть нам цену его закрытия приводит к тому, что функция возвращает ответ: "Ордера № 2 в истории не существует"!
Вначале я грешил на себя - искал ошибку в коде. Найти так и не удалось. Тогда я решил обновить терминал - у меня стоял Билд 225, я обновился до 229. Результат тот же самый - всех последующих ордеров в истори не существует - ордера невидимки :). Вот код, который я задействовал.