Советники: Программирование на MQL5 для трейдеров — исходные коды из книги. Часть 7 - страница 2

 
Denis Kirichenko #:

Вообще для учебника конечно лучше было бы в скобках писать:

Все операторы вида @=, где под собачкой подразумевается символ любой операции, всегда выполняются над правым операндом, полностью посчитанным до выполнения операции. Это освещено во второй части, в разделе Операции модификации.

Файл расчета маржи описывается в шестой части, где подразумевается, что предыдущие части освоены. Сложность к концу книги возрастает - с этим не спорю, поэтому на крупные понятия и принципы из прошлых разделов я старался делать ссылки из следующих, где это использовалось как кирпичики (чтобы освежить память), но не для таких мелких вещей.

 
Stanislav Korotky #:

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

Станислав, у меня более скромный уровень в программировании в отличие от Вашего. Я стараюсь писать код так, чтобы его легче было проверить в Отладчике. И поэтому не часто использую тернарный оператор. А если и использую, то со скобками... Есть такие умельцы, к-рые пишут по несколько тернарных операторов, входящих в другу друга. Это что-то уже близкое к стилю программирования макросами у коллеги fxsaber. Наверное каждый подход имеет право на жизнь. И это уже дело вкуса...

За учебник огромный респект и уважуха! Некоторые интересные вещи описаны поподробнее, чем в Документации.

 
Aleksandr Slavskii #:

Толку от этого всё равно мало, так как в итоге всё равно маржу считает не правильно, если объём больше трёх.

Расчет маржи для десяти контрактов.

Приложите скрипт для проверки. Сейчас запустил по всему обзору рынка - совпадает со стандартной функцией вне зависимости от объема.

 
Denis Kirichenko #:

Ещё и компилятор злится:

Вероятно, что-то поменялось в компиляторе. На момент выпуска книги все исходники компилировались без предупреждений и ошибок, за исключением случаев, где были намеренно допущены нарушения в демонстрационных целях.

 
Denis Kirichenko #:

Я стараюсь писать код так, чтобы его легче было проверить в Отладчике. И поэтому не часто использую тернарный оператор. А если и использую, то со скобками...

Согласен. Тоже придерживаюсь такого правила, кроме простых случаев - но здесь у каждого свой барьер простоты срабатывает. Читабельность кода индивидуально трактуется, обычно ищется "золотая середина" между подходом "все в одну строку" и "каждый токен на отдельной строке". Со скобками - аналогично. В компаниях-разработчиках ПО обычно есть свод правил по оформлению исходников - в данном случае его не было.

 
В кодовой базе опубликованы исправления и улучшения для чтения экономического календаря и экспорта в CSV. В частности, исправлен алгоритм сортировки для случая преимущественно отсортированных больших массивов (которые обычно получаются из MQL5 calendar API), что позволяет устранить замедления и переполнения стека.
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 #:

Приложите скрипт для проверки. Сейчас запустил по всему обзору рынка - совпадает со стандартной функцией вне зависимости от объема.

Блин. Как я мог не увидеть это сообщение. Блин.

Собственно у меня ничего не изменилось.

Сервер метаквотов,  версия терминала 4420.

Код такой

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

Результат такой

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

Кто то считает не правильно.  


ЗЫ. Возможно я не правильно избавился от этого - namespace MPM.  Не знаю, что это и зачем оно нужно, но оно не давало скомпилировать советник.

Собственно я просто удалил строку  namespace MPM, фигурные скобки за ним и переименовал OrderCalcMargin, добавил нижнее подчёркивание.

В общем, файл в таком виде скомпилировался. Возможно в этом ошибка?

//+------------------------------------------------------------------+
//|                                            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 one 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 #:

Код такой

Результат такой

Кто то считает не правильно.  


Вот нашел в новостях на начало 2024 года (т.е. после написания книги) про билд 4150 - https://www.metatrader5.com/en/releasenotes/terminal/2342

Floating Margin by Volume

В настройки сервера и интерфейс спецификации символа добавили зависимость маржи от объема.

Как к этим свойствам добраться из MQL5 - я не нашел.

У конкретного брокера/инструмента данная плавающая настройка маржи может быть не задействована, поэтому я не увидел разночтений при проверке не на 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 #:

В настройки сервера и интерфейс спецификации символа добавили зависимость маржи от объема.

Как к этим свойствам добраться из MQL5 - я не нашел.

Я тоже искал, и тоже не нашёл)
Решил, что это баг в моей голове, оказалось не в моей.
Спасибо.
 

@Renat Fatkhullin

Есть ли в планах добавление возможности получение этих свойств из MQL5 ?

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Советники: Программирование на MQL5 для трейдеров — исходные коды из книги. Часть 7

Stanislav Korotky, 2024.11.23 20:26

Вот нашел в новостях на начало 2024 года (т.е. после написания книги) про билд 4150 - https://www.metatrader5.com/en/releasenotes/terminal/2342

Floating Margin by Volume

В настройки сервера и интерфейс спецификации символа добавили зависимость маржи от объема.

Как к этим свойствам добраться из MQL5 - я не нашел.

У конкретного брокера/инструмента данная плавающая настройка маржи может быть не задействована, поэтому я не увидел разночтений при проверке не на MQ demo.