Особенности языка mql5, тонкости и приёмы работы - страница 208

 
mktr8591:

Видимо, я неправильно понял торговую ситуацию.

Как я представлял: отложенный лимитник исполнялся несколькими сделками. Все это время он висел в живых ордерах, и поле ORDER_TIME_SETUP   не было константой. После крайней сделки он попал в историю. В этот момент ORDER_TIME_SETUP стало константой.

Или было не так?

ORDER_TIME_SETUP - всегда константа. Когда попал в историю - появился ORDER_TIME_DONE.

 
fxsaber:

ORDER_TIME_SETUP - всегда константа. Когда попал в историю - появился ORDER_TIME_DONE.

Вот я сейчас выставляю отложенный лимитник. Затем меняю его руками и скриптом  и  ORDER_TIME_SETUP изменяется.

Что я неправильно делаю?

 

В прошлом вы уже постили про похожие случаи:

https://www.mql5.com/ru/forum/170952/page170#comment_15824249

https://www.mql5.com/ru/forum/170952/page172#comment_15829154

Особенности языка mql5, тонкости и приёмы работы
Особенности языка mql5, тонкости и приёмы работы
  • 2020.04.09
  • www.mql5.com
В данной теме будут обсуждаться недокументированные приёмы работы с языком mql5, примеры решения тех, или иных задач...
 
mktr8591:

Вот я сейчас выставляю отложенный лимитник. Затем меняю его руками и скриптом  и  ORDER_TIME_SETUP изменяется.

Что я неправильно делаю?

Так не меняется время выставления.

 
mktr8591:

В прошлом вы уже постили про похожие случаи:

https://www.mql5.com/ru/forum/170952/page170#comment_15824249

https://www.mql5.com/ru/forum/170952/page172#comment_15829154

Действительно, постил. Но напрочь не помнил. Думаю, что это баг.


fxsaber:

Что будет при повторном частичном исполнении - не знаю.

Теперь знаю - у данного брокера (склоняюсь в ошибке в их софте) не изменится больше.

 
// Возвращает снепшот котирования символа.
int QuotesSnapshot( const string Symb = NULL, const datetime From = 0 )
{    
  int Snapshot = INT_MAX;

  MqlTick Ticks[];
  
#define DAY (24 * 3600)  
  const int Size = CopyTicksRange(Symb, Ticks, COPY_TICKS_INFO, From ? From * 1000 : SymbolInfoInteger(Symb, SYMBOL_TIME) / DAY * DAY * 1000);
#undef DAY  
  
  for (int i = 1; i < Size; i++)
  {
    const int Interval = (int)(Ticks[i].time_msc - Ticks[i - 1].time_msc);
    
    if (Interval < Snapshot)
      Snapshot = Interval;
  }
  
  return(Snapshot);
}

Иногда полезно знать, как часто транслируются тики.

 

CloseBy-операция порождает две сделки. Своп первой (первая позиция в CloseBy) сделки содержит сумму свопов обеих позиций. Своп второй сделки нулевой.

Если сделать частичное закрытие позиции через CloseBy, то оставшаяся часть открытой позиции лишается свопа - обнуляется.


// Демонстрация работы со свопами во время частичного закрытия через CloseBy.

#define REPORT_TESTER             // В тестере будут автоматически записываться отчеты
#define REPORT_BROWSER            // Создание отчета с запуском браузера - требует разрешения DLL.
#include <Report.mqh> // https://www.mql5.com/ru/code/18801

#define Ask SymbolInfoDouble(_Symbol, SYMBOL_ASK)

void OnTick()
{
  static bool FirstRun = true;
  
  if (FirstRun)
  {
    if (!OrderSelect(0, SELECT_BY_POS))
      FirstRun = OrderSend(_Symbol, OP_BUY, 100, Ask, 0, 0, 0);
    else if (OrderSwap())
    {
      const TICKET_TYPE Ticket = OrderTicket();
      
//      FirstRun = !(OrderCloseBy(OrderSend(_Symbol, OP_SELL, 0.01, OrderClosePrice(),0, 0, 0), Ticket) &&
      FirstRun = !(OrderCloseBy(Ticket, OrderSend(_Symbol, OP_SELL, 0.01, OrderClosePrice(),0, 0, 0)) &&
                   OrderSelect(0, SELECT_BY_POS) && OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 0));      
    }    
  }    
}


Результат.


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

 

Вычисление количества ролловеров (не самый быстрый вариант).

#define DAY  (24 * 3600)
#define WEEK (DAY * 7)

// Возврящает количество "четвергов" между двумя датами.
int GetAmountWeekDay( const datetime Begin, const datetime End, const int DayWeek = -1 )
{
  const datetime OffsetTime = (DayWeek - WEDNESDAY) * DAY;
  
  return((DayWeek != -1) ? (int)((End - OffsetTime) / WEEK - (Begin - OffsetTime) / WEEK) : 0);
}

// Возврящает количество рабочих дней между двумя датами.
int GetAmountWorkingDays( const datetime Begin, const datetime End )
{
  const int Res = (int)(End / DAY - Begin / DAY);
  
  return(Res ? Res - GetAmountWeekDay(Begin, End, SATURDAY) - GetAmountWeekDay(Begin, End, SUNDAY) : 0);
}

// Возвращает количество ролловеров (включая тройные) между двумя датами.
int GetRolloverAmounts( datetime TimeOpen, datetime TimeClose,
                        datetime RolloverTime = 0, const int Rollover3Days = WEDNESDAY )
{
  RolloverTime = RolloverTime % DAY;
  
  TimeOpen -= RolloverTime;
  TimeClose -= RolloverTime;
  
  const int Res = GetAmountWorkingDays(TimeOpen, TimeClose);
  
  return(Res ? Res + (GetAmountWeekDay(TimeOpen, TimeClose, Rollover3Days) << 1) : 0);
}

#undef WEEK
#undef DAY


Пример использования.

// Сравниваем реальные и вычисленные значения свопов.

#include <MT4Orders.mqh>

input datetime inRolloverTime = 0; // Время ролловера
input int inCount = 100; // Маскимальное количество распечаток

// Вычисляет своп закрытой позиции.
double CalcOrderSwap( const datetime RolloverTime = 0 )
{
  return(((OrderType() <= OP_SELL) &&
          (SymbolInfoInteger(OrderSymbol(), SYMBOL_SWAP_MODE) == SYMBOL_SWAP_MODE_POINTS))
             // https://www.mql5.com/ru/forum/170952/page208#comment_24667438
           ? GetRolloverAmounts(OrderOpenTime(), OrderCloseTime(), RolloverTime,
             (int)SymbolInfoInteger(OrderSymbol(), SYMBOL_SWAP_ROLLOVER3DAYS)) *
             SymbolInfoDouble(OrderSymbol(), OrderType() ? SYMBOL_SWAP_SHORT : SYMBOL_SWAP_LONG) *
             SymbolInfoDouble(OrderSymbol(), SYMBOL_TRADE_TICK_VALUE) *
             OrderLots()
           : 0);
}

#define TOSTRING(A) " " + #A + " = " + (string)(A)

void OnStart()
{  
  for (int i = OrdersHistoryTotal() - 1, Count = 0; (i >= 0) && (Count < inCount); i--)
    if (OrderSelect(i, SELECT_BY_POS, MODE_HISTORY) && OrderSwap())
    {
      OrderPrint();
      Print((string)Count++ + TOSTRING(OrderSwap()) + TOSTRING(CalcOrderSwap(inRolloverTime)) + "\n");
    }
}


Результат.

#2122237 2021.09.09 23:09:15.512 sell 0.18 GBPCAD 1.75119 0.00000 1.75286 2021.09.10 04:27:40.506 1.75286 -0.84 -0.80 -20.07 7;[0] 7
97 OrderSwap() = -0.8 CalcOrderSwap(inRolloverTime) = -0.8048844238618312
 
fxsaber #:

CloseBy-операция порождает две сделки. Своп первой (первая позиция в CloseBy) сделки содержит сумму свопов обеих позиций. Своп второй сделки нулевой.

Если сделать частичное закрытие позиции через CloseBy, то оставшаяся часть открытой позиции лишается свопа - обнуляется.

...

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

Удивительно!

Неужели, из-за округления (чтобы не потерялся или не добавился цент)?

Или просто редко используемая операция, поэтому не важно?

 
Andrey Khatimlianskii #:

Удивительно!

Неужели, из-за округления (чтобы не потерялся или не добавился цент)?

Точно не в этом дело, т.к. при частичном закрытии (OrderClose не на полный OrderLots) своп дербанится соответствующим образом.

Или просто редко используемая операция, поэтому не важно?

Думаю, сильно не продумывали сценарии.

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