Experts: MQL5 Programming for Traders – Source Codes from the Book. Part 6 - page 3

 
hini #:

I've recently been learning Frame and I tested your code, FrameTransfer.mq5. This line is throwing an error in the current MT5 compiler. Please verify: #property tester_set "FrameTransfer.set" (invalid tester set file extension, '*.set' expected FrameTransfer.mq5)

It must be changed like this for it to compile successfully: #property tester_set "\\Presets\\FrameTransfer.set"

Even `#property tester_set "/Presets/FrameTransfer.set"` will fail.

Perhaps you could modify the description in the algorithm book:


Fix available in build 5506.
 
Alain Verleyen #:
Fix available in build 5506.
Thank you.
 
Stanislav Korotky optimisation criterion calculation file - RSquared.mqh, in which the calculation for the case of variable lots has been corrected.

The quality of estimation has been significantly improved - judging by the table of optimisation results, a combination of recovery factor and Sharpe parameters has been obtained.

Example of use.

Attention! If different symbols are traded, in order to get an adequate estimation of volumes, they should be converted from lots to the value in the deposit currency, for example (one of the simplified variants):

#include <MQL5Book/DealFilter.mqh>
#include <MQL5Book/RSquared.mqh>

template<typename T>
union Type2Bytes
{
   T d;
   uchar bytes[sizeof(T)];
};

double OnTester()
{
   HistorySelect(0, LONG_MAX);
   
   #define   STAT_PROPS 5
   
   const ENUM_DEAL_PROPERTY_DOUBLE props[STAT_PROPS] =
   {
      DEAL_PROFIT, DEAL_SWAP, DEAL_COMMISSION, DEAL_FEE, DEAL_VOLUME
   };
   double expenses[][STAT_PROPS];
   ulong tickets[]; // used here only to match 'select' prototype, but useful for debug
   
   DealFilter filter;
   filter.let(DEAL_TYPE, (1 << DEAL_TYPE_BUY) | (1 << DEAL_TYPE_SELL), IS::OR_BITWISE)
      .let(DEAL_ENTRY, (1 << DEAL_ENTRY_OUT) | (1 << DEAL_ENTRY_INOUT) | (1 << DEAL_ENTRY_OUT_BY), IS::OR_BITWISE)
      .select(props, tickets, expenses);

   const int n = ArraySize(tickets);
   
   double balance[];
   double volumes[]; // take trade volumes into account for using R2 criterion
   
   ArrayResize(balance, n + 1);
   balance[0] = 0;
   ArrayResize(volumes, n + 1);
   volumes[0] = 0;

   MapArray<ulong,double> sym2value; // symbol hash to 1 lot value
   
   for(int i = 0; i < n; ++i)
   {
      const string s = HistoryDealGetString(tickets[i], DEAL_SYMBOL);

      double value = 1;
      Type2Bytes<ulong> sym;
      ArrayInitialize(sym.bytes, 0);
      StringToCharArray(s, sym.bytes);
      int idx = sym2value.find(sym.d);
      if(idx == -1) // no record yet for symbol value per lot
      {
         const double price = SymbolInfoDouble(s, SYMBOL_ASK);
         const double pt = SymbolInfoDouble(s, SYMBOL_POINT);
         double profit = 1;
         ResetLastError();
         if(!OrderCalcProfit(ORDER_TYPE_BUY, s, 1, price, price + pt, profit)) // NB: estimated approximately, because it uses current rate for account currency
         {
            // WARN(StringFormat("OrderCalcProfit Error: %s %d ", s, _LastError));
         }
         value = profit * (price / pt); // NB: leverage is not applied here
         idx = sym2value.put(sym.d, value);
      }
      else
      {
         value = sym2value.getValue(idx);
      }
   
      double result = 0;
      for(int j = 0; j < STAT_PROPS - 1; ++j) // loop through all requested props except for deal volume
      {
         result += expenses[i][j];
      }
      // use volumes as a model - more investments - more returns expected
      volumes[i + 1] = expenses[i][STAT_PROPS - 1] * value + volumes[i];
      balance[i + 1] = result + balance[i];
   }
   
   const double r2 = RSquaredTest(balance, volumes);
   
   #undef   STAT_PROPS
   
   return r2 * 100;
}

Yellow is marked what had to be added compared to the calculation of trading one symbol (from the previous example).

 
Stanislav Korotky #:

Bugfix MQL5/Include/MQL5Book/TradeUtils.mqh.

Another related bugfix (in NormalizeLot method):

const double newLotsRounded = MathFloor(nlot * (1 + DBL_EPSILON) / stepLot) * stepLot;
Files:
TradeUtils.mqh  12 kb