EA: 交易者的MQL5编程(MQL5 Programming for Traders) - 源代码第七部分 - 页 2

 
Denis Kirichenko #:

一般来说,教科书最好用括号 写:

所有形式为 @= 的运算符,其中 doggy 表示任何运算的符号,总是在右操作数上执行,并在执行运算之前完全计数。这将在第 2 部分的修改操作中介绍。

第六部分将介绍余量计算文件,这里假定前面的部分已经掌握。本书接近尾声时,复杂性会增加--我并不反对这一点,因此我尽量在下面的章节中引用过去章节中的大概念和原理,在这些章节中,这些概念和原理被用作构建模块(以唤起你的记忆),但不是用于这些小事情。

 
Stanislav Korotky #:

......本书的复杂性在结尾部分有所增加--这一点无可争议,因此,对于过去章节中的大概念和原理,我试图参考后面章节中用作构建模块的内容(以唤起我的记忆),但对于这些细小的内容则没有参考。

斯坦尼斯拉夫,我的编程水平与你不同。我在编写代码时,尽量让调试器更容易检查。这就是我不经常使用三元运算符的原因。如果要使用,我也会用括号...有些人写的三元运算符互相包含,非常娴熟。这与我的同事fxsaber 的宏编程风格很接近。也许每种方法都有其生命力。这本来就是品味问题......

非常尊重和敬佩这本教程!有些有趣的东西比文档中描述得更详细。

 
Aleksandr Slavskii #:

反正它也没什么用处,因为如果数量超过 3,它最终还是会错误地计算边距。

十份合约的保证金计算。

请附上脚本以供检查。现在我在整个市场概览上运行了它 - 无论成交量如何,它都与标准功能一致。

 
Denis Kirichenko #:

编译器很生气:

可能是编译器出了问题。在本书发布时,所有源代码在编译时都不会出现警告或错误,除非是为了演示而故意出现异常。

 
Denis Kirichenko #:

我在编写代码时尽量让调试器更容易检查代码。这就是我不经常使用三元运算符的原因。如果要使用,我也会用括号....

我同意。我也坚持这条规则,除了简单的情况--但在这里,每个人都有自己的简单障碍。代码的可读性是单独处理的,通常我们会在 "全部放在一行 "和 "每个标记单独放在一行 "之间寻找一个 "黄金分割点"。使用括号--类似。软件公司通常都有一套关于源代码布局的规则,在这种情况下则没有。

 
代码库中 发布了更多关于经济日历读取和导出为 CSV 的错误修复和改进。具体而言,针对大部分已排序的大型数组(通常从 MQL5 日历 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 #:

请附上脚本以供验证。现在,我在整个市场概览上运行了该脚本 - 无论成交量如何,它都与标准功能相吻合。

哦,天哪。我居然没看到这条信息。哦,天哪。

实际上,对我来说没什么变化。

Metaquot 服务器 终端版本 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

有人数错了。


我可能错误地删除了命名空间 MPM。 我不知道它是什么,为什么需要它,但它不让我编译 EA。

实际上,我只是删除了命名空间 MPM 一行和后面的大括号,并将其重命名为 OrderCalcMargin,添加了下划线。

总的来说,文件是以这种形式编译的。这可能是错误所在吗?

//+------------------------------------------------------------------+
//|MarginProfitMeter.mqh | |
//|版权 (c) 2018-2022, Marketeer ||
//|https://www.mql5.com/en/users/marketeer|
//|| 一组用于计算利润率、潜在利润/亏损的函数。
//| 点值和覆盖率。|
//+------------------------------------------------------------------+
// 指标中不允许使用的内置 OrderCalcMargin 的类似功能
bool _OrderCalcMargin(const ENUM_ORDER_TYPE action, const string symbol,
                     double volume, double price, double &margin)
  {
   double marginInit, marginMain;
   MqlTick ticks;

// 检查给定参数
   if((action != ORDER_TYPE_BUY && action != ORDER_TYPE_SELL) || volume < 0 || price < 0)
      return false;

// 申请公式中使用的所有属性
   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;
  }

// 搜索 "当前 "和 "账户 "货币单一构建的可用符号
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;
  }

// 估计过去某一时刻指定符号的速率
double GetHistoricPrice(const string symbol, const datetime moment, const bool ask)
  {
   const int offset = iBarShift(symbol, _Period, moment);
// 注意:iClose 可以保存最后价格,而不是交易所符号的买入价。
// 没有快速处理的方法,只能进行刻度历史分析
   return iClose(symbol, _Period, offset) +
          (ask ? iSpread(symbol, _Period, offset) * SymbolInfoDouble(symbol, SYMBOL_POINT) : 0);
  }

// _将 "当前 "金额转换为 "账户 "金额
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;
  }

// 返回特定符号的点值(以账户货币表示
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 的 新闻。

按数量计算的浮动保证金

在服务器设置和符号规范界面中,他们添加了对成交量的保证金依赖性。

我没有找到如何从 MQL5 获取这些属性。

在特定的经纪商/工具中,浮动保证金设置可能未被激活,因此我在 MQ 演示中检查时未发现任何差异。

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 编程 - 书中的源代码。第七部分

Stanislav Korotky, 2024.11.23 20:26

在这里,我发现了 2024 年初(即书写完之后)关于构建 4150 的新闻 -https://www.metatrader5.com/en/releasenotes/terminal/2342。

按数量计算的浮动保证金

在服务器设置和符号规范界面中,他们增加了对体积的保证金依赖。

我没有找到如何从 MQL5 获取这些属性。

在特定的经纪商/工具中,浮动保证金设置可能未被激活,因此我在 MQ 演示中检查时未发现任何差异。