Libraries: MT4Orders QuickReport - page 5

 
Forester #:

Server: MetaQuotes-Demo Hedge
Deal with ticket 99 on page two.

A little localised.

#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)));
    }
}


It doesn't matter what the EA is doing. The main thing is the highlighted code, which simply displays MT5 orders from the trading history: the order's place, its ticket and the time it entered the history.

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

In the history table, MT5 orders are not sorted by ticket or time. I don't see the point in reporting this behaviour of MQ-Tester to the developers. After all, "the tasks are over the top".

Therefore, I would not standardise MQ-Tester.

 
fxsaber #:

A little localised.


It doesn't matter what the EA does. The main thing is a dedicated code that simply outputs MT5 orders from the trading history: the place of the order, its ticket and the time it got into the history.

In the history table, MT5 orders are not sorted by ticket or time. I don't see the point in reporting this behaviour of MQ-Tester to the developers. After all, "the tasks are over the top".

Therefore, I would not standardise MQ-Tester.

I think that limit orders have their own queue of transfer to history when they are closed. Not on every tick.
If they do not need to fix obvious bugs with the first test trades and swaps (which I discounted a couple of weeks ago), then it is just a feature. Confusion matrix is more important....
 
Sometimes it's good to know.
// Maximum duration of drawdown from the set time.
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);

It is better not to write so packed and frivolous (not only here, but also in other sources). The order of calculations of operands with the same priority is not set rigidly - the compiler can optimise it based on its own considerations, then you can get different side effects. If it works now, it doesn't mean that it won't stop working later, because the internal implementation of the compiler changes all the time.

 
Stanislav Korotky #:

It is better not to write so packed and frivolous (not only here, but also in other sources). The order of calculations of operands with the same priority is not set rigidly - the compiler can optimise it based on its own considerations, then you can get different side effects. If it works now, it doesn't mean that it won't stop working later, because the internal implementation of the compiler changes all the time.

Thanks for the sound advice! Unfortunately, it's hard to force myself to move away from the "concise" style in favour of the correct one. There is a lot of "wrong" code written and used.

 
fxsaber #:
// Maximum drawdown duration from a given time.
From the forward start date?
Stanislav Korotky #:

It is better not to write in such a packed and frivolous way (not only here, but also in other sources). The order of calculations of operands with the same priority is not set rigidly - the compiler can optimise it based on its own considerations, then you can get different side effects. If it works now, it doesn't mean that it won't stop working later, because the internal implementation of the compiler changes all the time.

What's wrong with it?

I just

/ (25 * 3600)
I don't like. There are 24 hours in a day, not 25.
 

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

Anyone.

What is wrong there?

There is no unambiguous order in which the string for Print will be formed. If from right to left, the result will be different from the intended one.

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


I wish there was unambiguity in such a case.

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

Thanks for the sound advice! Unfortunately, it's hard to force myself to move away from the "concise" style in favour of the correct one. There is a lot of "wrong" code written and used.

I almost always collapse functions and other code into one line if the code is worked/tested and I don't plan to return to it. Just to save space.
And it is more convenient to read the code without scrolling back and forth when you can see everything on one screen. Especially in editors that highlight the highlighted word (unfortunately Metaeditor is not one of them).
 
Forester #:
I almost always collapse functions and other code into one line if the code is worked/tested and I don't plan to return to it. Just to save space.
And it is more convenient to read the code without scrolling back and forth when you can see everything on one screen. Especially in editors that highlight the highlighted word (unfortunately Metaeditor is not one of them).

Unfortunately, this practice can lead to very hard-to-see errors when you change compilers.

However, there are situations where you just need to use the order set in the compiler. And there I don't know how to get round it so that there is no UB.

 
fxsaber #:

From anyone.

The information on max long drawdown is interesting. I made it for the whole array of strings. I haven't updated the code on the site yet.
But it's not quite clear what the date is for. If we make a point of division into back/forward tests (as I suggested), then we need to calculate statistics on them separately in 2 tables (max drawdown periods will be there too).
And just for one date it is somehow too specific and incomprehensible.