Especialistas: Programação no MQL5 para traders: códigos-fonte retirados do livro. Parte 7 - página 2

 
Denis Kirichenko #:

Em geral, para um livro didático, seria melhor escrever entre colchetes:

Todos os operadores do formato @=, em que doggy significa o símbolo de qualquer operação, são sempre executados sobre o operando direito, totalmente contado antes da execução da operação. Isso é abordado na Parte 2, em Operações de modificação.

O arquivo de cálculo de margem é descrito na sexta parte, onde se supõe que as partes anteriores tenham sido dominadas. A complexidade aumenta no final do livro - não discuto isso, então tentei fazer referências aos grandes conceitos e princípios das seções anteriores nas seções seguintes, onde eles foram usados como blocos de construção (para refrescar a memória), mas não para coisas tão pequenas.

 
Stanislav Korotky #:

...A complexidade aumenta no final do livro - não há dúvida quanto a isso, portanto, para os grandes conceitos e princípios das seções anteriores, tentei fazer referências às seções seguintes, onde foram usados como blocos de construção (para refrescar minha memória), mas não para coisas tão pequenas.

Stanislav, tenho um nível de programação mais modesto do que o seu. Tento escrever o código de modo que seja mais fácil verificá-lo no depurador. É por isso que não uso com frequência o operador ternário. E se o faço, uso-o com parênteses... Há pessoas muito habilidosas que escrevem vários operadores ternários incluídos uns nos outros. Isso é algo próximo ao estilo de programação de macros do meu colega fxsaber. Provavelmente, toda abordagem tem direito à vida. E isso já é uma questão de gosto...

Grande respeito e respeito pelo tutorial! Algumas coisas interessantes são descritas com mais detalhes do que na documentação.

 
Aleksandr Slavskii #:

De qualquer forma, é de pouca utilidade, pois no final ele ainda conta a margem incorretamente se o volume for maior que três.

Cálculo da margem para dez contratos.

Favor anexar o script para verificação. Agora eu o executei em toda a visão geral do mercado - ele coincide com a função padrão, independentemente do volume.

 
Denis Kirichenko #:

E o compilador está irritado:

Provavelmente algo mudou no compilador. Na época do lançamento do livro, todos os códigos-fonte eram compilados sem avisos ou erros, exceto nos casos em que havia irregularidades deliberadas para fins de demonstração.

 
Denis Kirichenko #:

Tento escrever o código de modo que seja mais fácil verificá-lo no depurador. É por isso que não uso com frequência o operador ternário. E se o faço, uso-o com parênteses....

Eu concordo. Eu também sigo essa regra, exceto em casos simples - mas aqui cada um tem sua própria barreira de simplicidade. A legibilidade do código é tratada individualmente, geralmente procuramos uma "média de ouro" entre a abordagem "tudo em uma linha" e "cada token em uma linha separada". Com colchetes - da mesma forma. As empresas de software geralmente têm um conjunto de regras sobre o layout do código-fonte - nesse caso, não havia nenhuma.

 
Mais correções de erros e melhorias na leitura do calendário econômico e na exportação para CSV foram publicadas na base de código. Especificamente, o algoritmo de classificação foi corrigido para o caso de matrizes grandes classificadas em sua maior parte (que geralmente são recebidas da API de calendário MQL5), de modo que a lentidão e os transbordamentos de pilha sejam eliminados.
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 #:

Anexe o script para verificação. Agora eu o executei em toda a visão geral do mercado - ele coincide com a função padrão, independentemente do volume.

Ah, cara. Não acredito que não vi essa mensagem. Caramba.

Na verdade, nada mudou para mim.

Servidor Metaquot, versão de terminal 4420.

O código é o seguinte

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

O resultado é o seguinte.

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

Alguém está contando errado.


Talvez eu tenha me livrado do namespace MPM incorretamente. Não sei o que ele é e por que é necessário, mas ele não me permitiu compilar o EA.

Na verdade, apenas removi a linha do namespace MPM, as chaves depois dela e renomeei OrderCalcMargin, acrescentando o sublinhado.

Em geral, o arquivo foi compilado dessa forma. É possível que esse seja o erro?

//+------------------------------------------------------------------+
//|MarginProfitMeter.mqh
//|Direitos autorais (c) 2018-2022, Marketeer
//| https://www.mql5.com/en/users/marketeer |
//|| Um conjunto de funções para calcular a margem, o lucro/prejuízo em potencial, o lucro/prejuízo em potencial e o lucro/prejuízo em potencial.
//| Valor do ponto e taxas de conversão.|
//+------------------------------------------------------------------+
// Análogo do OrderCalcMargin incorporado, que não é permitido em indicadores
bool _OrderCalcMargin(const ENUM_ORDER_TYPE action, const string symbol,
                     double volume, double price, double &margin)
  {
   double marginInit, marginMain;
   MqlTick ticks;

// verificar os parâmetros fornecidos
   if((action != ORDER_TYPE_BUY && action != ORDER_TYPE_SELL) || volume < 0 || price < 0)
      return false;

// solicitar todas as propriedades usadas nas fórmulas
   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;
  }

// Pesquisar símbolos disponíveis para uma única construção das moedas "current" e "account
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;
  }

// Estimar uma taxa de um símbolo específico em um determinado momento no passado
double GetHistoricPrice(const string symbol, const datetime moment, const bool ask)
  {
   const int offset = iBarShift(symbol, _Period, moment);
// NB: iClose pode manter o último preço em vez do lance para símbolos de câmbio
// não há uma maneira rápida de lidar com isso, apenas a análise do histórico de ticks
   return iClose(symbol, _Period, offset) +
          (ask ? iSpread(symbol, _Period, offset) * SymbolInfoDouble(symbol, SYMBOL_POINT) : 0);
  }

// _Converta a quantia de dinheiro "atual" em dinheiro "da conta
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;
  }

// Retorna o valor do ponto (na moeda da conta) de um símbolo específico
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 #:

O código é o seguinte

O resultado é o seguinte

Alguém está contando errado.


Aqui está a notícia do início de 2024 (ou seja, após a redação do livro) sobre a compilação 4150 - https://www.metatrader5.com/en/releasenotes/terminal/2342.

Margem flutuante por volume

Nas configurações do servidor e na interface de especificação de símbolos, eles adicionaram a dependência da margem em relação ao volume.

Não descobri como acessar essas propriedades a partir da MQL5.

Em uma corretora/instrumento específico, essa configuração de margem flutuante pode não estar ativada, portanto, não vi nenhuma diferença ao verificar se não estava na 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 #:

Foi adicionada a dependência da margem de volume às configurações do servidor e à interface de especificação de símbolos.

Não encontrei como acessar essas propriedades a partir da MQL5.

Também procurei por isso e não encontrei)
Pensei que fosse um bug na minha cabeça, mas acabou não sendo.
Obrigado.
 

@Renat Fatkhullin

Há algum plano para adicionar a capacidade de obter essas propriedades da MQL5?

Fórum sobre negociação, sistemas de negociação automatizados e teste de estratégias de negociação

Expert Advisors: MQL5 Programming for Traders - códigos-fonte do livro. Parte 7

Stanislav Korotky, 2024.11.23 20:26

Encontrei aqui nas notícias do início de 2024 (ou seja, depois que o livro foi escrito) sobre a compilação 4150 - https://www.metatrader5.com/en/releasenotes/terminal/2342.

Margem flutuante por volume

Nas configurações do servidor e na interface de especificação de símbolos, eles adicionaram a dependência de margem no volume.

Não encontrei uma maneira de acessar essas propriedades a partir da MQL5.

Em um determinado corretor/instrumento, essa configuração de margem flutuante pode não estar ativada, portanto, não vi nenhuma diferença ao verificar se não estava na demonstração MQ.