Не корректная работа с структурами базовых функций

 

Есть структура:

struct Position_Properties
{
   string      sInstrument;       // Символ торгового инструмента
   int         iType;             // Тип торговой операции
   int         iCurTicket;        // Тикет выбранного ордера
   double      dOpenPrice;        // Цена открытия
   double      dLots;             // Объём позиции на открытие
   double      dCurSL;            // Текущий Stop Loss выбранной позиции
   double      dCurTP;            // Текущий Take Profit выбранной позиции
   string      sComment;          // Комментарий
   int         iMagic;            // Магик
};

Для неё создан массив с некоторым запасом:

Position_Properties  SPos[100];

 В общем, ситуация такая:

До сих пор, в тестах то что писал, - работало. Но вчера столкнулся с косяком. И, судя по всему, не у меня в коде, а на стороне платформы. В метод удаления ордера попадает тикет, который почему-то функция удаления не "распознаёт". Почему?

Вот метод, где ошибка:

//=========================================================================================================================================
// 1.4 Функция удаляет выбранный отложенный ордер. ========================================================================================
int PositionsManipulations::fOrderDelete (Position_Properties& Pos,     // Структура свойств позиции
                                          color  fc_Arrow = CLR_NONE)   // Цвет стрелки на графике
{
   //---- Удаляем ТОЛЬКО отложенные ордера
   if (OrderType() < 2) return (false);
Print ("ТУТ");
   bool lb_InvalidSTOP = false;
//----
   if (fc_Arrow == CLR_NONE) fc_Arrow = ColorByClose [OrderType() % 2];

   //---- Производим удаление ордера в тестере
   if (!CBase.GetRealTrade())
   {
      if (!OrderDelete (Pos.iCurTicket, fc_Arrow))
      {
         Logging::WriteLog (StringConcatenate ("fOrderDelete(): ", CErrs.ErrorToString (_LastError)));
         return (SUCCESS);
      }
   }
   int    li_Cnt = 0;
   double ld_SL, ld_TP, ld_Price;
Print ("ТУТ_2");
   //---- Получаем актуальную информацию по символу и текущему ордеру
 //  CBase.GetMarkerInfo (Pos.sInstrument, Pos.iCurTicket);

   //---- Проверяем на условия FREEZELEVEL
   if (!CheckLevelsBLOCK (Pos, 1, ld_Price, ld_SL, ld_TP, lb_InvalidSTOP)) return (false);

   ResetLastError();

   //---- Производим удаление ордера в on-line торговле
   while (IsTradeAllowed() == true)
   {
      if (IsStopped() || li_Cnt > 200)
      {
         Logging::WriteLog (StringConcatenate ("Error: Trying to close ticket #", Pos.iCurTicket, ", which is ",GetNameOP (Pos.iType), " NOT IsTradeContextBusy"));

         return (false);
      }
Print ("Pos.iCurTicket = ", Pos.iCurTicket);
Print ("ТУТ_3");
      if (OrderDelete (Pos.iCurTicket, fc_Arrow))
      {
         Print ("Позиция закрыта");
         return (SUCCESS);
      }
      else
      {
         if (!CErrs.ErrorHandling (_LastError, lb_InvalidSTOP))
         {
            Logging::WriteLog (StringConcatenate ("Error Occured : ", CErrs.ErrorDescription (_LastError)));
            Logging::WriteLog (StringConcatenate ("fOrderDelete(): ", OrderSymbol(), "# ", Pos.iCurTicket, "/", GetNameOP (Pos.iType), " | Lots = ", DToSByLots (OrderLots())));
            
            li_Cnt++;
            
            if (NumberOfTry < li_Cnt) return (false);
         }
      }
   }

   //---- Контролируем возможные ошибки
   if (_LastError > 0)
       Logging::Printing (StringConcatenate ("ls_fName => ", CErrs.ErrorToString (_LastError)));
//----
   return (FAILURE);
}

 Вот лог, в котором видно, что до стандартной функции OrderDelete() всё принтуется исправно, а дальше, судя по логу тикет не читается функцией:

2015.08.16 09:38:31.412 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: unknown ticket 4 for OrderDelete function
2015.08.16 09:38:31.412 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: ТУТ_3
2015.08.16 09:38:31.412 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: Pos.iCurTicket = 4
2015.08.16 09:38:31.411 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: OrderDelete error 4108
2015.08.16 09:38:31.411 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: unknown ticket 4 for OrderDelete function
2015.08.16 09:38:31.411 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: ТУТ3
2015.08.16 09:38:31.411 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: Pos.iCurTicket = 4

 Возник вопрос. Почему тикет не опознан? Ведь в цикле перебора ордеров я выбираю его при помощи OrderSelect(), а значит данный ордер с данным тикетом присутствует. Номер тикета в принт возвразщается. Что ещё нужно?

 

Не много дополнил этот кусок из функции удаления:

Print ("Pos.iCurTicket = ", Pos.iCurTicket);
Print ("OrderTicket() = ", OrderTicket());
Print ("Pos.iType = ", Pos.iType);
Print ("OrderType() = ", OrderType());
Print ("Pos.dOpenPrice = ", Pos.dOpenPrice);
Print ("OrderOpenPrice() = ", OrderOpenPrice());
Print ("ТУТ_3");
      if (OrderDelete (Pos.iCurTicket, fc_Arrow))
      {
         Print ("Позиция закрыта");
         return (SUCCESS);
      }

 Вот что имеем:

2015.08.16 10:29:53.750 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: OrderDelete error 4108
2015.08.16 10:29:53.750 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: unknown ticket 4 for OrderDelete function
2015.08.16 10:29:53.750 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: ÒÓÒ_3
2015.08.16 10:29:53.750 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: OrderOpenPrice() = 1.09155
2015.08.16 10:29:53.750 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: Pos.dOpenPrice = 1.09155
2015.08.16 10:29:53.750 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: OrderType() = 5
2015.08.16 10:29:53.750 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: Pos.iType = 5
2015.08.16 10:29:53.750 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: OrderTicket() = 4
2015.08.16 10:29:53.750 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: Pos.iCurTicket = 4
2015.08.16 10:29:53.749 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: OrderDelete error 4108
2015.08.16 10:29:53.749 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: unknown ticket 4 for OrderDelete function
2015.08.16 10:29:53.749 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: ÒÓÒ_3
2015.08.16 10:29:53.749 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: OrderOpenPrice() = 1.09155
2015.08.16 10:29:53.749 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: Pos.dOpenPrice = 1.09155
2015.08.16 10:29:53.749 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: OrderType() = 5
2015.08.16 10:29:53.749 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: Pos.iType = 5
2015.08.16 10:29:53.749 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: OrderTicket() = 4
2015.08.16 10:29:53.749 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: Pos.iCurTicket = 4

 Т.е. очевидно, что структура возвращает верные данные, такие же как и просто переменные позиций (OrderTicket(), OrderType(), OrderOpenPrice()). Ордер выбран! Иначе не возвратились бы данные. К тому же я их сразу же на уровне выше выбираю... Тут без вариантов. Почему его тогда не удалить? Проблема в чём? 

 

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

Когда выбор происходит по тикету, то для определения, какому списку он принадлежит, нужно проверять время закрытия:

if (OrderSelect(ticket, SELECT_BY_TICKET))
{
   if (OrderCloseTime() == 0)
   {
      // Ордер находится в списке рабочих ордеров
   }
   else
   {
      // Ордер находится в истории счета (удален или закрыт)
   } 
}
 
Scriptong:

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

Когда выбор происходит по тикету, то для определения, какому списку он принадлежит, нужно проверять время закрытия:


Так по ходу позиции не в истории. Вот переделал так в функции удаления ордеров:

Print ("Pos.iCurTicket = ", Pos.iCurTicket);
Print ("OrderTicket() = ", OrderTicket());
Print ("Pos.iType = ", Pos.iType);
Print ("OrderType() = ", OrderType());
Print ("Pos.dOpenPrice = ", Pos.dOpenPrice);
Print ("OrderOpenPrice() = ", OrderOpenPrice());
Print ("OrderCloseTime() = ", OrderCloseTime());
Print ("ТУТ_3");
      if (OrderDelete (Pos.iCurTicket, fc_Arrow))
      {
         Print ("Позиция закрыта");
         return (SUCCESS);
      }
      else

 Вот в журнале видим так:

2015.08.16 22:14:23.340 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: ТУТ_3
2015.08.16 22:14:23.340 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: OrderCloseTime() = 1970.01.01 00:00:00
2015.08.16 22:14:23.340 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: OrderOpenPrice() = 1.09155
2015.08.16 22:14:23.340 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: Pos.dOpenPrice = 1.09155
2015.08.16 22:14:23.340 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: OrderType() = 5
2015.08.16 22:14:23.340 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: Pos.iType = 5
2015.08.16 22:14:23.340 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: OrderTicket() = 4
2015.08.16 22:14:23.340 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: Pos.iCurTicket = 4
2015.08.16 22:14:23.340 2015.06.02 04:55  Tester: stop button pressed
2015.08.16 22:14:23.338 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: OrderDelete error 4108
2015.08.16 22:14:23.338 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: unknown ticket 4 for OrderDelete function
2015.08.16 22:14:23.338 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: ТУТ_3
2015.08.16 22:14:23.338 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: OrderCloseTime() = 1970.01.01 00:00:00
2015.08.16 22:14:23.338 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: OrderOpenPrice() = 1.09155
2015.08.16 22:14:23.338 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: Pos.dOpenPrice = 1.09155
2015.08.16 22:14:23.338 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: OrderType() = 5
2015.08.16 22:14:23.338 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: Pos.iType = 5
2015.08.16 22:14:23.338 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: OrderTicket() = 4
2015.08.16 22:14:23.338 2015.06.02 04:55  ZZBaseVariant EURUSD,M5: Pos.iCurTicket = 4
 

так у вас ордер не удалился, конечно он в открытых и сидит.

пишите обработку ошибок 

 

Все это, конечно, очень странно. Но проблема в том, что мы смотрим на ситуацию через замочную скважину - видим только некоторый кусочек информации, согласно которому все верно: ордер действительно отложенный (Sell Stop), его тикет 4 и он находится в списке рабочих ордеров. В этом свете непонятно, почему тестер выдает ошибку "неверный номер тикета".

Чтобы решить проблему, нужно увидеть всю предысторию (открытие ордеров), что можно сделать показав содержимое вкладки "Результаты", а также распечатав состояние текущего рыночного окружения (цены, стоплевелы, фризлевелы и прочее). 

 

В общем-то, действительно, там была не корректна одна функция. Я когда переписывал класс, кавычки сдвинул. Появилась другая проблема. Тут уже канкретно не понятно как решить её нормально.

В общем, есть структура:

struct Position_Properties
{
   string      sInstrument;       // Символ торгового инструмента
   int         iType;             // Тип торговой операции
   int         iCurTicket;        // Тикет выбранного ордера
   double      dOpenPrice;        // Цена открытия
   double      dLots;             // Объём позиции на открытие
   double      dCurSL;            // Текущий Stop Loss
   double      dCurTP;            // Текущий Take Profit
   double      dNewSL;            // Новый Stop Loss
   double      dNewTP;            // Новый Take Profit
   string      sComment;          // Комментарий
   int         iMagic;            // Магик
};

 Создаю экземпляр структуры.

Position_Properties  SPos[100];

 В метод TrailingByFixedValue() передаю структуру. Там пытаюсь модифицировать позицию вызывая метод fOrderModify (Pos, 0, Gold). Все данные о позиции переданные в метод fOrderModify (Pos, 0, Gold) корректны. Там возникает ошибка 130. В данном методе fOrderModify (Pos, 0, Gold) вызывается метод обработки ошибок на предмет некорректного стоплевела, в который я передаю экземпляр структуры:

bool PositionsManipulations::CheckValidStops (Position_Properties& Pos,        // Структура свойств позиции
                                              double   fd_Price,               // Текущая цена
                                              bool     fb_IsNewOrder = true)   // Открытие ордера
{
   Print (__FUNCTION__, ": Вошли в метод ");
   bool   lb_Result = true;
   double ld_OrigSL = Pos.dCurSL,
          ld_OrigTP = Pos.dCurTP;
   string lsa_Txt [2] = { "","" },
          ls_Symbol = Pos.sInstrument;
   
   if (!fb_IsNewOrder) ls_Symbol = OrderSymbol();
//----
   ResetLastError();

   //---- Если SL не 0
   if (Pos.dNewSL != 0.0)
   {
      Print (__FUNCTION__, ": Pos.dNewSL = ", Pos.dNewSL);
      if (Pos.iType % 2 == OP_BUY)
      {
         Pos.dNewSL = fd_Price - SSym.gi_StopLevel;
         Print (__FUNCTION__, ": Pos.dNewSL = ", Pos.dNewSL);
         lsa_Txt [0] = StringConcatenate (__FUNCTION__, ": SL = ", DToS (ld_OrigSL), " | new SL [", DToS (Pos.dNewSL), "] = price [", DToS (fd_Price),
                                          "] - MinSTOP [", IToS (SSym.gi_StopLevel), "]");

         if (fb_IsNewOrder)
         {
            Pos.dNewSL -= SSym.gd_Spread;
            lsa_Txt [1] = StringConcatenate (__FUNCTION__, ": Minus spread [", DToS (SSym.gd_Spread), "]");
         }
    
         Pos.dNewSL = MathMin (Pos.dCurSL, Pos.dNewSL);
            
         if (!fb_IsNewOrder)
         {
            if (OrderStopLoss() != 0.0)
            {
               if (ND (OrderStopLoss() - Pos.dCurSL) >= 0.0)
                   lb_Result = false;
            }
         }
      }
//--- остальная логика

 В методе CheckValidStops() получается корректное значение СТОПА. НО  с CheckValidStops() должны посредством структуры передацца данные в экземпляр. Тока вот по факту там оказываются значения 0.0 у СТОПА постоянно. Значение теряется. Почему? Его нельзя передавать несколько уровней  т.е. несколько методов вложенных друг в друга?

 
shanty:

Тока вот по факту там оказываются значения 0.0 у СТОПА постоянно. Значение теряется. Почему? Его нельзя передавать несколько уровней  т.е. несколько методов вложенных друг в друга?

Можно передавать и так, и эдак. Важно следить за тем, каким образом передаются данные. Возможно, где-то передается информация по значению, а не по ссылке. По приведенному коду на этот вопрос не ответить. Нужно видеть всю цепочку передачи данных: от глобального уровня до самого глубокого вложения.
 

Поля структуры dCurSL и dNewSL должны изменяться. То, что по факту в каком-то из них оказывается 0, говорит о неверном алгоритме или входных данных функции CheckValidStops. К примеру, значение fd_Price может быть равно нулю (ведь непонятно, что там возвращает CBase.GetTradePrice). 

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

Еще есть такие непонятные моменты, как:

if (ND (Pos.dCurSL - Pos.dCurSL) != 0.0)

 и 

if (ND (Pos.dCurTP - Pos.dCurSL) != 0.0)

 Код после этих условий ни при каких обстоятельствах не будет исполнен, т. к. эквивалентен такому коду:

if (1 != 1)
{
   // Никогда не исполнится
}

Попробуйте вывести в журнал выполнение функций пошагово и увидите, где же затирается значение стопа. 

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