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

 
Denis Kirichenko #:

In general, for a textbook it would be better to write in brackets:

All operators of the form @=, where doggy means the symbol of any operation, are always executed over the right operand, fully counted before the operation is executed. This is covered in Part 2, under Modification Operations.

The margin calculation file is described in part six, where it is assumed that the previous parts have been mastered. The complexity increases towards the end of the book - I don't argue with that, so I tried to make references to the big concepts and principles from past sections from the following sections, where these were used as building blocks (to refresh your memory), but not for such small things.

 
Stanislav Korotky #:

...The complexity increases towards the end of the book - no argument with that, so for the big concepts and principles from past sections, I tried to make references from the following sections where it was used as building blocks (to refresh my memory), but not for such small things.

Stanislav, I have a more modest level in programming unlike yours. I try to write code so that it is easier to check it in the Debugger. That's why I don't often use the ternary operator. And if I do, I use it with parentheses... There are such skilful people who write several ternary operators included in each other. This is something close to the macro programming style of my colleague fxsaber. Probably every approach has a right to life. And it is already a matter of taste...

Great respect and respect for the tutorial! Some interesting things are described in more detail than in the Documentation.

 
Aleksandr Slavskii #:

It is of little use anyway, because in the end it still counts the margin incorrectly if the volume is more than three.

Margin calculation for ten contracts.

Please attach the script for checking. Now I have run it on the whole market overview - it coincides with the standard function regardless of the volume.

 
Denis Kirichenko #:

And the compiler's pissed off:

Probably something changed in the compiler. At the time of the book's release, all sources compiled without warnings or errors, except in cases where there were deliberate irregularities for demonstration purposes.

 
Denis Kirichenko #:

I try to write code so that it would be easier to check it in the Debugger. That's why I don't often use the ternary operator. And if I do, I use it with parentheses....

I agree. I stick to this rule too, except for simple cases - but here everyone has his own barrier of simplicity. Readability of the code is treated individually, usually we look for a "golden mean" between the approach "all in one line" and "each token on a separate line". With brackets - similarly. Software companies usually have a set of rules on source code layout - in this case there was none.

 
More bugfixes and improvements for the economic calendar reading and exporting to CSV are published in the codebase. Specifically, the sorting algorithm is fixed for the case of mostly sorted large arrays (which are usually received from MQL5 calendar API), so that slow-downs and stack-overflows are eliminated.
Economic Calendar CSV
Economic Calendar CSV
  • www.mql5.com
This script saves a predefined set of economic events from the MetaTrader's built-in economic calendar into CSV file.
 
Stanislav Korotky #:

Please attach the script for verification. Now I have run it on the whole market overview - it coincides with the standard function regardless of the volume.

Oh, man. I can't believe I didn't see that message. Oh, man.

Actually, nothing has changed for me.

Metaquot server, terminal version 4420.

The code is like this

#include "MarginProfitMeter.mqh"
//+------------------------------------------------------------------+
int OnInit(void)
  {
   EventSetTimer(1);
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
void OnTimer()
  {
   double margin = 0;
   double volume = 10;
   ENUM_ORDER_TYPE type = ORDER_TYPE_BUY;
   double price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   if(_OrderCalcMargin(type, _Symbol, volume, price, margin))
      Print("Symbol ", _Symbol, "; volume ", volume, "; MarginProfitMeter margin = ", margin);

   margin = 0;
   if(OrderCalcMargin(type, _Symbol, volume, price, margin))
      Print("Symbol ", _Symbol, "; volume ", volume, "; OrderCalcMargin margin = ", margin);
  }
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   EventKillTimer();
  }
//+------------------------------------------------------------------+

The result is this.

18:53:40.877    11 (EURUSD,H1)  Symbol EURUSD; volume 10.0; MarginProfitMeter margin = 10421.6
18:53:40.877    11 (EURUSD,H1)  Symbol EURUSD; volume 10.0; OrderCalcMargin margin = 23264.8

Someone is counting wrong.


I may have got rid of namespace MPM incorrectly. I don't know what it is and why it is needed, but it didn't let me compile the EA.

Actually, I just removed the namespace MPM line , curly braces after it and renamed OrderCalcMargin, added the underscore.

In general, the file compiled in this form. Is it possible that this is the error?

//+------------------------------------------------------------------+
//|MarginProfitMeter.mqh |
//|Copyright (c) 2018-2022, Marketeer |
//| https://www.mql5.com/en/users/marketeer |
//|| A set of functions to calculate margin, potential profit/loss, ||
//| point value and coversion rates.|
//+------------------------------------------------------------------+
// Analogue of built-in OrderCalcMargin which is not allowed in indicators
bool _OrderCalcMargin(const ENUM_ORDER_TYPE action, const string symbol,
                     double volume, double price, double &margin)
  {
   double marginInit, marginMain;
   MqlTick ticks;

// check given parameters
   if((action != ORDER_TYPE_BUY && action != ORDER_TYPE_SELL) || volume < 0 || price < 0)
      return false;

// request all properties used in the formulae
   if(!SymbolInfoTick(symbol, ticks))
      return false;
   if(!SymbolInfoMarginRate(symbol, action, marginInit, marginMain))
      return false;
   const double contract = SymbolInfoDouble(symbol, SYMBOL_TRADE_CONTRACT_SIZE);
   long leverage = AccountInfoInteger(ACCOUNT_LEVERAGE);
   if(volume == 0)
      volume = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
   if(price == 0)
      price = action == ORDER_TYPE_BUY ? ticks.ask : ticks.bid;

   if(margin == DBL_MAX)
      marginInit = marginMain;
   margin = 0;

   const ENUM_SYMBOL_CALC_MODE m = (ENUM_SYMBOL_CALC_MODE)SymbolInfoInteger(symbol, SYMBOL_TRADE_CALC_MODE);

   switch(m)
     {
      case SYMBOL_CALC_MODE_FOREX_NO_LEVERAGE:
         leverage = 1;

      case SYMBOL_CALC_MODE_FOREX:
         margin = volume * contract / leverage * marginInit;
         break;

      case SYMBOL_CALC_MODE_CFD:
         margin = volume * contract * price * marginInit;
         break;

      case SYMBOL_CALC_MODE_CFDINDEX:
         margin = volume * contract * price * SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE)
                  / SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE) * marginInit;
         break;

      case SYMBOL_CALC_MODE_CFDLEVERAGE:
         margin = volume * contract * price / leverage * marginInit;
         break;

      case SYMBOL_CALC_MODE_EXCH_STOCKS:
      case SYMBOL_CALC_MODE_EXCH_STOCKS_MOEX:
         if(price == 0)
            price = ticks.last;
         margin = volume * contract * price * marginInit;
         break;

      case SYMBOL_CALC_MODE_FUTURES:
      case SYMBOL_CALC_MODE_EXCH_FUTURES:
      case SYMBOL_CALC_MODE_EXCH_FUTURES_FORTS:
         margin = volume * SymbolInfoDouble(symbol, SYMBOL_MARGIN_INITIAL) * marginInit;
         break;
      default:
         PrintFormat("Unsupported symbol %s trade mode: %s", symbol, EnumToString(m));
     }

   string account = AccountInfoString(ACCOUNT_CURRENCY);
   string current = SymbolInfoString(symbol, SYMBOL_CURRENCY_MARGIN);
   if(current != account)
     {
      if(!_Convert(current, account, action == ORDER_TYPE_SELL, margin))
         return false;
     }

   return true;
  }

// Search available symbols for a single built of the 'current' and 'account' currencies
int _FindExchangeRate(const string current, const string account, string &result)
  {
   for(int i = 0; i < SymbolsTotal(true); i++)
     {
      const string symbol = SymbolName(i, true);
      const ENUM_SYMBOL_CALC_MODE m = (ENUM_SYMBOL_CALC_MODE)SymbolInfoInteger(symbol, SYMBOL_TRADE_CALC_MODE);
      if(m == SYMBOL_CALC_MODE_FOREX || m == SYMBOL_CALC_MODE_FOREX_NO_LEVERAGE)
        {
         string base = SymbolInfoString(symbol, SYMBOL_CURRENCY_BASE);
         string profit = SymbolInfoString(symbol, SYMBOL_CURRENCY_PROFIT);
         if(base == current && profit == account)
           {
            result = symbol;
            return +1;
           }
         else
            if(base == account && profit == current)
              {
               result = symbol;
               return -1;
              }
        }
     }
   return 0;
  }

// Estimate a rate of specified symbol at a given moment in past
double GetHistoricPrice(const string symbol, const datetime moment, const bool ask)
  {
   const int offset = iBarShift(symbol, _Period, moment);
// NB: iClose can hold Last price instead of Bid for exchange symbols
// there is no fast way to handle this, only ticks history analysis
   return iClose(symbol, _Period, offset) +
          (ask ? iSpread(symbol, _Period, offset) * SymbolInfoDouble(symbol, SYMBOL_POINT) : 0);
  }

// _Convert amount of 'current' money into 'account' money
bool _Convert(const string current, const string account,
             const bool ask, double &margin, const datetime moment = 0)
  {
   string rate;
   int dir = _FindExchangeRate(current, account, rate);
   if(dir == +1)
     {
      margin *= moment == 0 ?
                SymbolInfoDouble(rate, ask ? SYMBOL_BID : SYMBOL_ASK) :
                GetHistoricPrice(rate, moment, ask);
     }
   else
      if(dir == -1)
        {
         margin /= moment == 0 ?
                   SymbolInfoDouble(rate, ask ? SYMBOL_ASK : SYMBOL_BID) :
                   GetHistoricPrice(rate, moment, ask);
        }
      else
        {
         static bool once = false;
         if(!once)
           {
            Print("Can't convert ", current, " -> ", account);
            once = true;
           }
        }
   return true;
  }

// Return point value (in account currency) of specific symbol
double PointValue(const string symbol, const bool ask = false, const datetime moment = 0)
  {
   const double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
   const double contract = SymbolInfoDouble(symbol, SYMBOL_TRADE_CONTRACT_SIZE);
   const ENUM_SYMBOL_CALC_MODE m = (ENUM_SYMBOL_CALC_MODE)SymbolInfoInteger(symbol, SYMBOL_TRADE_CALC_MODE);
   double result = 0;

   switch(m)
     {
      case SYMBOL_CALC_MODE_FOREX_NO_LEVERAGE:
      case SYMBOL_CALC_MODE_FOREX:
      case SYMBOL_CALC_MODE_CFD:
      case SYMBOL_CALC_MODE_CFDINDEX:
      case SYMBOL_CALC_MODE_CFDLEVERAGE:
      case SYMBOL_CALC_MODE_EXCH_STOCKS:
      case SYMBOL_CALC_MODE_EXCH_STOCKS_MOEX:
         result = point * contract;
         break;

      case SYMBOL_CALC_MODE_FUTURES:
      case SYMBOL_CALC_MODE_EXCH_FUTURES:
      case SYMBOL_CALC_MODE_EXCH_FUTURES_FORTS:
         result = point * SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE) / SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE);
         break;
      default:
         PrintFormat("Unsupported symbol %s trade mode: %s", symbol, EnumToString(m));
     }

   string account = AccountInfoString(ACCOUNT_CURRENCY);
   string current = SymbolInfoString(symbol, SYMBOL_CURRENCY_PROFIT);

   if(current != account)
     {
      if(!_Convert(current, account, ask, result, moment))
         return 0;
     }

   return result;
  }
//+------------------------------------------------------------------+
 
Aleksandr Slavskii #:

The code is as follows

The result is like this

Someone's counting wrong.


Here is found in the news for the beginning of 2024 (i.e. after the writing of the book) about build 4150 - https://www.metatrader5.com/en/releasenotes/terminal/2342.

Floating Margin by Volume

In the server settings and symbol specification interface they added the margin dependence on volume.

I have not found how to get to these properties from MQL5.

In a particular broker/instrument this floating margin setting may not be activated, so I did not see any differences when checking not on MQ demo.

MetaTrader 5 build 4150: Trading report export and new machine learning methods in MQL5
MetaTrader 5 build 4150: Trading report export and new machine learning methods in MQL5
  • 2024.01.18
  • MetaQuotes
  • www.metatrader5.com
Added export of trading reports to HTML and PDF files. With this option, you can easily share your trading achievements with colleagues and investors. New export commands are available in the File menu and in the report menu. Added ability to save the current state of the Market Watch window to a CSV file. To do this, select Export in the...
 
Stanislav Korotky #:

Added volume margin dependency to the server settings and the symbol specification interface.

I have not found how to get to these properties from MQL5.

I also searched for it and did not find it either)
I thought it was a bug in my head, but it turned out not to be.
Thanks.
 

@Renat Fatkhullin

Are there any plans to add the ability to get these properties from MQL5 ?

Forum on trading, automated trading systems and testing trading strategies

Expert Advisors: MQL5 Programming for Traders - source codes from the book. Part 7

Stanislav Korotky, 2024.11.23 20:26

Here I found in the news for the beginning of 2024 (i.e. after the book was written) about build 4150 - https://www.metatrader5.com/en/releasenotes/terminal/2342.

Floating Margin by Volume

In server settings and symbol specification interface they added margin dependency on volume.

I have not found how to get to these properties from MQL5.

In a particular broker/instrument this floating margin setting may not be activated, so I did not see any differences when checking not on MQ demo.