English Русский Español Português
preview
市场模拟(第六部分):将信息从 MetaTrader 5 传输到 Excel

市场模拟(第六部分):将信息从 MetaTrader 5 传输到 Excel

MetaTrader 5测试者 |
90 1
Daniel Jose
Daniel Jose

概述

对于一些 MetaTrader 5 用户来说,最常给他们的生活带来麻烦的事情之一就是它缺少某些功能。

许多人,尤其是非程序员,发现在 MetaTrader 5 和其他程序之间传输信息非常困难。其中一个程序就是 Excel。许多人使用 Excel 作为管理和维护风险控制的一种方式。这是一个优秀的程序,易于学习,即使对于那些不是 VBA 程序员的人来说也是如此。然而,在 MetaTrader 5 和 Excel 之间传输信息并不是最简单的任务之一,特别是如果你没有编程知识的话。

尽管如此,它还是非常有用的,因为它大大简化了那些只想交易的人的生活,同时使用 Excel 作为管理操作风险的工具。但是,如果没有适当的编程知识,您肯定会发现自己依赖未知的程序,或者因为无法将信息从平台传输到 Excel 而放弃使用 MetaTrader 5。

幸运的是,Excel 提供了一些非常有趣的方法来实现这一点。稍后我们将更详细地讨论它们。不幸的是,MetaTrader 5 不包括任何允许我们直接将信息发送到 Excel 的内置功能。您要么需要编程知识,要么必须获得一些能够执行传输的工具。


理解问题

让我们先来了解一下最初遇到的挑战,以及在程序和 Excel 之间传输数据的最常用方法。最常见的方法之一是使用 RTD(实时数据)或 DDE(动态数据交换)。然而,这两种解决方案都需要掌握 COM(组件对象模型)接口编程的知识,而许多程序员实际上并不具备这一技能。即便你成功开发出这样的解决方案,其灵活性也未必高。

RTD 和 DDE 均为单向通信方式,即它们仅在系统之间建立桥梁连接。它们不允许使用某些特别有趣的功能,特别是在处理 Excel 时。但是因为 Excel 本身支持这些系统,所以它们很有用,因为它们提供了一种实时通信。

但让我们从更广阔的角度来看待这个问题,你真正需要在 Excel 中使用实时数据的频率有多高?大多数情况下,轻微的延迟是完全可以接受的。在这里,我并不是指那些想用 Excel 作为自动交易机器人控制系统的人。如果您使用的是 MetaTrader 5,您无疑希望计算在平台内进行,而不是将其发送到 Excel。让 Excel 计算仓位,然后让你的 EA 交易系统在 MetaTrader 5 中根据 Excel 的结果做出决策,这完全没有意义。

但是,如果您交易的头寸可能持续两天或更长时间,或者您交易多头/空头对,您肯定希望 Excel 能帮助您更顺利地管理资金并做出风险控制决策。在这种情况下,您希望 Excel 自动接收报价或信息。试想一下,如果你同时持有 20 个多空仓位,你该如何操作?根据您的策略,您必须每天或每小时手动更新 40 个报价。

犯错的风险是巨大的,更不用说手动逐一传输 40 个报价所浪费的时间了。真是件麻烦事。

因此,许多人都在寻找解决这个问题的办法。其中一种方法是直接引用来自网络的报价。


Web 解决方案

该 web 解决方案基于 Excel 本身,可以自动为我们执行更新操作。但这里有个小问题。

虽然它很容易创建,但并不理想。这是因为报价之间会有延迟,有时延迟较大,有时延迟较小。这主要是因为大多数金融信息服务都是付费的。

世上没有免费的午餐,尤其是在涉及到金钱的时候。

我不是来评判对这些服务收费是对是错的。问题是:如果你已经有了像 MetaTrader 5 这样的平台,使用这种方法有什么意义?

当您使用这种类型的解决方案时,打开与您的 Google 帐户关联的电子表格,并在该表格中输入以下命令:

GoogleFinance

通过将此命令添加到在线电子表格中的单元格中,您可以检索与所需资产相关的各种类型的数据。所有这些数据都会定期更新,更新之间通常会有延迟。如果你管理的仓位需要几天时间才能发生变化,那么这种延迟实际上并不是问题。对于买入并持有策略来说,这没问题;但如果你进行交易,情况就会变得复杂。

回到正题:您完全配置好在线电子表格之后,就可以保存并导出它以供其他地方使用。这并非真正意义上的导出。你真正想要的是提取 GoogleFinance 函数检索到的值,并将它们传输到另一个电子表格中 —— 这个电子表格就在你的电脑上 —— 这样你就可以舒服地工作了。

虽然这种解决方案适用于许多情况,但不适用于其他情况。在很多情况下,我们实际上需要尽快获得报价(通常只需要报价)。但是,无论您做什么,使用此解决方案都无法实现低于一分钟的更新频率。这可以从图 01 中看到。

图 01

图 01 - 属性窗口

在图 01 中,我们可以看到属性窗口,该窗口设置 Excel 导入组件的更新频率。如果你不知道或者从未见过这种窗口,别担心。我会告诉你如何到达那里。但请注意以下事项:即使您在此处将最小时间设置为一分钟,也不意味着报价本身每分钟都会更新,因为 Google Finance 函数的刷新速度并没有那么快。

所以你必须知道我们在这里做什么。我为您介绍了一种延迟一分钟获取资产报价的方法。如果您的目的是在每次价格变化时更新实时报价,则必须使用与此处所示不同的方法。但这里的解决方案在大多数情况下都能很好地解决各种问题。这是因为你会发现所需的编程非常简单易懂,而且 MetaTrader 5 和 Excel 之间的通信非常有效。


理解实现过程

有一些更复杂的解决方案,例如使用 Python 获取实时报价,还有一些更简单的解决方案,例如使用 RTD 或 DDE。但是这个方案可以直接用 MQL5 开发,易于快速实现,同时又优雅易用。

首先你需要了解的是,MetaTrader 5 有四种基本应用程序类型,它们各自适用于不同的用途。

  • EA 交易:众所周知的 EA 或机器人是 MetaTrader 5 应用程序,允许我们向交易所服务器发送订单或交易请求。这些程序主要就是为这类任务而设计的。
  • 指标:它们允许我们在图表上添加或显示信息。它们用于各种用途,包括价格监控,以显示它们被编程用于的特定内容。
  • 脚本:它们允许我们执行一项任务。它们通常快速进入和退出图表,不会长时间保持活跃。然而,它们总是附在特定的图表上。
  • 服务:与脚本一样,服务通常执行特定的任务,快速启动和停止。但与脚本不同,服务不附加到任何特定的图表上。即使 MetaTrader 5 终端中没有打开图表,它们也会保持活动状态。

您可能已经注意到,MetaTrader 5 中的所有应用程序类型都有其用途。但只有服务独立于平台上打开的任何图表运行,使其成为最佳选择。

请注意:尽管服务和脚本的行为方式不同(因为脚本与图表相关联),但就代码而言,服务和脚本实际上是相同的。唯一区别于它们的是,服务包含以下启用的属性:

#property service

脚本中出现这一行代码,就将其变成了一项服务。

因此,我们将采用的解决方案是创建一个服务。但正如我刚才提到的,您也可以将其用作脚本。然而,在这种情况下,它将与图表挂钩。唯一需要的实际代码更改是删除上面显示的属性。我们稍后在分析代码本身时会再回到这个问题。


开始实现

由于本文的一些读者可能不太熟悉 Excel,我将展示如何在其中执行必要的步骤,至少是基础步骤。如果这不适用于您,您可以跳到下一节,在那里我将解释如何在 MQL5 中实现该服务,以便它可以在 MetaTrader 5 中使用,并将所需的数据直接发送到 Excel。

在执行任何操作之前,您必须编辑一个稍后将由 MetaTrader 5 使用的小文件。但是您不能将此文件放置在系统中的随意位置。出于安全考虑,MQL5 不允许访问计算机文件系统中的随意位置。因此,为了正确操作,您需要打开 MetaEditor,然后在导航窗格中,按照下方动画 01 中所示的步骤进行操作:

动画 01

动画 01 – 访问正确的目录

执行此操作后,操作系统的文件资源管理器将打开,您将进入 MQL5 目录下的 FILES 文件夹。您需要创建的文件最初必须放置在此文件夹中。在其中,创建以下文件,如下所示。这只是我们实际要做的一个例子。

PETR4;
VALE3;
ITUB3;

将此文件保存为 QUOTE.CSV。但不要关闭文件资源管理器,下一步我们需要用到它,以便更容易找到我们刚刚保存的文件。

现在打开 Excel,创建一个空白工作表,然后按照以下步骤将此 QUOTE.CSV 文件链接到我们正在创建的电子表格中。

图 02

图 02

在图 02 中,您可以看到我们需要的选项位于何处。如果它在您的 Excel 版本中不可见,请在 “获取数据” 下查找。在任何情况下,您都必须选择从文本文件导入数据的选项。这类似于从 web 导入数据,但这里我们将使用本地文件。

图 03

图 03

选择图 02 所示的选项后,将打开一个文件浏览器窗口。使用操作系统文件资源管理器导航到前面提到的目录,直到在 MQL5 目录中找到 QUOTE.CSV 文件。找到后,确认您的选择,您将看到图 03 中显示的内容。请注意图 03 顶部显示的文件加载设置。如果一切正确,请单击 “加载” 按钮旁边的箭头,然后选择 “加载到…”然后您将被带到图 04。

图 04

图 04

在图 04 中,您可以选择数据在电子表格中的位置。由于这只是一个演示,请将选择保留在突出显示的区域中。然后单击“确定”,结果将如图 05 所示。

图 05

图 05

好吧,数据已加载。但仍然缺少一件事:告诉 Excel 如何以及何时更新数据。请记住,我们没有使用 RTD 或 DDE 服务器。因此,我们必须明确告诉 Excel 何时刷新这些数据;否则,它们将永远不会更新。如果您具备足够的 VBA 知识,您可以创建更复杂的程序。但在这里,我希望一切都保持简单,这样任何人都可以实现预期的结果。因此,为了让 Excel 知道如何以及何时更新 QUOTE.CSV 中的数据,您需要访问图 06 中显示的内容。

图 06

图 06

在 Excel 中选择表格后,“查询” 选项卡将变为可用状态。在此选项卡中,选择上面显示的 “属性” 元素。点击此元素后,您首先会看到图 07 中所示的内容。

图 07

图 07

仔细观察图 07,在这个窗口中,您必须修改一些设置,以便 Excel 可以自动更新数据。但请注意,正在更新的对象只是我们刚刚根据来自 QUOTE.CSV 的数据创建的表。因此,按照图 08 所示调整图 07 中的设置。

图 08

图 08

单击“确定”确认更改后,Excel 将按照定义的配置进行操作。因此,大约每 60 秒,它将随着文件的变化更新电子表格数据。自己试试:在文本编辑器中打开文件并添加值,如下例所示。

PETR4;30.80
VALE3;190.31
ITUB3;25.89

保存 QUOTE.CSV 文件,但无需关闭文本编辑器。稍等片刻,然后查看 Excel 表格。就像变魔术一样,你会看到电子表格更新为图 09 中所示的内容。

图 09

图片 09

使用文本编辑器再次修改值,直到完全理解发生了什么。请注意,从现在开始,我们可以做很多事情,而无需诉诸复杂或令人费解的解决方案。另一点值得一提的是,您可以使用本地网络共享。这样,Excel 就可以在与 MetaTrader 5 不同的计算机上运行。它们不一定需要在同一台机器上。


在 MQL5 中实现服务

在上一节的解释中,我提到了文件的使用以及必须将其放置在哪里。但现在,为了真正完成本文,我们需要创建将在 MetaTrader 5 中运行的服务。不过不用担心 —— 这里的实现非常简单,创建和使用起来都很容易。在本文的最后,您甚至可以找到一个演示视频,以帮助消除对如何操作该系统的任何疑问。

首先,我必须说,与演示视频中出现的不同,您实际上不需要在市场观察窗口中显示资产。在视频中,显示了资产,以便您可以跟随并查看流程是如何展开的。但在通常情况下,这并非必要。您可以直接运行该服务,它不会干扰市场观察中的资产,也不会影响 MetaTrader 5 的性能。

假设您已经创建了我们需要的文件,如前一节所示,我们可以继续讨论服务代码,了解一切将如何真正发挥作用。完整的服务代码如下所示:

01. //+------------------------------------------------------------------+
02. #property service
03. #property copyright "Daniel Jose"
04. #property description "Quote sharing service between"
05. #property description "MetaTrader 5 and Excel"
06. #property version   "1.00"
07. //+------------------------------------------------------------------+
08. input string user01 = "Quote.csv"; //FileName
09. //+------------------------------------------------------------------+
10. class C_ShareAtExcel
11. {
12.     private :
13.             string  szSymbol[],
14.                     szFileName;
15.             int     maxBuff;
16.             bool    bError;
17. //+------------------------------------------------------------------+
18. inline void Message(const string szMsg)
19.                     {
20.                             PrintFormat("Sharing service with Excel: [%s].", szMsg);
21.                     }
22. //+------------------------------------------------------------------+
23.     public  :
24. //+------------------------------------------------------------------+
25.             C_ShareAtExcel(string szArg)
26.                     :bError(true),
27.                      maxBuff(0),
28.                      szFileName(szArg)
29.                     {
30.                             int     file;
31.                             string  sz0, szRet[];
32.     
33.                             if ((file = FileOpen(szFileName, FILE_CSV | FILE_READ | FILE_ANSI)) == INVALID_HANDLE)
34.                             {
35.                                     Message("Failed");
36.                                     return;
37.                             }
38.                             while (!FileIsEnding(file))
39.                             {
40.                                     sz0 = FileReadString(file);
41.                                     if (StringSplit(sz0, ';', szRet) > 1)
42.                                     {
43.                                             ArrayResize(szSymbol, maxBuff + 1);
44.                                             szSymbol[maxBuff] = szRet[0];
45.                                             StringToUpper(szSymbol[maxBuff]);
46.                                             maxBuff++;
47.                                     }
48.                             }
49.                             FileClose(file);
50.                             bError = false;
51.                             Message("Started");
52.                     }
53. //+------------------------------------------------------------------+
54.             ~C_ShareAtExcel()
55.                     {
56.                             ArrayResize(szSymbol, 0);
57.                             Message("Finished");
58.                     }
59. //+------------------------------------------------------------------+
60.             void Looping(int seconds)
61.                     {
62.                             string  szInfo;
63.                             int     file;
64.                             
65.                             while ((!_StopFlag) && (!bError))
66.                             {
67.                                     szInfo = "";
68.                                     for (int c0 = 0; c0 < maxBuff; c0++)
69.                                             szInfo += StringFormat("%s;%0.2f\r\n", szSymbol[c0], iClose(szSymbol[c0], PERIOD_D1, 0));
70.                                     if ((file = FileOpen(szFileName, FILE_TXT | FILE_WRITE | FILE_ANSI | FILE_SHARE_WRITE)) != INVALID_HANDLE)
71.                                     {
72.                                             FileWriteString(file, szInfo);
73.                                             FileClose(file);
74.                                     };
75.                                     Sleep(seconds * 1000);
76.                             }
77.                     }
78. //+------------------------------------------------------------------+
79. };
80. //+------------------------------------------------------------------+
81. C_ShareAtExcel *share;
82. //+------------------------------------------------------------------+
83. void OnStart()
84. {
85.     share = new C_ShareAtExcel(user01);
86.     
87.     share.Looping(2);
88.     
89.     delete share;
90. }
91. //+------------------------------------------------------------------+

服务源代码

如您所见,代码非常紧凑。但按照我的习惯,我们在这里使用一个类,这样,如果我们将来决定,我们可以将此代码重用于其他目的。但是,您可以完全在一个过程中创建相同的逻辑,并将所有逻辑都放在 OnStart 函数中。

但让我们深入细节并解释代码是如何工作的。这样,即使您刚开始使用 MQL5,您也可以调整它以将其他信息发送到 Excel。请注意:虽然我在这里指的是 Excel,但没有什么能阻止你将数据传输到其他程序或系统。

在第 2 行,我们有一个属性指令,它告诉 MQL5 必须将代码视为服务。如果你想将其用作脚本,只需禁用或删除第 2 行。这样做不会影响代码操作;它只需将脚本附加到图表上即可运行。

在第 8 行,我们为用户提供了定义将使用哪个文件的选项。请记住,必须按照上一节中的说明创建和编辑文件;否则,系统将无法工作。

第 10 行,我们开始定义我们的类。请注意第 12 行,其中声明了一个私有语句。这意味着从那个地方开始,所有内容都将是该类的私有内容,无法从外部访问。然后,我们为类声明一些全局变量,紧接着,在第 18 行,我们创建了一个过程来标准化终端中打印的消息。这些信息表明了服务正在执行的操作。

第 24 行,我们声明一个公有语句。从这个地方开始,类内部的所有内容都可以通过类接口访问。紧接着,在第 26 行,我们开始创建类构造函数。它将接收要使用的文件名作为参数。请注意,编程方式就好像类不是服务代码的一部分一样。这是使用面向对象编程(OOP)的正确方法。即使第 8 行已经有了相关信息,我们却好像没有一样;相反,它是在后面传递的。

现在,在第 33 行,我们尝试打开指定的文件。如果我们无法打开它进行读取,我们会使用第 35 行通知用户,代码将在第 36 行返回。但是,如果可以访问该文件,我们就开始读取它。使用从第 38 行开始的循环逐行读取。第 40 行从文件中读取一整行。在第 41 行,我们将资产交易品种与该行中存在的任何其他信息隔离开来。请注意,我们使用分号 ( ; ) 作为分隔符。

如果第 41 行指示数据有效,我们将在内存中分配一个新位置并将资产交易品种存储在那里。该交易品种不需要大写,因为在第 45 行我们对其进行了规范化。另请注意,没有检查来验证资产交易品种是否实际存在。换句话说,你需要提供一个有效的交易品种。但在这里,这种验证并非绝对必要。如果出错,Excel 会显示异常结果,您可以快速发现并纠正错误。因此,MQL5 中不需要交易品种验证。

如果一切顺利,我们将关闭文件并通知终端该服务已激活 —— 这是在第 51 行完成的。

接下来我们在代码中看到的是类析构函数,它从第 54 行开始。这个析构函数只有两行代码,它释放了分配的内存,并通知系统该类正在从任务列表中删除。

现在,在第 60 行,我们有了程序的主要过程。该过程会使类在循环中运行,直到服务停止为止。循环从第 65 行开始。请注意:此循环的执行方式不会导致处理器或平台过载。在迭代之间,我们会等待一段时间,以便其他任务可以运行。此延迟以秒为单位指定为过程的参数。该参数在第 75 行使用,该行在下一次循环迭代之前有一个暂停。

现在,这个循环中真正的“魔法”就来了。在第67行,我们清除将写入文件的字符串的内容。为了确保写入操作尽可能快地完成 —— 因为它可能恰好发生在 Excel 读取文件的时候(是的,这种情况确实会发生) —— 我们从第 68 行开始执行一个循环。此循环在第 69 行构建要写入 Excel 的数据。此时,您可以设置任何内容,几乎任何内容。

第 68 行的循环结束后,我们尝试在第 70 行访问该文件。注意:通常情况下,当另一个应用程序正在读取文件时,尝试向该文件写入数据会导致访问错误,有些错误会导致数据传输失败。在使用生产者-消费者算法时,这类问题是众所周知的。但幸运的是,MQL5 允许我们使用 FILE_SHARE_WRITE 标志,该标志会通知系统允许同时进行文件访问。

如果成功打开文件进行写入,我们将在第 72 行一次性写入所有内容。然后我们立即在第 73 行关闭文件。

至此,循环就完成了,只要服务运行,循环就会继续下去。


结论

本文介绍了一种非常简单有效的方法,可以将数据从 MetaTrader 5 传输到 Excel。这种方法非常适合那些想要监控投资组合或管理不需要实时更新的交易的人。

在下面的视频中,您可以看到该系统的工作原理,并澄清可能因涉及金融数据使用的细节而产生的任何疑问。由于系统非常简单,文章中的解释足以让任何人使用代码,因此没有附件。一切都将完全取决于您实际打算监控的资产。


本文由MetaQuotes Ltd译自葡萄牙语
原文地址: https://www.mql5.com/pt/articles/11794

附加的文件 |
ShareAtExcel.mq5 (4.03 KB)
最近评论 | 前往讨论 (1)
SuperTaz
SuperTaz | 3 10月 2025 在 17:43

quote.csv" 文件必须保存为 ANSI 编码。

还是不行,还有一个错误有待发现...

使用Python和MQL5进行特征工程(第四部分):基于UMAP回归的K线模式识别 使用Python和MQL5进行特征工程(第四部分):基于UMAP回归的K线模式识别
降维技术被广泛用于提升机器学习模型的性能。让我们来讨论一项被称为“统一流形逼近与投影”的相对较新的技术(UMAP)。这项新技术的开发旨在针对性地克服传统方法在数据中产生伪影和失真的局限性。UMAP是一种强大的降维技术,它能以一种新颖而有效的方式帮助我们将相似的K线进行分组,从而降低在样本外数据上的错误率,并提升我们的交易表现。
交易中的神经网络:具有预测编码的混合交易框架(StockFormer) 交易中的神经网络:具有预测编码的混合交易框架(StockFormer)
在本文中,我们将讨论混合交易系统 StockFormer,其结合了预测编码和强化学习(RL)算法。该框架用到 3 个变换器分支,集成了多样化多头注意力(DMH-Attn)机制,改进了原版的注意力模块,采用多头前馈模块,能够捕捉不同子空间中的多元化时间序列形态。
从基础到中级:模板和类型名称 (五) 从基础到中级:模板和类型名称 (五)
在本文中,我们将探讨模板的最后一个简单用例,并讨论在代码中使用 typename 的好处和必要性。虽然这篇文章乍一看可能有点复杂,但为了以后使用模板和 typename,正确理解它很重要。
让手动回测变得简单:为MQL5策略测试器构建自定义工具包 让手动回测变得简单:为MQL5策略测试器构建自定义工具包
在本文中,我们设计了一个自定义的MQL5工具包,用于在策略测试器中轻松进行手动回测。我们将解释其设计与实现方案,重点介绍交互式交易控制功能。然后,我们将展示如何使用它来有效地测试交易策略。