В роботе АСК и БИД берутся не те

 

Добрый день.

Пишу робота для ФОРТСа и заметил что после открытия ордера прибыль оказывается положительной а робот этого не замечает или замечает через раз.

В чем может быть дело?

Заранее спасибо.

 Код:

   MqlTick last_tick;
   SymbolInfoTick(Symbol(),last_tick);
            double ask=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
         double bid=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);

///  
///BUY
   if(tradeResult==0)
      if(last_tick.last>=ask+interval)
        {
         MqlTradeRequest request={0};
         MqlTradeResult result={0};
         double spread = MathAbs(ask-bid);
         request.action=TRADE_ACTION_PENDING;         // setting a pending order
         request.magic=68975;                      // ORDER_MAGIC
         request.symbol=_Symbol;                   // symbol
         request.volume=Lots;                      // volume in 0.1 lots
         request.sl=ask-SlPips;        // Stop Loss is not specified
                                       //request.tp=NormalizeDouble(ask + TpPips * gTickSize, _Digits);        // Take Profit is not specified     
         request.type=ORDER_TYPE_BUY_LIMIT;              // order type
         request.price=ask;                        // open price
         request.type_filling=Filling;
         request.deviation=0;
         request.type_time=ORDER_TIME_DAY;
         request.expiration=0;
         //--- send a trade request
         int i=PositionsTotal();//Wait openedPosition 
         if(OrderSend(request,result))
           {
            while(i==PositionsTotal())//Wait openedPosition
              {
              }
            tradeResult=1;
            tradePrice=ask;
            LastPrice=last_tick.last;
           }
        }
///
///SELL
   if(tradeResult==0)
      if(last_tick.last<=bid-interval)
        {
         MqlTradeRequest request={0};
         MqlTradeResult result={0};
         request.action=TRADE_ACTION_PENDING;         // setting a pending order
         request.magic=68975;                      // ORDER_MAGIC
         request.symbol=_Symbol;                   // symbol
         request.volume=Lots;                      // volume in 0.1 lots
         request.sl=bid+SlPips;        // Stop Loss is not specified
                                       //request.tp=NormalizeDouble(bid - TpPips * gTickSize, _Digits);        // Take Profit is not specified     
         request.type=ORDER_TYPE_SELL_LIMIT;             // order type
         request.price=bid;                        // open price
         request.type_filling=Filling;
         request.deviation=0;
         request.type_time=ORDER_TIME_DAY;
         request.expiration=0;            //--- send a trade request
         int i=PositionsTotal();//Wait openedPosition
         if(OrderSend(request,result))
           {
            while(i==PositionsTotal())//Wait openedPosition
              {
              }
            tradeResult=2;
            tradePrice=bid;
            LastPrice=last_tick.last;
           }
        }
///ClosePosition
   if(tradeResult==2) ///if SELL position
      if(((LastPrice>=ask || LastPrice>=bid) && (tradePrice>=ask)) || (tradePrice>ask))
        {
         CTrade trade;
         trade.SetTypeFilling(Filling);
         int i=PositionsTotal()-1;
         while(i>=0)
           {
            if(trade.PositionClose(_Symbol)) i--;
           }
         tradeResult=0;
        }

   if(tradeResult==1) ///if BUY position
      if(((LastPrice<=bid || LastPrice<=ask) && (tradePrice<=bid)) || (tradePrice<bid))
        {
         CTrade trade;
         trade.SetTypeFilling(Filling);
         int i=PositionsTotal()-1;
         while(i>=0)
           {
            if(trade.PositionClose(_Symbol)) i--;
           }
         tradeResult=0;
        }
///
///PositionSL
   if(tradeResult!=0)
      if(!PositionSelect(_Symbol))
         tradeResult=0;
///
 

Проблема не в значениях Bid и Ask. Скорее всего, дело в значениях переменных tradeResult, LastPrice и tradePrice. Из приведенного кода не понятно, как организуется преемственность значений этих переменных от одного тика к другому.

Кроме того, как-то странно происходит закрытие:

         int i=PositionsTotal()-1;
         while(i>=0)
           {
            if(trade.PositionClose(_Symbol)) i--;
           }
         tradeResult=0;

То есть перебираются все позиции, но, вне зависимости от того, по какому они символу, закрывается позиция по текущему символу. Потом, не проверяя успешность закрытия позиции, происходит сброс флага tradeResult. Значит, если с первого раза закрыть позицию не удалось, то больше попыток произведено не будет.

P. S. Зачем нужно дублирование условий?

tradePrice<=bid || tradePrice<bid

 Ведь первое условие включает в себя второе. То же самое с Ask.

 
Игорь Герасько:

Проблема не в значениях Bid и Ask. Скорее всего, дело в значениях переменных tradeResult, LastPrice и tradePrice. Из приведенного кода не понятно, как организуется преемственность значений этих переменных от одного тика к другому.

P. S. Зачем нужно дублирование условий?

 Ведь первое условие включает в себя второе. То же самое с Ask.

Это весь код который выполняется в void OnTick().

Повторение условия нужно для того чтобы к последней цене подошла текущая цена и робот закрылся бы в плюсе. А второе условие нужно для того чтобы Робот закрылся в плюсе в любом другом случае - обычно это происходит через один тик.

По моему условия разные так как с начало выполняется условие в больших скобках.  

 

Прошу прощения не тот ког.

Вот тот:

//+------------------------------------------------------------------+
//|                                                    LastPrice.mq5 |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
input int interval=100;  //Мин. отклонение цены сделки
input double Lots=1;   //Лот
input int SlPips=100;   //Stop Loss
input ENUM_ORDER_TYPE_FILLING Filling=ORDER_FILLING_RETURN;  //Режим заполнения ордера
#include <trade/trade.mqh>
int tradeResult=0;
double tradePrice=0,LastPrice=0;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
///GetPrice
   MqlTick last_tick;
   SymbolInfoTick(Symbol(),last_tick);
            double ask=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
         double bid=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);

///  
///BUY
   if(tradeResult==0)
      if(last_tick.last>=ask+interval)
        {
         MqlTradeRequest request={0};
         MqlTradeResult result={0};
         double spread = MathAbs(ask-bid);
         request.action=TRADE_ACTION_PENDING;         // setting a pending order
         request.magic=68975;                      // ORDER_MAGIC
         request.symbol=_Symbol;                   // symbol
         request.volume=Lots;                      // volume in 0.1 lots
         request.sl=ask-SlPips;        // Stop Loss is not specified
                                       //request.tp=NormalizeDouble(ask + TpPips * gTickSize, _Digits);        // Take Profit is not specified     
         request.type=ORDER_TYPE_BUY_LIMIT;              // order type
         request.price=ask;                        // open price
         request.type_filling=Filling;
         request.deviation=0;
         request.type_time=ORDER_TIME_DAY;
         request.expiration=0;
         //--- send a trade request
         int i=PositionsTotal();//Wait openedPosition 
         if(OrderSend(request,result))
           {
            while(i==PositionsTotal())//Wait openedPosition
              {
              }
            tradeResult=1;
            tradePrice=ask;
            LastPrice=last_tick.last;
           }
        }
///
///SELL
   if(tradeResult==0)
      if(last_tick.last<=bid-interval)
        {
         MqlTradeRequest request={0};
         MqlTradeResult result={0};
         request.action=TRADE_ACTION_PENDING;         // setting a pending order
         request.magic=68975;                      // ORDER_MAGIC
         request.symbol=_Symbol;                   // symbol
         request.volume=Lots;                      // volume in 0.1 lots
         request.sl=bid+SlPips;        // Stop Loss is not specified
                                       //request.tp=NormalizeDouble(bid - TpPips * gTickSize, _Digits);        // Take Profit is not specified     
         request.type=ORDER_TYPE_SELL_LIMIT;             // order type
         request.price=bid;                        // open price
         request.type_filling=Filling;
         request.deviation=0;
         request.type_time=ORDER_TIME_DAY;
         request.expiration=0;            //--- send a trade request
         int i=PositionsTotal();//Wait openedPosition
         if(OrderSend(request,result))
           {
            while(i==PositionsTotal())//Wait openedPosition
              {
              }
            tradeResult=2;
            tradePrice=bid;
            LastPrice=last_tick.last;
           }
        }
///ClosePosition
   if(tradeResult==2) ///if SELL position
      if(((LastPrice>=ask || LastPrice>=bid) && (tradePrice>=ask)) || (tradePrice>ask))
        {
         CTrade trade;
         trade.SetTypeFilling(Filling);
         int i=PositionsTotal()-1;
         while(i>=0)
           {
            if(trade.PositionClose(_Symbol)) i--;
           }
         tradeResult=0;
        }

   if(tradeResult==1) ///if BUY position
      if(((LastPrice<=bid || LastPrice<=ask) && (tradePrice<=bid)) || (tradePrice<bid))
        {
         CTrade trade;
         trade.SetTypeFilling(Filling);
         int i=PositionsTotal()-1;
         while(i>=0)
           {
            if(trade.PositionClose(_Symbol)) i--;
           }
         tradeResult=0;
        }
///
///PositionSL
   if(tradeResult!=0)
      if(!PositionSelect(_Symbol))
         tradeResult=0;
///
  }
//+------------------------------------------------------------------+
 
Alexander Pavlov:

Это весь код который выполняется в void OnTick().

Повторение условия нужно для того чтобы к последней цене подошла текущая цена и робот закрылся бы в плюсе. А второе условие нужно для того чтобы Робот закрылся в плюсе в любом другом случае - обычно это происходит через один тик.

По моему условия разные так как с начало выполняется условие в больших скобках.  

А, там две скобки после bid. Не заметил, слились в одну
 
Alexander Pavlov:

Прошу прощения не тот ког.

Вот тот:

Суть не меняется. В коде нет обработки случаев, когда закрытие позиции закончилось неудачно. Но несмотря на это, советник продолжает оперировать значением tradeResult = 0, т. е. считает, что позиции уже нет.

Вместо tradeResult лучше использовать проверку типа существующей позиции. А уже потом, определив тип, пытаться закрывать. Кроме того, нужно учесть, что метод trade.PositionClose всего лишь отсылает торговый приказ. Нужно еще дождаться результатов его выполнения, а то будете бомбить сервер приказами на закрытие между отправкой приказа и приходом результата.

 

Зачем Вы ещё раз берёте

double ask=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
         double bid=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);

 Если в структуре MqlTick уже есть эти данные?

struct MqlTick
  {
   datetime     time;          // Время последнего обновления цен
   double       bid;           // Текущая цена Bid
   double       ask;           // Текущая цена Ask
   double       last;          // Текущая цена последней сделки (Last)
   ulong        volume;        // Объем для текущей цены Last
  };

 А это

if(last_tick.last>=ask+interval)

 Ни "в какие ворота"!

last - double, ask -double,  а interval - int !!! 

Не используйте для ФОРТС  стандартную библиотеку.

И на ФОРТС лучше использовать стаканы, нежели OnTick() 

 Вот "рыба":

//+------------------------------------------------------------------+
//|                                                    LastPrice.mq5 |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"
//
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
  if ( !MarketBookAdd( _Symbol ) )   
  {
    MessageBox( "Не добавлен стакан по символу " + _Symbol );
    return( INIT_FAILED );
  }
  return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
  MarketBookRelease( _Symbol );     
}
//+------------------------------------------------------------------+
//| Get Stakan values function                                       |
//+------------------------------------------------------------------+ 
bool GetStakanValues( const string aSymbol, double &ask, double &bid )
{
  MqlBookInfo book_price[];
  bid = 0;
  ask = DBL_MAX;
  
//--- Get stakan
  if ( MarketBookGet( aSymbol, book_price ) )
  {
    int size = ArraySize( book_price );
//---    
    if ( size > 0 )
    { 
      for( int i = 0; i < size; i++ )
      {
        if ( book_price[i].type == BOOK_TYPE_SELL )
        {
          if ( book_price[i].price < ask )
          {
            ask = book_price[i].price;
          }
        }
        else
        if ( book_price[i].type == BOOK_TYPE_BUY )
        {
          bid = book_price[i].price;
          return( true );
        }
      }
    }
  }
//---
  if ( ask == DBL_MAX ) ask = 0;
  return( false);
}
//+------------------------------------------------------------------+
//| BookEvent function                                               |
//+------------------------------------------------------------------+
void OnBookEvent(const string &symbol)
{
  if ( symbol == _Symbol )
  {
    if ( PositionSelect( _Symbol ) )
    {
      //---
    }
    else
    {
      double ask, bid;
//---      
      if ( GetStakanValues( _Symbol, ask, bid ) )
      {
        //---
      }
    }
  }   
}
//+------------------------------------------------------------------+

 

 

 
Михаил:

Зачем Вы ещё раз берёте

 Если в структуре MqlTick уже есть эти данные?

 А это

 Ни "в какие ворота"!

last - double, ask -double,  а interval - int !!! 

Не используйте для ФОРТС  стандартную библиотеку.

И на ФОРТС лучше использовать стаканы, нежели OnTick() 

 Вот "рыба":

 

 

Я подумал что АСК и БИД таким образом возьмутся правильно, т.е. все значения которые идут на графике.

Спасибо за бук попробую разобраться.

Да кстати в другом брокере вроде позу сразу закрывает.  

 
Игорь Герасько:

Суть не меняется. В коде нет обработки случаев, когда закрытие позиции закончилось неудачно. Но несмотря на это, советник продолжает оперировать значением tradeResult = 0, т. е. считает, что позиции уже нет.

Вместо tradeResult лучше использовать проверку типа существующей позиции. А уже потом, определив тип, пытаться закрывать. Кроме того, нужно учесть, что метод trade.PositionClose всего лишь отсылает торговый приказ. Нужно еще дождаться результатов его выполнения, а то будете бомбить сервер приказами на закрытие между отправкой приказа и приходом результата.

Так вроде есть цикл где проверяется условие на закрытие позиции - про который Вы ранее говорили.

Я кроме PositionSelect и копаться в истории сделок никаких проверок не знаю. Как то крутил PositionSelect в цикле и через пол дня он дал сбой. Может есть альтернатива попроще хистори? 

 
Alexander Pavlov:

Так вроде есть цикл где проверяется условие на закрытие позиции - про который Вы ранее говорили.

Я кроме PositionSelect и копаться в истории сделок никаких проверок не знаю. Как то крутил PositionSelect в цикле и через пол дня он дал сбой. Может есть альтернатива попроще хистори? 

Зачем крутить PositionSelect в цикле? Если нужно следить только за текущим символом, то достаточно:

if (PositionSelect(_Symbol))
{
   // Есть позиция по символу - аналог tradeResult != 0
   if (OrderGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
   {
       // Длинная позиция, аналог tradeResult = 1
   }
   else
   {
       // Короткая позиция, аналог tradeResult = 2
   }
}

Это верный способ существования позиции. Но еще нужно обдумать, как действовать после отсылки запроса о закрытии позиции, чтобы не отправлять новые приказы закрытия, пока не придет ответ от сервера. Смотрите в сторону OnTrade() и OnTradeTransaction().

 
Игорь Герасько:

Зачем крутить PositionSelect в цикле? Если нужно следить только за текущим символом, то достаточно:

Это верный способ существования позиции. Но еще нужно обдумать, как действовать после отсылки запроса о закрытии позиции, чтобы не отправлять новые приказы закрытия, пока не придет ответ от сервера. Смотрите в сторону OnTrade() и OnTradeTransaction().

Спасибо. Но сейчас меня беспокоит то что при открытии позиции ордер иногда висит очень долго. Как бы его кикнуть на следующем тике?
Причина обращения: