市场模拟:MQL5 中的 SQL 入门(一)
引言
大家好,欢迎阅读另一篇关于创建复制/模拟系统的文章。
在上一篇文章“市场模拟(第 24 部分):SQL 入门(七)”中,我们完成了我认为最基本的基础知识,这样即使你没有 SQL 经验,至少也能理解我们接下来要做的事情。这是因为我们正在进入复制/模拟系统开发的新阶段,而在此阶段,掌握 SQL 知识将至关重要,这样你才能理解本文以及后续文章的内容。
如果你刚开始学习 SQL,并且仅依赖之前文章中学到的知识,请不要担心。如果正确使用和理解这些材料,它们已经足够解决我们真正需要的许多任务。在第一阶段,我们将继续以 SQLite 为范围,因为它已经集成到 MetaTrader 5 中,这使得使用起来更加方便,无需借助 DLL 甚至套接字。
所以,如果你已经在 MQL5 程序中使用 SQLite,那么这篇文章对你来说并无新意。但如果你才刚刚开始探索这个必须认真对待数据库使用的领域,并且不知道如何用 MQL5 来实现,那么我建议你舒舒服服地坐在椅子上,仔细阅读这篇文章。本文将介绍如何用 MQL5 语言开始操作 SQL 数据库。但是,我们不会使用任何数据库,而是会使用 SQLite。而且,正如你在之前的文章中所见,我们可以在这个系统中做很多事情。所有这些都可以在 MQL5 中轻松实现。
使用 MQL5 创建 SQL 数据库
好的,我们首先需要创建一个数据库。正如我们在之前的文章中所见,这相当简单,并不困难。你可以直接在 MetaEditor 中操作,从命令行操作,或者使用专门用于编辑 SQL 脚本的程序。但我想让你明白,我们并不一定非得按照这种方式来做。它可以通过某种编程语言来实现这一目的。
如果你进行搜索,你会发现许多人用不同的方式、不同的语言来解释同一个过程。但如果你仔细观察,你会发现本质上所有内容都归结为 SQL。而这也是事情变得最有趣的地方。如果你理解了这些原理,你将能够调整用例如 Java 编写的代码,以便在 MQL5 中实现。原因是,最终,真正处理数据和处理记录的是 SQL 代码。Java 只是为特定类型的用户提供了一个更友好的界面。
在 VBA 中,你也会遇到同样的方法,即使用 Excel 来展示直接通过 SQL 获取的数据。因此,理解 SQL 代码的实际工作原理至关重要。最终,我们还是会使用 SQL。作为 SQL 的承载或支撑语言,它只是把 SQL 提供的数据呈现出来。
了解所有事物的真正运作方式,对你日后的工作将大有裨益。因此,让我们从最基本的原则开始:使用 MQL5 创建一个 SQLite 数据库文件。由于我们的目标是尽可能清楚地解释这一点,我们将采用最简单的方法。即使用 MQL5 脚本。这是因为脚本更容易理解,也更容易测试。我们将使用的第一个代码片段如下:
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. #property description "Basic script for SQL database written in MQL5" 04. #property version "1.00" 05. #property script_show_inputs 06. //+------------------------------------------------------------------+ 07. input string user01 = "DataBase01"; //FileName 08. //+------------------------------------------------------------------+ 09. void OnStart() 10. { 11. string szFileName = user01 + ".sqlite"; 12. int handleDB; 13. 14. if ((handleDB = DatabaseOpen(szFileName, DATABASE_OPEN_CREATE | DATABASE_OPEN_READWRITE)) == INVALID_HANDLE) 15. { 16. Print("Unable to create or open the file ", szFileName); 17. return; 18. } 19. DatabaseClose(handleDB); 20. Print("Database file saved successfully.."); 21. } 22. //+------------------------------------------------------------------+
MQL5 的代码
这是打开或创建数据库文件的最简单代码。所有这些都是使用 MQL5 和 SQLite 完成的。请注意,它非常易于理解。在第 07 行,我们允许脚本用户指定需要创建或打开的数据库的名称。请注意,我们没有指定要使用的文件扩展名;我们稍后会指定。所使用的扩展名在第 11 行中指出。请注意,这里我们使用脚本用户提供的名称,并将其与另一个字符串连接起来,在这种情况下,该字符串将是文件名扩展名。
需要注意的是,我们可以使用任何扩展名,但我建议你使用能表明所用文件类型的扩展名。对于 SQL 数据库,最常见的扩展名是 .DB,而对于 SQLite,则是 .sqlite,因为我们可以使用 SQLite 特定的元素。这一点在之前的文章中已经解释过。如果你有任何疑问,可以查阅这些文章以及其中提到的资源,以便更好地理解这个主题。
由于我们将处理文件,所以需要一个句柄。这在第 12 行中有所展示。在第 14 行,我们使用 MQL5 中的 DatabaseOpen 函数来打开甚至创建数据库文件。此时,有一个重要细节需要注意。数据库文件可以在三个不同的位置创建。所有这些都是使用同一个 DatabaseOpen 函数完成的。数据存储位置如下:第一个位置是 RAM,这意味着数据库关闭后将不再存在。这在某些情况下非常有用,但在我们的情况下,至少目前不会使用它。第二个位置,
与第三种情况一样,将取决于传递给 DatabaseOpen 函数的参数。请注意,在所示代码中,我们使用了参数 DATABASE_OPEN_CREATE 和 DATABASE_OPEN_READWRITE 。因此,数据库文件将在 MQL5\Files 文件夹下的某个位置创建。我说“某个位置”,是因为用户指定的名称可能包含有效的目录名称。如果发生这种情况,我们需要进入用户指定的目录。无论如何,由于指定的参数,该目录将位于 MQL5\Files 文件夹内。
但是,如果除了我们在代码中看到的参数之外,我们还添加了参数 DATABASE_OPEN_COMMON ,则此位置可能会有所不同。这将文件夹从 MQL5\Files 更改为 COMMON\Files。“但是 COMMON 文件夹在哪里?我该如何访问它?”这种疑虑很常见。所以,亲爱的读者,如果您不知道这个文件夹在哪里,只需在本地磁盘上找到以下路径即可:
C:\Users\<UserName>\AppData\Roaming\MetaQuotes\Terminal
在这个位置,你会找到 COMMON 文件夹,在其中你会找到 Files 文件夹。请务必将 <UserName> 替换为登录 Windows 的用户的名称。
如果创建或访问指定文件被拒绝,MetaTrader 5 终端将打印第 16 行中的消息。紧接着,在第 17 行,脚本将终止。但如果一切顺利,在第 19 行,我们将关闭数据库文件,并在第 20 行在 MetaTrader 5 终端中打印一条消息,表明所有操作已成功完成。因此,您将能够在 MetaEditor 中打开它,并看到与下图所示类似的内容:

此时,我们可以在 MetaEditor 中使用 SQL。然而,在我们的情况下,我们将从 MQL5 中使用它。尽管如此,为了跟随 MQL5 的操作,您仍然可以使用 MetaEditor,甚至可以使用之前讲解 SQL 时提到的程序。在学习 MQL5 中使用 SQLite 的早期阶段,能够监控操作进度非常重要。基本的 SQL 知识对此非常有用。因此,利用之前文章中的辅助材料可以进一步加快学习进程。我们在这里要做的事情相当有趣。
非常好,既然我们已经知道如何创建或打开 SQL 数据库文件,我们就可以进入下一个阶段了。但首先让我澄清一些可能引起疑虑的事情。当我们说要用 SQL 打开文件、访问数据以及添加或修改记录时,我希望你记住我们将使用 SQLite。这是因为,如果使用 MySQL 或 SQL Server 等其他 SQL 实现来执行我们在这里要做的相同操作,执行方式会有所不同。所以不要混淆。
SQL 语言本身是统一的,但它有多种具体实现,而不同实现支持的能力范围并不完全相同。在此,我们至少在实现的初始阶段将仅使用 SQLite。未来我们可能会改变主意,但若发生这种情况,我们会解释如何从 SQLite 迁移到另一种 SQL 实现。然而,你不应该害怕学习 SQL,因为无论使用它的应用程序或实现方式如何,SQL 语言始终是相同的。
创建最初的几张表
在解释 SQL 命令时,我们将采取非常类似的方法。这是必要的,以便从纯 SQL 编程顺利过渡到嵌入在其他代码中的 SQL。在这种情况下,接收这些命令的代码是 MQL5。幸运的是,MQL5 开发人员做得非常出色,使所有内容都易于理解和使用。因此,我们确实需要学会使用 MQL5 中可用于处理数据库的所有函数中的六个。“那么其他函数就不需要了吗?”不,我并没有这么说。我是说我们需要学会使用六个函数。通过了解如何使用这六个函数并稍微理解 SQL,我们可以完美地处理任何相关情况。至少这适用于使用 MQL5 附带的 SQLite。
如果我们要通过 DLL 使用 SQLite,那么工作方式会略有不同。这是因为在此情况下,我们将直接使用包含在 DLL 文件中的 SQLite 进行调用。因此,如果这是你的具体情况,我建议你研究一下通过 DLL 使用 SQLite 的文档,因为这里的所有内容与我们即将探讨的有所不同。
现在,让我们来看看我们需要学习使用哪些函数。我们已经展示了其中的两个,即 DatabaseOpen 和 DatabaseClose。但是我们还需要 DatabaseExecute、DatabasePrepare、DatabaseReadBind 和 DatabaseFinalize 函数。当然,了解如何使用其他函数在许多情况下会有很大帮助。但有了这六个函数,我们现在可以非常轻松地构建几乎任何东西,当然,前提是我们具备良好的 SQL 编程基础知识。
得益于我们在前几篇文章中介绍的内容,你至少已经能够做一些相当有趣的事情了。当然,你还可以用你自己的方式去做很多人做不到的事情。但是,正如我承诺的那样,我们会循序渐进地进行所有工作,以便每个人都能跟上进度并了解正在发生的事情。
好的,正如你可能在之前的文章中注意到的那样,我们所做的一切都与表有关,所以让我们从这个主题的基础知识开始吧。因此,我们的新脚本如下所示。
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. #property description "Basic script for SQL database written in MQL5" 04. #property version "1.00" 05. #property script_show_inputs 06. //+------------------------------------------------------------------+ 07. input string user01 = "DataBase01"; //FileName 08. //+------------------------------------------------------------------+ 09. void OnStart() 10. { 11. string szFileName = user01 + ".sqlite", 12. szRequestSQL; 13. int handleDB; 14. 15. if ((handleDB = DatabaseOpen(szFileName, DATABASE_OPEN_CREATE | DATABASE_OPEN_READWRITE)) == INVALID_HANDLE) 16. { 17. Print("Unable to create or open the file ", szFileName); 18. return; 19. } 20. szRequestSQL = "CREATE TABLE IF NOT EXISTS tb_Symbol(id PRIMARY KEY, symbol NOT NULL UNIQUE);"; 21. if (!DatabaseExecute(handleDB, szRequestSQL)) 22. { 23. Print("Request execution failed."); 24. DatabaseClose(handleDB); 25. return; 26. } 27. DatabaseClose(handleDB); 28. Print("Database file saved successfully."); 29. } 30. //+------------------------------------------------------------------+
MQL5 的代码
当此脚本在 MetaTrader 5 中运行后,结果如下:

“哇,太棒了。但这是怎么做到的呢?”很简单。我们只是使用了之前文章中讲解 SQL 时所看到的内容。在这里,我们完全使用 MQL5 来完成所有操作。怎么做到的?以上一节中看到的脚本为基础,我们只需在代码中添加几行。但有一点需要注意:这段代码的结构还不正确。在这里,我想向您展示如何完成之前看到过的相同操作。因此,我们添加了第 12 行,这是一个字符串,用于接收我们想要执行的 SQL 命令。在第 20 行,我们指定了这个命令的内容。在本例中,我们要求 SQL 在数据库中创建一个名为 tb_Symbol 的表(如果该表不存在的话)。
紧接着,我们使用 DatabaseExecute 函数,指示 SQLite 执行该 SQL 命令。如果此过程失败,第 23 行的消息将在 MetaTrader 5 终端中打印出来。由于数据库已打开,我们需要将其关闭,这一操作在第 24 行完成。在第 25 行,我们完成了在 MetaTrader 5 中执行脚本的操作。
现在请注意一点。在使用 MetaTrader 5 附带的 SQLite 时,我们想要发送给 SQLite 执行的任何命令都将通过 DatabaseExecute 发送。然而,这仅适用于我们想要发出 SQL 命令的情况。在执行查询时,我们还需要使用其他函数。注意所有内容的组合方式,我们可以开发出我们需要的东西。
因此,在继续处理查询之前,让我们将这个 MQL5 脚本变得更加通用,从而更适合与我们正在创建的数据库一起使用。由于结构可以改变,我们可以将这个相同的脚本转化为一个类。虽然在这个阶段这可能看起来很简单,但它将带来显著的帮助,因为我们将能够使代码更具可重用性,从而更安全、更稳定。然后,我们将之前看到的相同代码转换为如下所示的代码,只是现在使用的是类:
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. #property description "Basic script for SQL database written in MQL5" 04. #property version "1.00" 05. #property script_show_inputs 06. //+------------------------------------------------------------------+ 07. input string user01 = "DataBase01"; //FileName 08. //+------------------------------------------------------------------+ 09. class C_DB_SQLite 10. { 11. private : 12. int m_handleDB; 13. public : 14. //+------------------------------------------------------------------+ 15. C_DB_SQLite(const string szFileName) 16. :m_handleDB(INVALID_HANDLE) 17. { 18. if ((m_handleDB = DatabaseOpen(szFileName, DATABASE_OPEN_CREATE | DATABASE_OPEN_READWRITE)) == INVALID_HANDLE) 19. { 20. Print("Unable to create or open the file ", szFileName); 21. return; 22. } 23. } 24. //+------------------------------------------------------------------+ 25. ~C_DB_SQLite() 26. { 27. DatabaseClose(m_handleDB); 28. Print("Closing Database..."); 29. } 30. //+------------------------------------------------------------------+ 31. bool Command(const string szRequestSQL) 32. { 33. bool ret = DatabaseExecute(m_handleDB, szRequestSQL); 34. Print("Request execution: ", (ret ? "Success" : "Failed"), "..."); 35. return ret; 36. } 37. //+------------------------------------------------------------------+ 38. }; 39. //+------------------------------------------------------------------+ 40. void OnStart() 41. { 42. C_DB_SQLite *DB; 43. 44. DB = new C_DB_SQLite(user01 + ".sqlite"); 45. 46. (*DB).Command("CREATE TABLE IF NOT EXISTS tb_Symbol(id PRIMARY KEY, symbol NOT NULL UNIQUE);"); 47. 48. delete DB; 49. } 50. //+------------------------------------------------------------------+
MQL5 的代码
请注意,现在我们在处理数据库时,结构要复杂得多。这是因为,无论我们要做什么,每当我们向数据库发送命令时,无论我们打开的是一个数据库还是数十个数据库,我们都会将命令发送到正确的数据库。命令总是会发送到正确的数据库。这是因为现在函数是在第 9 行到第 38 行之间创建的类内部使用的,而这仅仅是个开始。尽管如此,我们已经拥有了该类为我们提供的所有安全性。
例如,如果句柄尚未初始化,我们就不能使用它。由于初始化是通过类构造函数来执行的,所以我们能确保始终使用有效的句柄。这一点可以从第 33 行看出,我们使用该句柄向 SQL 发送命令。
现在请大家注意以下几点:许多人可能会认为,使用甚至创建一个类来封装与 SQLite 的通信系统有些过分,但让我们稍微思考一下,也许这会改变你的想法。你可能会想:“为什么我要专门创建一个类来使用MetaTrader 5中包含的SQLite?直接使用 MQL5 函数要容易得多。尤其是我不会在程序中大量使用 SQL。”从这个角度来看,我同意你的观点,但让我们从更广泛的角度来考虑这个问题。MQL5 使我们能够轻松简单地访问 MetaTrader 5 内置的 SQLite。这很好。但我们不应局限于此。
如果我们开发了一系列应用程序,甚至是一个使用 MetaTrader 5 内置 SQLite 的系统,并且同时只使用 MQL5 函数,那么在某个时候,我们将只能且仅限于使用 MetaTrader 5 中的 SQLite。我们将无法在 DLL 文件中使用我们自己的 SQLite 构建。最糟糕的是,如果我们在某个时候决定使用另一种 SQL 实现,无论是 MySQL、SQL Server 还是其他任何一种,我们都将需要大量的工作来重写所有代码,以满足必要的依赖性。这是因为我们仅提到的 MySQL 和 SQL Server 并不使用可通过 MQL5 访问的文件系统。我们甚至可以使用 MQL5,但为此我们必须使用另一种工具,其应用在本系列中我们已经展示过。我们说的是套接字。
换句话说,要访问采用客户端-服务器架构的数据库,我们必须使用套接字。如果我们的实现从一开始就设计了一个类系统来隐藏实现细节,那么我们只需修改这个类,对其进行扩展或调整,使其能够通过套接字提供必要的通信支持。这大大简化了整个开发过程。因为如果我们需要通过将 MetaTrader 5 中使用的 SQLite 替换为我们自己编译成 DLL 的 SQLite 来更改 SQL 实现,这将很容易做到。
当我们需要更改实现方式时,情况也是如此。当从基于文件的 SQLite 迁移到客户端-服务器 SQL 时,我们不会遇到重大问题。只需简单地更改类的实现方式,其余代码就会从这些更改中受益。就这么简单。因此,不要低估开发应用程序时所预期的未来工作方式可能发生变化所带来的优势。请记住:技术会随着时间而改变。创建一个与某事物紧密绑定或不可分割的实现并不是最佳选择。
理解一些要点
在继续之前,我想给你看点东西,因为对你来说理解它非常重要。让我们执行以下操作。在之前的文章中,我们创建了表之间的关系来构建关系数据库。我们解释了如何做到这一点,以及根据关系模型构建数据库的这种方式的优缺点。但是,当我们通过 MetaTrader 5 内置的 SQLite 处理大量 SQL 命令时,我们需要采取一些预防措施。或者,更准确地说,我们需要想出一种让操作更安全的方法。
我们将要展示的内容将迫使我们在下一篇文章中做出一些决定。请仔细研究以下 MQL5 代码:
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. #property description "Basic script for SQL database written in MQL5" 04. #property version "1.00" 05. #property script_show_inputs 06. //+------------------------------------------------------------------+ 07. input string user01 = "DataBase01"; //FileName 08. //+------------------------------------------------------------------+ 09. class C_DB_SQLite 10. { 11. private : 12. int m_handleDB; 13. public : 14. //+------------------------------------------------------------------+ 15. C_DB_SQLite(const string szFileName) 16. :m_handleDB(INVALID_HANDLE) 17. { 18. if ((m_handleDB = DatabaseOpen(szFileName, DATABASE_OPEN_CREATE | DATABASE_OPEN_READWRITE)) == INVALID_HANDLE) 19. { 20. Print("Unable to create or open the file ", szFileName); 21. return; 22. } 23. } 24. //+------------------------------------------------------------------+ 25. ~C_DB_SQLite() 26. { 27. DatabaseClose(m_handleDB); 28. Print("Closing Database..."); 29. } 30. //+------------------------------------------------------------------+ 31. bool Command(const string szRequestSQL) 32. { 33. bool ret = DatabaseExecute(m_handleDB, szRequestSQL); 34. Print("Request execution: ", (ret ? "Success" : "Failed"), "..."); 35. return ret; 36. } 37. //+------------------------------------------------------------------+ 38. }; 39. //+------------------------------------------------------------------+ 40. void OnStart() 41. { 42. C_DB_SQLite *DB; 43. 44. DB = new C_DB_SQLite(user01 + ".sqlite"); 45. 46. (*DB).Command("PRAGMA FOREIGN_KEYS = ON;"); 47. (*DB).Command("CREATE TABLE IF NOT EXISTS tb_Symbols" 48. "(" 49. "id PRIMARY KEY," 50. "symbol NOT NULL UNIQUE" 51. ");"); 52. (*DB).Command("CREATE TABLE IF NOT EXISTS tb_Quotes" 53. "(" 54. "of_day NOT NULL," 55. "price NOT NULL," 56. "fk_id NOT NULL," 57. "FOREIGN KEY (fk_id) REFERENCES tb_Symbols(id)" 58. ");"); 59. delete DB; 60. } 61. //+------------------------------------------------------------------+
MQL5 的代码
注意 MQL5 代码中命令的排列方式。这是执行 SQL 命令所必需的。经常发生这样的情况,在写了很多东西之后,我们最终会犯某种错误。现在请看下面的脚本:
01. PRAGMA FOREIGN_KEYS = ON; 02. 03. CREATE TABLE IF NOT EXISTS tb_Symbols 04. ( 05. id PRIMARY KEY, 06. symbol NOT NULL UNIQUE 07. ); 08. 09. CREATE TABLE IF NOT EXISTS tb_Quotes 10. ( 11. of_day NOT NULL, 12. price NOT NULL, 13. fk_id NOT NULL, 14. FOREIGN KEY (fk_id) REFERENCES tb_Symbols(id) 15. );
SQLite 代码
将此脚本与上一个脚本进行比较。请注意,尽管后者使用的是纯 SQL,并且其语法可以在编写时进行分析,但当我们将字符串直接插入 MQL5 代码时,我们无法实现同样的可能性。这就是 MQL5 与 MetaTrader 5 内置的 SQLite 引擎交互的机制。也就是说,如果我们在 MQL5 代码中的字符串内编写 SQL 代码时出现拼写错误,SQL 将无法正确执行我们的代码。因此,我们可能会归咎于 MQL5 甚至 MetaTrader 5,这将是一个很大的错误。然而,应该注意的是,在这两个版本的代码中,我们都创建了一个包含相关表的数据库。如果偶然在某个时候我们将表名 “tb_Symbols” 写成了 “tb_Symbol”,那么结果将与下图所示完全不同:

请注意,如果我们尝试在 MetaEditor 中查看与上图所示的相同结构,我们将无法成功。我们在另一篇文章中已经讨论过这个问题了。如果您不明白这里发生了什么,我建议您阅读我们解释 SQL 以及如何获取更有效地使用 SQL 系统所需的程序的文章。
但我在这里想要强调的重点正是这一点。在字符串中查看 SQL 代码时,可能存在不易察觉的错误。但是,如果我们使用能够分析 SQL 代码的编辑器,查找这些错误就会容易得多,如下所示:

需要注意的是,在独立的 SQL 脚本中发现错误要容易得多。正如我之前所说,作为程序员,出现笔误并不少见。因此,使用合适的工具可以节省大量时间来弄清楚为什么某个特定的代码片段能够运行或不能运行。大多数情况下,错误仅仅是在输入命令时出现的拼写错误。
最后的想法
在今天的文章中,我们开始研究在 MQL5 代码中使用 SQL。我们研究了如何创建数据库。或者更准确地说,如何使用 MQL5 内置的功能来创建 SQLite 数据库文件。我们还研究了如何创建表,以及如何通过使用主键和外键来建立表之间的关系。所有这些同样都是借助 MQL5 完成的。我们看到,通过使用一个类来隐藏正在创建的实现,创建可以稍后迁移到其他 SQL 实现的代码是多么容易。
最重要的是:我们确保在使用 SQL 时,各个阶段都存在出现问题风险。这是因为,在 MQL5 代码中,SQL 代码会被放置在字符串值内。这会显著增加出错的可能性,例如因笔误而导致 MQL5 中的 SQL 代码执行失败。然而,我们能够并且将会创建一种机制,该机制不仅赋予我们更多自由,还能帮助我们避免这些问题,因为市面上还有专门用于提升 SQL 脚本可读性的编辑器。
因此,在下一篇文章中,我们将创建一个机制,使这种可移植性更容易实现。许多有经验的人可能已经猜到这是什么意思了。但如果情况并非如此,也不用担心;我们将在下一篇文章中探讨如何做到这一点。我们将继续在 SQL 领域开展工作,只是现在将使用 MQL5 作为执行的基础。这是必要的,这样 MetaTrader 5 才能允许我们的复制/模拟系统开始在其工作中使用数据库。所以继续学习吧,我们下篇文章再见,到时候一切都会更加精彩。
| 文件 | 描述 |
|---|---|
| Experts\Expert Advisor.mq5 | 演示 Chart Trade 与 EA 之间的交互(交互需要 Mouse Study)。 |
| Indicators\Chart Trade.mq5 | 创建一个窗口,用于配置待发送的委托(需要 Mouse Study 才能进行交互) |
| Indicators\Market Replay.mq5 | 创建用于与复制/模拟服务交互的控件(交互需要 Mouse Study)。 |
| Indicators\Mouse Study.mq5 | 提供图形控件与用户之间的交互(对于复制/模拟系统和真实市场都是必要的)。 |
| Services\Market Replay.mq5 | 创建并维护市场复制/模拟服务(整个系统的主文件)。 |
| Code VS C++\Servidor.cpp | 创建并维护用 C++ 开发的服务器套接字(MiniChat 版本)。 |
| Code in Python\Server.py | 在 Python 中创建并维护一个套接字,用于 MetaTrader 5 和 Excel 之间的通信。 |
| Indicators\Mini Chat.mq5 | 允许通过指标实现迷你聊天(运行需要服务器)。 |
| Experts\Mini Chat.mq5 | 允许使用 EA 实现迷你聊天(运行需要服务器)。 |
| Scripts\SQLite.mq5 | 演示如何通过 MQL5 使用 SQL 脚本。 |
| Files\Script 01.sql | 演示如何创建带有外键的简单表。 |
| Files\Script 02.sql | 演示向表中插入值。 |
本文由MetaQuotes Ltd译自葡萄牙语
原文地址: https://www.mql5.com/pt/articles/13062
注意: MetaQuotes Ltd.将保留所有关于这些材料的权利。全部或部分复制或者转载这些材料将被禁止。
本文由网站的一位用户撰写,反映了他们的个人观点。MetaQuotes Ltd 不对所提供信息的准确性负责,也不对因使用所述解决方案、策略或建议而产生的任何后果负责。
交易中的神经网络:自适应周期分段(结论)
MQL5 自优化 EA(第12部分):利用矩阵分解构建线性分类器
市场模拟(第 22 部分):SQL 入门(五)