Скачать MetaTrader 5

Изменение лота последующего ордера при условии ...

Авторизуйтесь или зарегистрируйтесь, чтобы добавить комментарий
Есть вопросы автору статьи? Обсуди их на форуме!
Dmitry44
16
Dmitry44 2016.05.10 13:44 

Привет, подскажите, наверняка кто-то уже с этим сталкивался, я хочу реализовать следующий момент -> если у меня лотность предыдущего ордера больше значения n, то следующий ордер я хочу выставить с лотностью n/2

if (OrderSelect (OrdersTotal(),SELECT_BY_POS,MODE_TRADES))

  {

        if ( OrderLots() >n )

            {

                 double lots = n/2;

            }        

   }

В чём может быть проблема? так как у меня это не работает, заранее спасибо
LRA
336
LRA 2016.05.10 17:09  
Dmitry44:  так ... не работает
if (OrderSelect (OrdersTotal(),SELECT_BY_POS))
{
        if ( OrderLots() >n )   double lots = n/2;       
}
1) OrdersTotal() - количество ордеров. Ордера нумеруются от 0 до OrdersTotal()-1.  Ордер с номером OrdersTotal() не существует.

2) Есть мнение, что ордера в базе данных МОГУТ располагаться в другом порядке... Последний по номеру последний ли по времени? Говорят, надо проверить...

3) Переменная double lots, объявлена внутри блока (часть кода, заключенная в фигурные скобки), принадлежит локальной области видимости. Такая переменная не видна (поэтому и недоступна) за пределами блока, в котором она объявлена.

4) MODE_TRADES - можно не указывать



Artyom Trishkin
Модератор
75735
Artyom Trishkin 2016.05.10 18:27  
Dmitry44:

Привет, подскажите, наверняка кто-то уже с этим сталкивался, я хочуреализовать следующий момент -> если у меня лотность предыдущегоордера больше значения n, то следующий ордер я хочу выставить слотностью n/2

if (OrderSelect (OrdersTotal(),SELECT_BY_POS,MODE_TRADES))

  {

        if ( OrderLots() >n )

            {

                 double lots = n/2;

            }        

   }

В чём может быть проблема? так как у меня это не работает, заранее спасибо

Приблизительно что-то вроде того:

   double Lots=0.1;
   double n=10.0;
   double lastCloseLots=LotsLastClosePos(Symbol(),Magic);
   double lastOpenLots=LotsLastOpenPos(Symbol(),Magic);
   
   //--- если работаем по лоту последней закрытой позиции
   if(lastCloseLots>0 && lastCloseLots>n) Lots=NormalizeLot(Symbol(),n*0.5);
   //--- если работаем по лоту последней открытой позиции
   if(lastOpenLots>0 && lastOpenLots>n) Lots=NormalizeLot(Symbol(),n*0.5);
//+------------------------------------------------------------------+
double LotsLastClosePos(string sy, int mn) {
   datetime tm=0;
   double lots=0;
   for(int i=0; i<OrdersHistoryTotal(); i++) {
      if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)) {
         if(OrderMagicNumber()!=mn) continue;
         if(OrderSymbol()!=sy)      continue;
         if(OrderCloseTime()>tm) {
            tm=OrderCloseTime();
            lots=OrderLots();
            }
         }
      }
   return(lots);
}
//+------------------------------------------------------------------+
double LotsLastOpenPos(string sy, int mn) {
   datetime tm=0;
   double lots=0;
   for(int i=OrdersTotal()-1; i>=0 i--) {
      if(OrderSelect(i,SELECT_BY_POS)) {
         if(OrderMagicNumber()!=mn) continue;
         if(OrderSymbol()!=sy)      continue;
         if(OrderOpenTime()>tm) {
            tm=OrderOpenTime();
            lots=OrderLots();
            }
         }
      }
   return(lots);
}
//+------------------------------------------------------------------+
double NormalizeLot(string sy, double order_lots) {
   double ml=SymbolInfoDouble(sy,SYMBOL_VOLUME_MIN);
   double mx=SymbolInfoDouble(sy,SYMBOL_VOLUME_MAX);
   double ln=NormalizeDouble(order_lots,int(ceil(fabs(log(ml)/log(10)))));
   return((ln<ml)?ml:(ln>mx)?mx:ln);
}
//+------------------------------------------------------------------+
Vladimir
328
Vladimir 2016.05.10 22:26  
LRA:
 2) Есть мнение, что ордера в базе данных МОГУТ располагаться в другом порядке... Последний по номеру последний ли по времени? Говорят, надо проверить...
Наверное, стоит отметить, что это не просто мнение. Мне запомнился ответ одного из представителей разработчика двух- трехгодичной давности на прямой вопрос об упорядоченности ордеров в истории, звучавший (по памяти) так: "Metaquotes не гарантирует никакой упорядоченности в историческом списке ордеров". При этом сам я никогда не встречал неупорядоченных исторических списков, и упорядочены они были всегда по возрастанию тикетов. Можно предполагать, что тикеты используются как первичный ключ в базах данных. Но это лишь догадка, никто этого не гарантирует. Никакие проверки гарантии на будущее не дадут.
Artyom Trishkin
Модератор
75735
Artyom Trishkin 2016.05.10 23:19  
Vlad143:
Наверное, стоит отметить, что это не просто мнение. Мне запомнился ответ одного из представителей разработчика двух- трехгодичной давности на прямой вопрос об упорядоченности ордеров в истории, звучавший (по памяти) так: "Metaquotes не гарантирует никакой упорядоченности в историческом списке ордеров". При этом сам я никогда не встречал неупорядоченных исторических списков, и упорядочены они были всегда по возрастанию тикетов. Можно предполагать, что тикеты используются как первичный ключ в базах данных. Но это лишь догадка, никто этого не гарантирует. Никакие проверки гарантии на будущее не дадут.
Как так? Ищем ордера и позиции по времени - однозначная гарантия что выберите именно первый, или именно последний - тот, который именно и ищете.
Vladimir
328
Vladimir 2016.05.11 04:38  
artmedia70:
Как так? Ищем ордера и позиции по времени - однозначная гарантия что выберите именно первый, или именно последний - тот, который именно и ищете.

Совершенно верно. Если ИЩИТЕ и искомый параметр (время) различается у всех ордеров не меньше, чем на секунду (с такой погрешностью можно узнать время в свойствах ордера, это тип datetime). Если же просто взять последний по порядку номеров в массиве, с номером (OrdersTotal()-1), то никто не гарантирует, что у него будет наибольшее в истории время открытия или закрытия или тикет или что-либо еще. В случае, если в истории тысячи или десятки тысяч ордеров, этот поиск может занять много времени, если осуществлять его простым перебором. Но другого выхода нет. Искать необходимо, упорядоченности нет.

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

Конкретно в случае поиска именно последнего добавленного в историю ордера возможны неприятности и при любой длине истории. Если добавление произошло только что (например, 10-100 миллисекунд тому назад), то высока вероятность того, что в истории, которая доступна советнику (скрипту), нового ордера еще нет. Нужно подождать, пока изменение истории на сервере отразится в изменении истории на терминале. В MQL5 нужно еще ждать, когда история из терминальной копии перейдет в тот экземпляр памяти, в котором хранится история конкретно для этого советника или скрипта. Этот механизм отражен в документации на MQL5, в документации MQL4 таких сведений не встречал. А задержки с обновлением истории встречал. Ждать лучше в цикле с задержкой 16 мс и проверкой появления в истории последнего добавленного ордера.

Вопрос обновления истории я изучал только для ордеров "с рынка", для открытия по OrderSend и закрытия по OrderClose. Для отложенных (buystop, buylimit, sellstop, selllimit) сказать не могу ничего, кроме того, что их превращение на сервере в открытые сделки вовсе не является сигналом к началу обновления истории в терминале, как это могло бы показаться. Успевает ли история в терминале обновиться до вызова события прихода тика (советники), не знаю. Тем более не знаю, когда этого следует ожидать в скриптах. Хорошо бы, если бы знающие люди ответили. Интересно, в частности, когда программа на MQL сможет узнать о том, что уже сработал TakeProfit или StopLoss.

Artyom Trishkin
Модератор
75735
Artyom Trishkin 2016.05.11 08:24  
Vlad143:

Совершенно верно. Если ИЩИТЕ и искомый параметр (время) различается у всех ордеров не меньше, чем на секунду (с такой погрешностью можно узнать время в свойствах ордера, это тип datetime). Если же просто взять последний по порядку номеров в массиве, с номером (OrdersTotal()-1), то никто не гарантирует, что у него будет наибольшее в истории время открытия или закрытия или тикет или что-либо еще. В случае, если в истории тысячи или десятки тысяч ордеров, этот поиск может занять много времени, если осуществлять его простым перебором. Но другого выхода нет. Искать необходимо, упорядоченности нет.

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

Конкретно в случае поиска именно последнего добавленного в историю ордера возможны неприятности и при любой длине истории. Если добавление произошло только что (например, 10-100 миллисекунд тому назад), то высока вероятность того, что в истории, которая доступна советнику (скрипту), нового ордера еще нет. Нужно подождать, пока изменение истории на сервере отразится в изменении истории на терминале. В MQL5 нужно еще ждать, когда история из терминальной копии перейдет в тот экземпляр памяти, в котором хранится история конкретно для этого советника или скрипта. Этот механизм отражен в документации на MQL5, в документации MQL4 таких сведений не встречал. А задержки с обновлением истории встречал. Ждать лучше в цикле с задержкой 16 мс и проверкой появления в истории последнего добавленного ордера.

Вопрос обновления истории я изучал только для ордеров "с рынка", для открытия по OrderSend и закрытия по OrderClose. Для отложенных (buystop, buylimit, sellstop, selllimit) сказать не могу ничего, кроме того, что их превращение на сервере в открытые сделки вовсе не является сигналом к началу обновления истории в терминале, как это могло бы показаться. Успевает ли история в терминале обновиться до вызова события прихода тика (советники), не знаю. Тем более не знаю, когда этого следует ожидать в скриптах. Хорошо бы, если бы знающие люди ответили. Интересно, в частности, когда программа на MQL сможет узнать о том, что уже сработал TakeProfit или StopLoss.

Всё бы ничего, только зачем цепляться и поправлять меня в слове "ищете"? Особенно, если ваша поправка не соответствует правилам русского языка...

Что делаете? Ищете?

Что делаешь? Ищешь?

Делайте! Ищите!

Разве сейчас нету времени в милисекундах?

А вообще, данные в терминал приходят с каждым новым тиком. Может стоит проверить на новом тике появление в истории очередного ордера? Ну и его время с милисекундами. (Я не проверял)

LRA
336
LRA 2016.05.11 10:00  

Рассудим логически. Ордера помещаются в базу данных истории в момент их закрытия. При последовательном выборе их SELECT_BY_POS,MODE_HISTORY ордер с номером OrdersHistoryTotal()-1 должен оказаться последним. Вряд ли разработчикам придет в голову мысль усложнить программу и, тем самым, изменить порядок помещения ордеров в базу данных.

При получении отчета по истории ордера сортируются в том порядке, в каком они расположены на вкладке История Счета. А их расположение на этой вкладке можно изменить на прямое или обратное, щелкая по заголовкам таблиц. И если когда-то функция Select() была сложнее и выбирала ордера в соответствии с расположением ордеров на вкладке История Счета, то очевидно, что разработчики отказались от этого усложнения. Очевидно также, что возврат к этому усложнению невозможен, т.к. настоящее положение устраивает пользователей и запросы на усложнение со стороны пользователей отсутствуют.

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

Vladimir
328
Vladimir 2016.05.11 14:48  
artmedia70:

Всё бы ничего, только зачем цепляться и поправлять меня в слове "ищете"? Особенно, если ваша поправка не соответствует правилам русского языка...

Что делаете? Ищете?

Что делаешь? Ищешь?

Делайте! Ищите!

Разве сейчас нету времени в милисекундах?

А вообще, данные в терминал приходят с каждым новым тиком. Может стоит проверить на новом тике появление в истории очередного ордера? Ну и его время с милисекундами. (Я не проверял)

- странно. Это как раз я допустил в этом месте ошибку в русском языке, никого не поправлял. Выделил слово "ищете", чтобы подчеркнуть, что есть разница между тем, чтобы просто выбрать последний по номеру ордер, и между работой по поиску, которая может оказаться большой;

- время как свойство ордера в истории возвращают всего три функции. Вот куски из справки: "datetime  OrderOpenTime();", "datetime  OrderCloseTime();" "datetime  OrderExpiration();" "Тип datetime предназначен для хранения даты и времени в виде количества секунд, прошедших с 01 января 1970 года.". Миллисекунды не встречаются.

- правильно ли я Вас понял, что до начала обработки события в OnTick() история, с которой работает советник, всегда уже актуализирована? Или приходит тик, генерируется событие  NewTick, запускается OnTick(), а вслед за этим начинает обновляться история?

Vladimir
328
Vladimir 2016.05.11 15:51  
LRA:

Рассудим логически. Ордера помещаются в базу данных истории в момент их закрытия. При последовательном выборе их SELECT_BY_POS,MODE_HISTORY ордер с номером OrdersHistoryTotal()-1 должен оказаться последним. Вряд ли разработчикам придет в голову мысль усложнить программу и, тем самым, изменить порядок помещения ордеров в базу данных.

При получении отчета по истории ордера сортируются в том порядке, в каком они расположены на вкладке История Счета. А их расположение на этой вкладке можно изменить на прямое или обратное, щелкая по заголовкам таблиц. И если когда-то функция Select() была сложнее и выбирала ордера в соответствии с расположением ордеров на вкладке История Счета, то очевидно, что разработчики отказались от этого усложнения. Очевидно также, что возврат к этому усложнению невозможен, т.к. настоящее положение устраивает пользователей и запросы на усложнение со стороны пользователей отсутствуют.

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

Спасибо.

Возникло сомнение относительно вкладки "Торговля", где параметры вкладки "История счета" не действуют. Выяснил, что зря говорил об истории. Подразумевал список всех ордеров, но не одну лишь историю счета.

Стал читать, что следует называть историей в справке к MQL4 на слово "OrderSelect". Неожиданно нашел теперь уже в справке точный ответ на вопрос об упорядоченности ордеров:

"При последовательном выборе ордеров с помощью параметра SELECT_BY_POS информация отдаётся в том порядке, в котором она поступила с торгового сервера. Никакая сортировка полученного списка ордеров не гарантируется."

Это относится как к списку открытых и отложенных ордеров (MODE_TRADES в Select), так и к списку закрытых и удаленных ордеров (="история терминала", видимая во вкладке "История счета"). Я ошибочно говорил об истории (истории счета), реально речь шла о распространении изменений в первом списке от сервера до терминала и до MQL программы. Второй список не меняется при добавлении новых ордеров. Однако порядок поступления элементов списков с сервера в терминал, как уточняют разработчики, никакой не гарантируется. Возможно, это сделано для упрощения асинхронного (одновременного, параллельного) исполнения запросов к серверу.

Artyom Trishkin
Модератор
75735
Artyom Trishkin 2016.05.11 18:26  
Vlad143:

Спасибо.

Возникло сомнение относительно вкладки "Торговля", где параметры вкладки "История счета" не действуют. Выяснил, что зря говорил об истории. Подразумевал список всех ордеров, но не одну лишь историю счета.

Стал читать, что следует называть историей в справке к MQL4 на слово "OrderSelect". Неожиданно нашел теперь уже в справке точный ответ на вопрос об упорядоченности ордеров:

"При последовательном выборе ордеров с помощью параметра SELECT_BY_POS информация отдаётся в том порядке, в котором она поступила с торгового сервера. Никакая сортировка полученного списка ордеров не гарантируется."

Это относится как к списку открытых и отложенных ордеров (MODE_TRADES в Select), так и к списку закрытых и удаленных ордеров (="история терминала", видимая во вкладке "История счета"). Я ошибочно говорил об истории (истории счета), реально речь шла о распространении изменений в первом списке от сервера до терминала и до MQL программы. Второй список не меняется при добавлении новых ордеров. Однако порядок поступления элементов списков с сервера в терминал, как уточняют разработчики, никакой не гарантируется. Возможно, это сделано для упрощения асинхронного (одновременного, параллельного) исполнения запросов к серверу.

Самый надёжный способ найти последний ордер - перебор всех ордеров по времени. Есть люди, пренебрегающие этим, говорящие, что всё устаканилось, и всё работает точно и чётко при выборе OrdersTotal()-1 или 0. Но это всё очень не надёжно. Я остановился на переборе по времени и не завишу от случая.
12
Авторизуйтесь или зарегистрируйтесь, чтобы добавить комментарий