Мой эксперт выполняет двойную запись - страница 7

 

если я использую сон, я потеряю тики?

каковы будут последствия? можете поделиться со мной?

Documentation on MQL5: Common Functions / Sleep
Documentation on MQL5: Common Functions / Sleep
  • www.mql5.com
Common Functions / Sleep - Documentation on MQL5
 
doshur:

если я использую сон, я потеряю тики?

каковы будут последствия? можете поделиться со мной?

Это зависит от вашей стратегии. Поскольку эта проблема "двойных сделок" может возникнуть только тогда, когда ваш торговый код выполняется на каждом тике, у вас, вероятно, есть стратегия, которая зависит от тиков. Поэтому вам предстоит оценить, каковы могут быть последствия, если вы потеряете тики, которые приходят во время задержки (сна).

 
angevoyageur:

Это зависит от вашей стратегии. Так как эта проблема о "двойных сделках" может возникнуть только тогда, когда ваш торговый код выполняется на каждом тике, у вас, вероятно, есть стратегия, которая зависит от тика. Поэтому вы сами должны оценить, каковы могут быть последствия, если вы потеряете тики, которые придут во время вашей задержки (сна).

Так, если я просплю 800

значит, я потеряю тики на следующие 800 мс? После того, как я вхожу в сделку, мой советник ничего не делает, только сидит там до TP или SL или ждет времени для выхода.

Значит, моя стратегия в порядке, если я использую sleep?

Возвращает ли вызов refreshrates() тики?

Documentation on MQL5: Common Functions / Sleep
Documentation on MQL5: Common Functions / Sleep
  • www.mql5.com
Common Functions / Sleep - Documentation on MQL5
 
doshur:

Значит, если я сплю в течение 800

значит, я теряю тики на следующие 800 мс? После того, как я вхожу в сделку, мой советник ничего не делает, только сидит там до TP или SL или ждет времени для выхода.

Значит, моя стратегия в порядке, если я использую sleep?

Возвращает ли вызов refreshrates() тики?

doshur, тики вы теряете, вы теряете, нет машины обратного хода.

По поводу документации наhttps://www.mql5.com/en/docs/common/sleep функцияприостанавливает выполнение текущего эксперта или скрипта в заданном интервале.

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

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

Именно поэтому я предлагаю цикл тестирования PositionSelect после открытия сделки, чтобы дважды проверить выполнение PositionOpen и возврат как лучшее обходное решение, чем просто Sleep(), и это также устраняет причину проблемы (согласно тестамangevoyageur).

Documentation on MQL5: Common Functions / Sleep
Documentation on MQL5: Common Functions / Sleep
  • www.mql5.com
Common Functions / Sleep - Documentation on MQL5
 

Это то, что я использую сейчас. Где я должен закодировать обходное решение, предоставленное figurelli, более элегантным способом.

//
         {
            Price = SymbolInfoDouble(Symbol(), SYMBOL_ASK);

            if(m_Trade.PositionOpen(Symbol(), ORDER_TYPE_BUY, LotSize, Price, 0, 0))
            {
               Sleep(800);

               if(m_Trade.ResultRetcode() == 10009)
               {
                  Print("Position opened in ", Symbol());

                  return;
               }
               else
               {
                  Print("Error opening position in ", Symbol(), " - ", m_Trade.ResultComment(), "\n", "Return Code Desc - ", m_Trade.ResultRetcodeDescription());
               }
            }
            else
            {
               Print("Error with PositionOpen in ", Symbol(), " - ", m_Trade.ResultComment(), "\n", "Return Code Desc - ", m_Trade.ResultRetcodeDescription());
            }
         }
 
doshur:

Это то, что я использую сейчас. Где я должен закодировать обходной путь, предложенный figurelli, более элегантным способом.

Здравствуйте, doshur, у меня тоже были проблемы с двойной записью в одном из моих советников. На самом деле, эти проблемы возникали только тогда, когда я торговал высоколиквидными активами. Даже после настройки отправки ордеров в асинхронном режиме, советник "видимо" слишком долго ждал ответа сервера для обновления PositionsTotal()... тем временем другие входящие тики запускали условия для отправки второго ордера... на португальском форуме я опубликовал обходной путь, которым хотел бы поделиться здесь.

Идея проста:

//--- global variables
CTrade trade;
bool position_opened=false;

//--- inside OnTick()
if( conditions to open && position_opened==false )
  {
   //--- set the global variable to true to avoid duplicate orders
   position_opened=true;
   trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,"comment");
  }

Единственная проблема с этим кодом - это случай, когда ордер не принимается сервером, поэтому вам нужно "сбросить" глобальную переменную... Вы можете использовать это:

MqlTradeResult mresult;

//--- 
if(mresult.retcode==10009 || mresult.retcode==10008)
  {Print("Success!");}
else 
  {
   Print("Error = ",GetLastError());
   ResetLastError();
   //--- Sets the global variable to false
   position_opened=false;
   return;
  }

Таким образом, в случае, если первый отправленный ордер возвращает ошибку, глобальная переменная будет установлена в false, чтобы советник мог отправить другой ордер. Однако, должен сказать, что я тестировал этот код только на акциях и фьючерсах, но не на рынке Форекс... :-(

 
Malacarne:

Здравствуйте, Дошур, у меня тоже были проблемы с двойными записями в одном из моих советников. На самом деле, эти проблемы возникали только тогда, когда я торговал высоколиквидными активами. Даже после настройки отправки ордеров в асинхронном режиме, советник "видимо" слишком долго ждал ответа сервера для обновления PositionsTotal()... тем временем другие входящие тики запускали условия для отправки второго ордера... на португальском форуме я опубликовал обходной путь, которым хотел бы поделиться здесь.

Идея проста:

Единственная проблема с этим кодом - это случай, когда ордер не принимается сервером, поэтому вам нужно "сбросить" глобальную переменную... Вы можете использовать это:

Таким образом, в случае, если первый отправленный ордер возвращает ошибку, глобальная переменная будет установлена в false, чтобы советник мог отправить другой ордер. Однако, должен сказать, что я тестировал этот код только на акциях и фьючерсах, но не на рынке Форекс... :-(

Это кажется жизнеспособным. Посмотрим, будут ли уfigurelli иangevoyageur какие-либо комментарии по этому обходному пути...
 
doshur:
Это кажется жизнеспособным. Давайте посмотрим, есть ли уfigurelli иangevoyageur какие-либо комментарии по этому обходному пути...

Это решение, предложенное Malacarne (с некоторыми корректировками, которые я предложу), является отличным, поскольку для меня это не обходной путь (как скромно называет Malacarne), а один элегантный и правильный способ решения этого вопроса.

На мой взгляд, изначальная проблема двойной записи - это не ошибка MT5, а ошибка кодирования, так как в справке указано:

"Успешное завершение метода PositionOpen(...) не всегда означает успешное выполнение торговой операции. Необходимо проверить результат торгового запроса (код возврата торгового сервера) с помощьюResultRetcode() и значение, возвращаемоеResultDeal()".

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

1) Протестируйте возврат PostionOpen() тоже, как в оригинальном коде, например:

if (trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,"comment")) position_opened=true;

2) Более полная обработка ResultRetcode(), так как у вас могут быть открыты другие соответствующие позиции, например, 10010 -TRADE_RETCODE_DONE_PARTIAL - Только часть запроса была выполнена. Также, 10008 - TRADE_RETCODE_PLACED - Order placed не является Success для меня, просто 10009 -TRADE_RETCODE_DONE -Request completed, и это асинхронные сообщения, так что вторая часть кода Malacarne могла бы рассмотреть это и/илитикет сделки, после того, как сделка будет выполнена.

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

 
Malacarne:

Здравствуйте, doshur, у меня тоже были проблемы с двойными записями в одном из моих советников. На самом деле, эти проблемы возникали только тогда, когда я торговал высоколиквидными активами. Даже после настройки отправки ордеров в асинхронном режиме, советник "видимо" слишком долго ждал ответа сервера для обновления PositionsTotal()... тем временем другие входящие тики запускали условия для отправки второго ордера... на португальском форуме я опубликовал обходной путь, которым хотел бы поделиться здесь.

Идея проста:

Единственная проблема с этим кодом - это случай, когда ордер не принимается сервером, поэтому вам нужно "сбросить" глобальную переменную... Вы можете использовать это:

Таким образом, в случае, если первый отправленный ордер возвращает ошибку, глобальная переменная будет установлена в false, чтобы советник мог отправить другой ордер. Однако, должен сказать, что я тестировал этот код только на акциях и фьючерсах, но не на рынке Форекс... :-(

Это правильный подход, однако вы должны сбросить вашу глобальную переменную position_opened в false, когда ваша позиция закрыта. Где вы это делаете?

О вашей реализации, некоторые детали:

  1. Нет необходимости устанавливать position_opened в true, а затем в false, если произошла ошибка.
  2. Вы используете объект класса CTrade, поэтому нет необходимости использовать новую структуру MqlTradeResult.
  3. Как отметил figurelli в своем сообщении, вы должны проверить возвращаемое значение PositionOpen.
  4. Имя класса CTrade, а не Ctrade. mql5 чувствителен к регистру.
  5. position_opened - это bool, не нужно сравнивать его с false. Если вы делаете это, вы должны использовать '==', а не '='.

Итак, вот измененный код(скомпилированный, но не протестированный):

//+------------------------------------------------------------------+
//|                                                      ProjectName |
//|                                      Copyright 2012, CompanyName |
//|                                       http://www.companyname.net |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>

//--- global variables
CTrade trade;
bool position_opened=false;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnTick()
  {
   bool conditions_to_open;
   ENUM_ORDER_TYPE order_type;
   double lot;
   double price,sl,tp;

//---...set variables

//--- inside OnTick()
   if(conditions_to_open && !position_opened) //-- Or position_opened==false
     {
      if(trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,"comment")
         && 
         (trade.ResultRetcode()==10009 || trade.ResultRetcode()==10008)) //-- Or others condition according to your needs
        {
         //--- set the global variable to true to avoid duplicate orders
         position_opened=true;
         Print("Success!");
        }
      else
        {
         Print("Error = ",GetLastError(), "trade error = ", trade.ResultRetcode());
         //--- Sets the global variable to false
         // position_opened=false;                                         //-- Not needed as position_opened is already false
         return;
        }

     }
//--- 
  }
//+------------------------------------------------------------------+
 
figurelli:

...

На мой взгляд, изначальная проблема двойной записи - это не ошибка MT5, а ошибка кодирования, поскольку в справке указано:

"Успешное завершение метода PositionOpen(...) не всегда означает успешное выполнение торговой операции. Необходимо проверить результат торгового запроса (код возврата торгового сервера) с помощьюResultRetcode() и значение, возвращаемоеResultDeal()".

Не думаю, что это имеет отношение к вопросу данной темы. Проблема, которую мы получаем, возникает в случае, когда запрос был успешно заполнен и позиция открыта. Но эта позиция открывается на торговом сервере, проблема, с которой мы столкнулись, это когда происходит задержка, более важная, чем обычно, и терминал MT5 получает уведомление об этой новой позиции ПОСЛЕ того, как новый тик уже обработан.

Это не баг, так как все так и задумано. НО, на мой взгляд, это плохой дизайн для платформы, которая позволяет явно синхронные и асинхронные торговые запросы. Мы говорим здесь о запросе, который должен быть синхронным, но на самом деле он не синхронный, так как когда вы получаете ответ от сервера на запрос (trade.ResultRetCode в коде выше), мы все еще должны ждать, пока платформа MT5 будет проинформирована и обновлена о результатах торговли. (Я понял все это с помощью этой темы).

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

1) Протестируйте возврат PostionOpen() тоже, как в оригинальном коде, например:

2) Более полная обработка ResultRetcode(), так как у вас могут быть открыты другие соответствующие позиции, например, 10010 -TRADE_RETCODE_DONE_PARTIAL - Только часть заявки была выполнена. Также, 10008 - TRADE_RETCODE_PLACED - Order placed не является Success для меня, просто 10009 -TRADE_RETCODE_DONE -Request completed, и этоасинхронные сообщения, так что вторая часть кода Malacarne могла бы рассмотреть это и/илитикет сделки, после того, как сделка будет выполнена.

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

Конечно, вы абсолютно правы, что нужно проверять возвращаемое значение PositionOpen И возвращаемый код результата торговли. Однако ResultRetCode является синхронным, это обновление базы данных MT5 о позиции (сделке и ордере) является асинхронным. Тест, который я сделал с вашим предложением, продемонстрировал это, так как я использую, конечно же, код, который проверяет возвращаемое значение торгового запроса.
Причина обращения: