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 就会改变。

我做错了什么?

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

我现在在这里设置一个延迟的限制器。然后,我手动和通过脚本改变它,ORDER_TIME_SETUP 就会改变。

我做错了什么?

它不会改变设定的时间。

 

的确,我有。但我完全记不起来了。我想这是一个错误。


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)会相应地消耗掉交换的资金。

还是说这只是一个很少使用的操作,所以并不重要?

我不认为有多少人考虑到了这些情况。