Библиотеки: MT4Orders QuickReport - страница 5

 
Forester #:

Сервер:  MetaQuotes-Demo Hedge
Сделка с тикетом 99 на второй странице.

Немного локализовал.

#include <MT4Orders.mqh>

void OnTick ()
{
  static int Count = 0;
  
  if (Count > 6)
    return;
  
  MqlTick Tick;
  SymbolInfoTick(_Symbol, Tick);
  
  const double Offset = 5 * _Point;
  bool Buy =  false;
  bool Sell =  false;

  for (uint i = OrdersTotal(); (bool)i--;)
    if (OrderSelect(i, SELECT_BY_POS))         
    {
      if(OrderMagicNumber())
        switch (OrderType())
        {
        case OP_BUY:
          OrderModify(OrderTicket(), OrderOpenPrice(), 0, Tick.bid + Offset, 0);
          Buy = true;
         
         break;
        case OP_SELL:
          OrderModify(OrderTicket(), OrderOpenPrice(), 0, Tick.ask - Offset, 0);
          Sell = true;
         
         break;
        case OP_BUYLIMIT:
          OrderModify(OrderTicket(), Tick.ask - Offset, 0, 0, 0);
          Buy = true;
         
         break;
        case OP_SELLLIMIT:          
          OrderModify(OrderTicket(), Tick.bid + Offset, 0, 0, 0);
          Sell = true;
         
         break;
        }
      else
        OrderDelete(OrderTicket());
    }

  if (!Buy)
    OrderSend(_Symbol, OP_BUYLIMIT, 1, Tick.ask - Offset, 0, 0, 0, NULL, ++Count);

  if (!Sell)
    OrderSend(_Symbol, OP_SELLLIMIT, 1, Tick.bid + Offset, 0, 0, 0, NULL, ++Count);
  
  OrderSend(_Symbol, OP_BUYLIMIT, 1,  Tick.ask - Offset, 0, Tick.ask - Offset, Tick.ask - Offset);
  Count++;
}

string TimeToString( const long Time )
{
  return((string)(datetime)(Time / 1000) + "." + IntegerToString(Time % 1000, 3, '0'));
}

void OnDeinit( const int )
{
  if (HistorySelect(0, INT_MAX))
    for (uint i = HistoryOrdersTotal(); (bool)i--;)
    {
      const ulong Ticket = HistoryOrderGetTicket(i);
      
      Print((string)i + ": " + (string)Ticket + " " + TimeToString(HistoryOrderGetInteger(Ticket, ORDER_TIME_DONE_MSC)));
    }
}


Неважно, что делает советник. Главное - выделенный код, который просто выводит MT5-ордера из истории торгов: место ордера, его тикет и время его попадания в историю.

11: 13 2023.05.29 23:54:39.425
10: 12 2023.05.29 00:04:25.870
 9: 11 2023.05.29 00:03:59.331
 8: 10 2023.05.29 00:03:59.430
 7: 9 2023.05.29 00:03:59.281
 6: 8 2023.05.29 00:03:59.281
 5: 7 2023.05.29 00:03:59.227
 4: 3 2023.05.29 00:03:59.331
 3: 6 2023.05.29 00:03:18.390
 2: 5 2023.05.29 00:03:18.390
 1: 4 2023.05.29 00:02:41.107
 0: 2 2023.05.29 00:02:41.107

В таблице истории MT5-ордера не сортированы ни по тикету, ни по времени. Не вижу смысла сообщать об этом поведении MQ-Тестера разработчикам. Ведь "задач выше крыши".

Поэтому эталонизировать MQ-Тестер не стал бы.

 
fxsaber #:

Немного локализовал.


Неважно, что делает советник. Главное - выделенный код, который просто выводит MT5-ордера из истории торгов: место ордера, его тикет и время его попадания в историю.

В таблице истории MT5-ордера не сортированы ни по тикету, ни по времени. Не вижу смысла сообщать об этом поведении MQ-Тестера разработчикам. Ведь "задач выше крыши".

Поэтому эталонизировать MQ-Тестер не стал бы.

Думаю у лимитных ордеров своя очередь переноса в историю при их закрытии. Не на каждом тике.
Если им явные баги с первыми сделками теста и свопами (которые пару недель назад скидывал) не нужно исправлять, то это просто фича. Матрица конфузии важнее...
 
Иногда полезно знать.
// Максимальная продолжительность просадки с заданного времени.
int MaxLengthDD( datetime &BeginDD, datetime &EndDD, const datetime From = 0 )
{
  const int Total = OrdersHistoryTotal();
  
  double Profit = 0;
  double MaxProfit = 0;
  datetime Begin = 0;
  
  BeginDD = 0;
  EndDD = 0;
  
  for (int i = 0; i < Total; i++)
    if (OrderSelect(i, SELECT_BY_POS, MODE_HISTORY) && (OrderType() <= OP_SELL))
    {
      if (!Begin && (OrderOpenTime() > From))
        Begin = OrderOpenTime();
        
      Profit += OrderProfit() + OrderSwap() + OrderCommission();
      
      if ((Profit > MaxProfit) || (i == Total - 1))
      {
        MaxProfit = Profit;
        
        const datetime End = OrderCloseTime();        
        
        if (Begin && (End - Begin > EndDD - BeginDD))
        {
          BeginDD = Begin;
          EndDD = End;
        }
        
        if (Begin)
          Begin = End;
      }
    }
    
  return((int)(EndDD - BeginDD));
}

void PrintMaxLengthDD( const datetime &From[] )
{
  const int Size = ArraySize(From);
  
  datetime BeginDD, EndDD;
  
  for (int i = 0; i < Size; i++)
    Print("From " + TimeToString(From[i], TIME_DATE) + " MaxLengthDD = " + (string)(MaxLengthDD(BeginDD, EndDD, From[i]) / (25 * 3600)) + " days: " +
          (string)BeginDD + " - " + (string)EndDD);  
}
 

fxsaber #:
Иногда полезно знать.

Print("From " + TimeToString(From[i], TIME_DATE) + " MaxLengthDD = " + (string)(MaxLengthDD(BeginDD, EndDD, From[i]) / (25 * 3600)) + " days: " +
          (string)BeginDD + " - " + (string)EndDD);

Так упакованно и фривольно лучше не писать (не только здесь, но и в прочих исходниках). Порядок вычислений операндов с одним и тем же приоритетом не установлен жестко - компилятор может это оптимизировать исходя из своих соображений, тогда можно получить разные побочные эффекты. Если работает сейчас, не значит, что не перестанет работать потом, т.к. внутренняя реализация компилятора всё время меняется.

 
Stanislav Korotky #:

Так упакованно и фривольно лучше не писать (не только здесь, но и в прочих исходниках). Порядок вычислений операндов с одним и тем же приоритетом не установлен жестко - компилятор может это оптимизировать исходя из своих соображений, тогда можно получить разные побочные эффекты. Если работает сейчас, не значит, что не перестанет работать потом, т.к. внутренняя реализация компилятора всё время меняется.

Спасибо за дельный совет! К сожалению, сложно заставить себя уходить от "лаконичного" стиля в пользу правильного. Очень много "неправильного" кода написал и использую.

 
fxsaber #:
// Максимальная продолжительность просадки с заданного времени.
C даты начала форварда?
Stanislav Korotky #:

Так упакованно и фривольно лучше не писать (не только здесь, но и в прочих исходниках). Порядок вычислений операндов с одним и тем же приоритетом не установлен жестко - компилятор может это оптимизировать исходя из своих соображений, тогда можно получить разные побочные эффекты. Если работает сейчас, не значит, что не перестанет работать потом, т.к. внутренняя реализация компилятора всё время меняется.

А что там не так?

Мне только

/ (25 * 3600)
не понравилось. В сутках 24 часа, а не 25
 

Forester #:
C даты начала форварда?

С любого.

А что там не так?

Нет однозначности, в какой последовательности будет формироваться строка для Print. Если справа-налево, то будет отличный от задуманного результат.

    Print("From " + TimeToString(From[i], TIME_DATE) + " MaxLengthDD = " + (string)(MaxLengthDD(BeginDD, EndDD, From[i]) / (25 * 3600)) + " days: " +
          (string)BeginDD + " - " + (string)EndDD);  


ЗЫ Была бы однозначность в таком случае.

int MaxLengthDD( const datetime &BeginDD, const datetime &EndDD, const datetime From = 0 )
 
fxsaber #:

Спасибо за дельный совет! К сожалению, сложно заставить себя уходить от "лаконичного" стиля в пользу правильного. Очень много "неправильного" кода написал и использую.

Я вообще почти всегда функции и др. код сворачиваю в одну строку, если код отработан/протестирован и возвращаться к нему не планирую. Просто чтобы место не занимал.
Да и читать код удобнее без скроллинга туда сюда, когда все видно на одном экране. Особенно в редакторах, которые подсвечивают выделенное слово (к сожалению Metaeditor к ним не относится ).
 
Forester #:
Я вообще почти всегда функции и др. код сворачиваю в одну строку, если код отработан/протестирован и возвращаться к нему не планирую. Просто чтобы место не занимал.
Да и читать код удобнее без скроллинга туда сюда, когда все видно на одном экране. Особенно в редакторах, которые подсвечивают выделенное слово (к сожалению Metaeditor к ним не относится ).

К сожалению, эта практика может привести к очень трудноуловимым ошибкам при смене компилятора.

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

 
fxsaber #:

С любого.

Информация по макс продолжительной просадке интересна. Я сделал ее для всего полученного массива строк. Пока не обновлял код на сайте.
А вот с датой не совсем понятно, для чего это. Если сделать точку разделения на бек/форвард тесты (как я предположил), то надо и статистики по ним отдельно посчитать в 2 таблички (макс периоды просадок там тоже будут).
А просто для одной даты это делать как-то слишком специфично и непонятно.