ФОРТС. Вопросы по исполнению - страница 74

 
leonerd:
Понятно, значит нет гарантии исполнения. 
100% гарантий даже в банке нет. Попробуйте поиграться с политикой исполнения "все-ничего". Только на Фортс этот режим кажется не работает. Также можно анализировать ликвидность стакана до непосредственного захода в рынок - во многих случаях может помочь. Однако 100% гарантий быть не может: рынок может либо гарантировать исполнение, либо гарантировать цену, но не одновременно эти два фактора. Что важнее - решать Вам.
 

  Ну, вот и разбанили Филимонова (  Mikhail Filimonov) очевидно после его просьбы. 

  Всего-то делов.   

 

Читал долго и внимательно.

За что забанили родоначальника темы понятно:

Нет человека - нет проблемы.

А задержки-то устранили? 

 
prostotrader:

Читал долго и внимательно.

За что забанили родоначальника темы понятно:

Нет человека - нет проблемы.

А задержки-то устранили? 

а кто их теперь будет замерять то кроме него? все бана боятся :)

 
coderex:

а кто их теперь будет замерять то кроме него? все бана боятся :)

Ну, для начала, нужно написать тестового эксперта:

//+------------------------------------------------------------------+
//|                                                   Test_delay.mq5 |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
input int Transactions=1500;
ulong order_ticket;
int tr_cnt;
ulong Magic=1234567890;
ulong order_id;
ulong start,stop;
#define ERR_ZERO_TICKET -1;
bool exp_busy;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum ENUM_ORD_SELECT
  {
   SELECT_ERROR = 0,
   SELECT_FALSE = 1,
   SELECT_TRUE  = 2,
   SELECT_BUSY  = 3
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum ENUM_ORD_REAL_STATE
  {
   ORD_NOT_SPECIFIED         = 0, //Состояние ордера не определено
   ORD_NONE_CANCELED         = 1, //Ордера нет, отменён пользователем
   ORD_NONE_PARTIAL_CANCELED = 2, //Ордера нет, исполнился частично (не был залит вторым объёмом)
   ORD_NONE_PARTIAL          = 3, //Ордера нет, исполнился частично
   ORD_NONE_EXPIRED          = 4, //Ордера нет, удалён по сроку
   ORD_NONE_FILLED           = 5, //Ордера нет, исполнился полностью
   ORD_NONE_REJECTED         = 6, //Ордера нет, отклонён брокером(биржей)
   ORD_BUSY                  = 7, //Ордер находится в переходном состоянии
   ORD_EXIST                 = 8, //Ордер выставлен на биржу, возможны действия над ним
   ORD_EXIST_PARTIAL         = 9  //Ордер выставлен на биржу, частично исполнился, возможны действия над ним
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
struct ORDER_DATA
  {
   int               error_code;
   datetime          time_setup;
   ENUM_ORDER_TYPE   type;
   ENUM_ORDER_STATE  state;
   ENUM_ORD_REAL_STATE real_state;
   datetime          expiration;
   datetime          time_done;
   long              t_set_msc;
   long              t_done_msc;
   ENUM_ORDER_TYPE_FILLING type_filling;
   ENUM_ORDER_TYPE_TIME type_time;
   long              magic;
   long              pos_id;
   double            vol_init;
   double            vol_cur;
   double            price_open;
   double            sl;
   double            tp;
   double            price_cur;
   double            price_stlim;
   string            symbol;
   string            comment;
  };
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   order_ticket=0;
   tr_cnt=0;
   start=0;
   stop=0;
   exp_busy=false;
   Print("Тест начат: ",TimeTradeServer());
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   ORDER_DATA order_data;
   if(!exp_busy)
     {
      if(tr_cnt>=Transactions)
        {
         if((order_ticket>0) && (OrderRealSelect(order_ticket,order_data,false)==SELECT_TRUE)) RemoveOrder(order_ticket);
         Print("Тест закончен: ",TimeTradeServer());
        }
      else
        {
         if(order_ticket>0)
           {
            if(OrderRealSelect(order_ticket,order_data,false)==SELECT_TRUE) RemoveOrder(order_ticket);
           }
         else
           {
            SetOrder();
           }
        }
     }
  }
//+------------------------------------------------------------------+
//| TradeTransaction function                                        |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction &trans,
                        const MqlTradeRequest &request,
                        const MqlTradeResult &result)
  {
   switch(trans.type)
     {
      case TRADE_TRANSACTION_REQUEST: if((order_id!=0) && (result.request_id==order_id))
        {
         order_ticket=result.order;
         order_id=0;
        }
      break;
      case TRADE_TRANSACTION_ORDER_UPDATE:  if((order_ticket!=0) && (trans.order==order_ticket))
        {
         ORDER_DATA order_data;
         if(OrderRealSelect(order_ticket,order_data,false)==SELECT_TRUE)
           {
            stop=GetMicrosecondCount();
            tr_cnt++;
            Print("Время установки ордера: ",NormalizeDouble(double(stop-start)/1000,2)," ms");
            Sleep(1000);
            exp_busy=false;
           }
        }
      break;
      case TRADE_TRANSACTION_HISTORY_ADD: if((order_ticket!=0) && (trans.order==order_ticket))
        {
         ORDER_DATA order_data;
         if(OrderRealSelect(order_ticket,order_data,false)==SELECT_FALSE)
           {
            stop=GetMicrosecondCount();
            tr_cnt++;
            order_ticket=0;
            Print("Время удаления ордера: ",NormalizeDouble(double(stop-start)/1000,2)," ms");
            Sleep(1000);
            exp_busy=false;
           }
        }
      break;
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void SetOrder()
  {
   MqlTradeRequest request={0};
   MqlTradeResult  result={0};
   order_id=0;
   order_ticket=0;
   request.magic=Magic;
   request.symbol=Symbol();
   request.volume=1;
   request.type_filling=ORDER_FILLING_RETURN;
   request.type_time=ORDER_TIME_DAY;
   request.action=TRADE_ACTION_PENDING;
   request.type=ORDER_TYPE_SELL_LIMIT;
   request.comment="";
   request.price=SymbolInfoDouble(Symbol(),SYMBOL_SESSION_PRICE_LIMIT_MAX);
   if(OrderSendAsync(request,result))
     {
      if(result.retcode==TRADE_RETCODE_PLACED)
        {
         order_id=result.request_id;start=GetMicrosecondCount();exp_busy=true;
         Print("Запрос на установку ордера.");
        }
     }
   else
     {Print("Ордер не отослан!");}
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void RemoveOrder(const ulong o_ticket)
  {
   MqlTradeRequest request={0};
   MqlTradeResult  result={0};
   order_id=0;
   request.action=TRADE_ACTION_REMOVE;
   request.order=o_ticket;
   if(OrderSendAsync(request,result))
     {
      if(result.retcode==TRADE_RETCODE_PLACED)
        {
         order_id=result.request_id;start=GetMicrosecondCount();exp_busy=true;
         Print("Запрос на удаление ордера.");
        }
     }
   else
     {Print("Ордер не отослан!");}
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
ENUM_ORD_SELECT OrderRealSelect(const ulong ticket,ORDER_DATA &ord_data,const bool get_data) //Отличная функция, спасибо Михаилу
  {
   double init_vol= 0;
   double cur_vol = 0;
   ZeroMemory(ord_data);
   ord_data.real_state = ORD_NOT_SPECIFIED;
   ord_data.error_code = ERR_SUCCESS;
   ResetLastError();
//---  
   if(ticket>0)
     {
      if(HistoryOrderSelect(ticket))
        {
         if(get_data)
           {
            ord_data.comment=HistoryOrderGetString(ticket,ORDER_COMMENT);
            ord_data.expiration=datetime(HistoryOrderGetInteger(ticket,ORDER_TIME_EXPIRATION));
            ord_data.magic=HistoryOrderGetInteger(ticket,ORDER_MAGIC);
            ord_data.pos_id=HistoryOrderGetInteger(ticket,ORDER_POSITION_ID);
            ord_data.price_cur=HistoryOrderGetDouble(ticket,ORDER_PRICE_CURRENT);
            ord_data.price_open=HistoryOrderGetDouble(ticket,ORDER_PRICE_OPEN);
            ord_data.price_stlim=HistoryOrderGetDouble(ticket,ORDER_PRICE_STOPLIMIT);
            ord_data.sl=HistoryOrderGetDouble(ticket,ORDER_SL);
            ord_data.state=ENUM_ORDER_STATE(HistoryOrderGetInteger(ticket,ORDER_STATE));
            ord_data.symbol=HistoryOrderGetString(ticket,ORDER_SYMBOL);
            ord_data.t_done_msc=datetime(HistoryOrderGetInteger(ticket,ORDER_TIME_DONE_MSC));
            ord_data.t_set_msc =datetime( HistoryOrderGetInteger(ticket, ORDER_TIME_SETUP_MSC));
            ord_data.time_done =datetime( HistoryOrderGetInteger( ticket, ORDER_TIME_DONE));
            ord_data.time_setup=datetime(HistoryOrderGetInteger(ticket,ORDER_TIME_SETUP));
            ord_data.tp=HistoryOrderGetDouble(ticket,ORDER_TP);
            ord_data.type=ENUM_ORDER_TYPE(HistoryOrderGetInteger(ticket,ORDER_TYPE));
            ord_data.type_filling=ENUM_ORDER_TYPE_FILLING(HistoryOrderGetInteger(ticket,ORDER_TYPE_FILLING));
            ord_data.type_time=ENUM_ORDER_TYPE_TIME(HistoryOrderGetInteger(ticket,ORDER_TYPE_TIME));
            ord_data.vol_cur=HistoryOrderGetDouble(ticket,ORDER_VOLUME_CURRENT);
            ord_data.vol_init=HistoryOrderGetDouble(ticket,ORDER_VOLUME_INITIAL);
           }
         else
           {
            ord_data.state=ENUM_ORDER_STATE(HistoryOrderGetInteger(ticket,ORDER_STATE));
            cur_vol=HistoryOrderGetDouble(ticket,ORDER_VOLUME_CURRENT);
            init_vol=HistoryOrderGetDouble(ticket,ORDER_VOLUME_INITIAL);
           }
         //---
         switch(ord_data.state)
           {
            case ORDER_STATE_CANCELED: if(get_data)
              {
               if(ord_data.vol_init==ord_data.vol_cur)
                 {
                  ord_data.real_state=ORD_NONE_CANCELED;
                 }
               else
                 {
                  ord_data.real_state=ORD_NONE_PARTIAL_CANCELED;
                 }
              }
            else
              {
               if(init_vol==cur_vol)
                 {
                  ord_data.real_state=ORD_NONE_CANCELED;
                 }
               else
                 {
                  ord_data.real_state=ORD_NONE_PARTIAL_CANCELED;
                 }
              }
            break;

            case ORDER_STATE_PARTIAL:  ord_data.real_state=ORD_NONE_PARTIAL;
            break;

            case ORDER_STATE_EXPIRED:  ord_data.real_state=ORD_NONE_EXPIRED;
            break;

            case ORDER_STATE_FILLED:   ord_data.real_state=ORD_NONE_FILLED;
            break;

            case ORDER_STATE_REJECTED: ord_data.real_state=ORD_NONE_REJECTED;
            break;
           }
        }
      else
      if(OrderSelect(ticket))
        {
         if(get_data)
           {
            ord_data.comment=OrderGetString(ORDER_COMMENT);
            ord_data.expiration=datetime(OrderGetInteger(ORDER_TIME_EXPIRATION));
            ord_data.magic=OrderGetInteger(ORDER_MAGIC);
            ord_data.pos_id=OrderGetInteger(ORDER_POSITION_ID);
            ord_data.price_cur=OrderGetDouble(ORDER_PRICE_CURRENT);
            ord_data.price_open=OrderGetDouble(ORDER_PRICE_OPEN);
            ord_data.price_stlim=OrderGetDouble(ORDER_PRICE_STOPLIMIT);
            ord_data.sl=OrderGetDouble(ORDER_SL);
            ord_data.state=ENUM_ORDER_STATE(OrderGetInteger(ORDER_STATE));
            ord_data.symbol=OrderGetString(ORDER_SYMBOL);
            ord_data.t_done_msc=datetime(OrderGetInteger(ORDER_TIME_DONE_MSC));
            ord_data.t_set_msc =datetime( OrderGetInteger(ORDER_TIME_SETUP_MSC));
            ord_data.time_done =datetime( OrderGetInteger(ORDER_TIME_DONE ));
            ord_data.time_setup=datetime(OrderGetInteger(ORDER_TIME_SETUP));
            ord_data.tp=OrderGetDouble(ORDER_TP);
            ord_data.type=ENUM_ORDER_TYPE(OrderGetInteger(ORDER_TYPE));
            ord_data.type_filling=ENUM_ORDER_TYPE_FILLING(OrderGetInteger(ORDER_TYPE_FILLING));
            ord_data.type_time=ENUM_ORDER_TYPE_TIME(OrderGetInteger(ORDER_TYPE_TIME));
            ord_data.vol_cur=OrderGetDouble(ORDER_VOLUME_CURRENT);
            ord_data.vol_init=OrderGetDouble(ORDER_VOLUME_INITIAL);
           }
         else
           {
            ord_data.state=ENUM_ORDER_STATE(OrderGetInteger(ORDER_STATE));
           }
         //--- 
         switch(ord_data.state)
           {
            case ORDER_STATE_STARTED:
            case ORDER_STATE_REQUEST_ADD:
            case ORDER_STATE_REQUEST_MODIFY:
            case ORDER_STATE_REQUEST_CANCEL: ord_data.real_state=ORD_BUSY;
            break;

            case ORDER_STATE_PARTIAL:        ord_data.real_state=ORD_EXIST_PARTIAL;
            break;

            case ORDER_STATE_PLACED:         ord_data.real_state=ORD_EXIST;
            break;
           }
        }
      else
        {
         ord_data.error_code=GetLastError();
        }
      //---   
      if(( ord_data.error_code!=ERR_SUCCESS) || 
         (ord_data.real_state==ORD_NOT_SPECIFIED))
        {
         return(SELECT_ERROR);
        }
      else
        {
         switch(ord_data.real_state)
           {
            case ORD_BUSY:          return(SELECT_BUSY);
            break;

            case ORD_EXIST:
            case ORD_EXIST_PARTIAL: return(SELECT_TRUE);
            break;

            default:                return(SELECT_FALSE);
            break;
           }
        }
     }
   else
     {
      ord_data.error_code=ERR_ZERO_TICKET;
      return(SELECT_ERROR);
     }
  }
//+------------------------------------------------------------------+
 

Тестирование производилось на реальном счёте брокера "0т", билд терминала 1375, на среднеликвидном инструменте SILV-9.16

За 1500 транзакций (~3 часа) выяснилось следущее:

Средняя скорость (за исключением очень редких задержек) составила ~22мс

Очень редкие задежки, доходившие чуть более 300 мс могут быть вызваны сетевыми соединениями.

Вероятно разработчики пофиксили багу.

Полные логи эксперта и терминала в подвале. 

Файлы:
MT-5.zip  76 kb
 

Кстати, посмотрел внимательно лог и иногда встречается следующее:

PN      0       16:44:22.973    Test_delay (SILV-9.16,M1)       Время удаления ордера: 91.84999999999999 ms

 Почему, ведь в коде прописано округлять до 2 знаков после запятой:

Print("Время удаления ордера: ",NormalizeDouble(double(stop-start)/1000,2)," ms");
 
prostotrader:

Кстати, посмотрел внимательно лог и иногда встречается следующее:

 Почему, ведь в коде прописано округлять до 2 знаков после запятой:

Для вывода на печать нужно использовать функцию преобразования double в string:

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   ulong  stop=123457;
   ulong  start=123400;
   for(int i=0;i<10;i++)
     {
      stop+=i;
      Print("Время удаления ордера, old: ",NormalizeDouble(double(stop-start)/1000,2)," ms",
            ", new: ",DoubleToString((double)(stop-start)/1000.0,2)," ms");
     }
  }

и вывод текста в "Экспертах":

2016.08.20 11:53:50.227 Test (EURUSD,D1)        Время удаления ордера, old: 0.06 ms, new: 0.06 ms
2016.08.20 11:53:50.227 Test (EURUSD,D1)        Время удаления ордера, old: 0.06 ms, new: 0.06 ms
2016.08.20 11:53:50.227 Test (EURUSD,D1)        Время удаления ордера, old: 0.06 ms, new: 0.06 ms
2016.08.20 11:53:50.227 Test (EURUSD,D1)        Время удаления ордера, old: 0.06 ms, new: 0.06 ms
2016.08.20 11:53:50.227 Test (EURUSD,D1)        Время удаления ордера, old: 0.07000000000000001 ms, new: 0.07 ms
2016.08.20 11:53:50.227 Test (EURUSD,D1)        Время удаления ордера, old: 0.07000000000000001 ms, new: 0.07 ms
2016.08.20 11:53:50.227 Test (EURUSD,D1)        Время удаления ордера, old: 0.08 ms, new: 0.08 ms
2016.08.20 11:53:50.227 Test (EURUSD,D1)        Время удаления ордера, old: 0.09 ms, new: 0.09 ms
2016.08.20 11:53:50.227 Test (EURUSD,D1)        Время удаления ордера, old: 0.09 ms, new: 0.09 ms
2016.08.20 11:53:50.227 Test (EURUSD,D1)        Время удаления ордера, old: 0.1 ms, new: 0.10 ms
 
подскажите, а ордер бай-стоп при открытии скользит на ФОРТС?
 
Евгений:
подскажите, а ордер бай-стоп при открытии скользит на ФОРТС?

Бай-стоп не выводится на биржу, а "дежурит" на сервере МТ5, следовательно,

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

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