English Русский Español Português
preview
从基础到中级:结构(三)

从基础到中级:结构(三)

MetaTrader 5示例 |
38 0
CODE X
CODE X

概述

在上一篇文章“从基础到中级:指标(四)”中,我们用简单明了的方式展示了如何做一件对很多初学者来说非常困难的事情。现在,每个人都知道一个简单易行的方法,可以将自己的想法变为现实。目标在于创建一个指标,该指标能够通过颜色来展示特定的交易系统。当然,我们在那里展示了如何实现内含线模式。但这一知识可应用于任何蜡烛图颜色模式指示(或不指示)交易机会的模式。

嗯,这很有意思。然而,我认为我们可以探讨另一个问题,在我看来,这个问题也相当有趣。我们在上一篇文章的结尾就开始考虑这个问题了。但在继续讨论本文将探讨的主题之前,我们需要先做一个简短的回顾。

在有关结构的文章中,尤其是在网站上的“从基础到中级:结构(二)”中,我们解释了如何使用结构来创建记录块。在那两篇文章中,我们提到结构是一种特殊的数据类型,你可以在其中以逻辑且简化的方式放置各种信息。然而,由于我们之前没有展示过其他内容,因此深入探讨结构的细节会变得困难,甚至没有必要。但是,前一篇文章已经为我们深入探讨其他问题打下了充分的基础。从本质上讲,我们现在想要证明结构不仅可以用于组织记录数据。

所以,在简短介绍之后,我们终于可以开始讨论正题,并着手理解使用类的原因了。为此,我们将从该问题的第一个主题开始。


结构化代码

最让我感到沮丧的,或许就是看到代码中所有内容都纠缠不清。在老式 BASIC 盛行的年代,编写没有预定义结构的代码是有一定逻辑的。这是由语言的本质决定的。在像 BATCH 这样的语言中,比如基于脚本的批处理语言(例如 SQL),从某种意义上说,我们可能没有一个非常明确的结构。毕竟,在大多数情况下,需要执行的任务相对简单,代码也是如此,通常都很短。

然而,当我们转向具有更深层次目标的语言时,一切都会变得更加复杂,MQL5 就是这种情况。在这种情况下,我们通常有一个目标,仅凭几行代码很难实现,即使使用头文件来隐藏大部分复杂性也是如此。但编程的某些方面确实让人感到乏味和厌倦。其中之一是,初级程序员倾向于重复那些本可以更好地组织的代码片段。

当我说到结构化代码时,我并不是指使用函数或过程来保持代码中的某种结构。在这种情况下,我的意思是将代码嵌入到结构中,以便于其维护和处理。许多编程导师认为,在代码中使用函数和过程就已经使代码结构化了。但这并不一定意味着代码是结构化的。它只是组织得更好,仅此而已。

为了实现真正结构化的代码,我们需要使用许多人认为疯狂或至少过于复杂的方法和概念。其中一个工具就是类。但现在还不是讨论类的时候,因为类的出现并不是因为程序员们某天醒来突然想到:“我们要创造一种东西,让所有刚起步的程序员都举步维艰。那样我们就能成为最酷的程序员了。”不,类的出现是为了解决创建真正结构化代码的问题。

为了理解这一局限性,我们需要深入研究更复杂的问题。所以,做好准备吧,因为从现在开始,事情会变得非常有趣,甚至会变得很有趣。

也许你正带着些许怀疑地看着我,不明白我想展示什么。但别担心,我们会一步步来,因为让你理解我们的意图是极其重要的。否则,你将会对我们即将建模以实现面向对象编程的内容感到困惑。

在上一篇文章中,我们看到了以下代码:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. input bool user01 = true;       //Show time scale
05. input bool user02 = true;       //Show price scale
06. //+----------------+
07. struct st_Mem
08. {
09.     long    View_DateScale,
10.             View_PriceScale;
11. }gl_StyleGraphic;
12. //+------------------------------------------------------------------+
13. int OnInit()
14. {
15.     gl_StyleGraphic.View_DateScale = ChartGetInteger(0, CHART_SHOW_DATE_SCALE);
16.     gl_StyleGraphic.View_PriceScale = ChartGetInteger(0, CHART_SHOW_PRICE_SCALE);
17. 
18.     ChartSetInteger(0, CHART_SHOW_DATE_SCALE, user01);
19.     ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, user02);
20. 
21.     return INIT_SUCCEEDED;
22. };
23. //+------------------------------------------------------------------+
24. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
25. {
26.     return rates_total;
27. };
28. //+------------------------------------------------------------------+
29. void OnDeinit(const int reason)
30. {
31.     ChartSetInteger(0, CHART_SHOW_DATE_SCALE, gl_StyleGraphic.View_DateScale);
32.     ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, gl_StyleGraphic.View_PriceScale);
33.     ChartRedraw();
34. };
35. //+------------------------------------------------------------------+

代码 01

这段代码很简单。但是,如果您真的很好奇,您可以研究图表属性,尝试直接通过代码创建和管理其外观。如果你能做到这一点,那么我向你表示祝贺,因为这是未来想要成为优秀专业人士的必要条件之一。

然而,尽管这段代码看似简单,许多人仍认为它是结构化的代码。在我看来,我们在代码 01 中看到的并不是结构化的代码,而是组织良好的代码。尽管它很简单,但在我看来,它并不是解释结构化代码的理想代码。为此,我们将转向更简单的东西:脚本。这是因为脚本只响应 Start 事件。该事件结束后,代码即终止。没有比这更简单了

好的,让我们从下面显示的代码开始。

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     struct st_Mem
07.     {
08.         long    View_DateScale,
09.                 View_PriceScale;
10.     }StyleGraphic;
11. 
12.     StyleGraphic.View_DateScale = ChartGetInteger(0, CHART_SHOW_DATE_SCALE);
13.     StyleGraphic.View_PriceScale = ChartGetInteger(0, CHART_SHOW_PRICE_SCALE);
14. 
15.     ChartSetInteger(0, CHART_SHOW_DATE_SCALE, false);
16.     ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, false);
17.     ChartRedraw();
18. 
19.     Sleep(2000);
20. 
21.     ChartSetInteger(0, CHART_SHOW_DATE_SCALE, StyleGraphic.View_DateScale);
22.     ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, StyleGraphic.View_PriceScale);
23.     ChartRedraw();
24. }
25. //+------------------------------------------------------------------+

代码 02

这段代码比图 01 中的代码要简单得多,并且其目的相同:隐藏价格和时间刻度,然后再替换它们。在图表上运行此脚本,您将看到类似于下方动画的效果:

动画 01

如你所见,一切都很简单:第 19 行代码负责让刻度暂时消失。在配置中,我们指定在再次执行代码之前暂停大约两秒钟。但是,我希望你们注意两点:第 17 行和第 23 行。在上一篇文章中,我解释了为何应在代码中使用此命令。但在这里我们使用的是脚本,超时时间很短,所以上述两行中出现的这个命令非常重要。如果没有它,我们可能就不会看到价格和时间刻度隐藏和重新出现。

好吧,到目前为止,一切都很好。但在我看来,代码 02 并不是结构化代码,尽管在第 06 行我们声明了一个结构。那么,让我们开始编写许多人认为结构化的代码。为此,我们将把代码 02 修改为如下所示的版本:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. struct st_Mem
05. {
06.     long    View_DateScale,
07.             View_PriceScale;
08. };
09. //+------------------------------------------------------------------+
10. void OnStart(void)
11. {
12.     st_Mem StyleGraphic;
13. 
14.     StyleGraphic = SAVE();
15. 
16.     ChartSetInteger(0, CHART_SHOW_DATE_SCALE, false);
17.     ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, false);
18.     ChartRedraw();
19. 
20.     Sleep(2000);
21.     
22.     RESTORE(StyleGraphic);
23. }
24. //+------------------------------------------------------------------+
25. st_Mem SAVE(void)
26. {
27.     st_Mem local;
28. 
29.     local.View_DateScale = ChartGetInteger(0, CHART_SHOW_DATE_SCALE);
30.     local.View_PriceScale = ChartGetInteger(0, CHART_SHOW_PRICE_SCALE);
31. 
32.     return local;
33. }
34. //+------------------------------------------------------------------+
35. void RESTORE(const st_Mem &arg)
36. {
37.     ChartSetInteger(0, CHART_SHOW_DATE_SCALE, arg.View_DateScale);
38.     ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, arg.View_PriceScale);
39. 
40.     ChartRedraw();
41. }
42. //+------------------------------------------------------------------+

代码 03

代码 03 将产生与动画 01 相同的结果,但略有不同。与代码 02 不同,这里的组织结构更为清晰,因为我们可以在不同的时间使用第 25 行的函数,也可以随时使用第 35 行的过程。我们在代码 03 中可以看到,这种建模和实现方式的主要优势在于,我们可以保存和恢复所有图表属性值,而无需担心哪些值会被更改。这避免了创建大量总是包含同一种代码的代码行。

但这种方法存在一个小问题,在代码 03 中可以明显看出。问题如下:我们正在处理一个包含数据的结构。到目前为止,一切都很好。但如果目标是直接处理结构中的数据,那么在第 25 行实现一个函数和在第 35 行实现一个过程又有什么意义呢?

起初,初学者或经验丰富的程序员并不会觉得这有什么困扰,尤其是在处理简单代码时,但当我们开始处理更复杂的代码时,这就会变成一个真正的难题。这是因为我们开始将那些在我们所使用的数据上下文之外看似不合理的内容纳入考虑。

代码 03 非常有助于解释这一点,并且能帮助你,我亲爱的读者,理解我们即将要做的事情的概念。请注意以下事项:我们有一个结构,可以在代码中的多个不同位置使用。这个结构的目的是存储和恢复图表在特定时刻的状态。因此,我们可以按照上述代码进行实现。

但是随着我们创建新元素,SAVE 函数和 RESTORE 过程开始变得脱离上下文。我们可能还需要创建另一个函数和过程,它们的名称完全相同,但目的却与保存和恢复图表属性不同。在那种情况下,我们可以使用重载,但这会毫无必要地使代码变得复杂。而正是在这一刻,问题出现了:代码是否结构化。

在结构化代码中,SAVE 和 RESTORE 函数将不再像我们在代码 03 中看到的那样声明,因为它们没有正确地与第 04 行定义的结构上下文相关联,而是将在该结构的上下文中声明,或者更确切地说,是在该结构的上下文中实现。由于这无法通过片段来展示,我们将直接转向其他代码中讨论的解决方案,只不过现在是在一个完全结构化的模型中。这可以在下面的代码中看到:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. struct st_PropertyGraphics
05. {
06.     long    View_DateScale,
07.             View_PriceScale;
08. //+----------------+
09.     void SAVE(void)
10.     {
11.         View_DateScale = ChartGetInteger(0, CHART_SHOW_DATE_SCALE);
12.         View_PriceScale = ChartGetInteger(0, CHART_SHOW_PRICE_SCALE);
13.     }
14. //+----------------+
15.     void RESTORE(void)
16.     {
17.         ChartSetInteger(0, CHART_SHOW_DATE_SCALE, View_DateScale);
18.         ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, View_PriceScale);
19. 
20.         ChartRedraw();
21.     }
22. //+----------------+
23. };
24. //+------------------------------------------------------------------+
25. void OnStart(void)
26. {
27.     st_PropertyGraphics StyleGraphic;
28. 
29.     StyleGraphic.SAVE();
30. 
31.     ChartSetInteger(0, CHART_SHOW_DATE_SCALE, false);
32.     ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, false);
33.     ChartRedraw();
34. 
35.     Sleep(2000);
36.     
37.     StyleGraphic.RESTORE();
38. }
39. //+------------------------------------------------------------------+

代码 04

“哇!真是一团糟。现在我的大脑已经快疯了,因为据我所知,结构是一种特殊的变量,可以被组织起来创建记录的小型数据库。但在代码 04 中看到的内容,我完全看不懂。”

嗯,我们刚刚提高了标准。那些没有练习和研究现在所展示内容的人将无法取得进步,因为从现在开始,可能性会迅速增加,呈指数级增长。不过,无需担心代码 04。我尽量让所有内容都尽可能具有教育性,以避免解释的必要性,从而将注意力集中在更有趣的事情上。

那么,让我们来看看代码 04 中发生了什么。首先,代码 04 的工作方式与我们上面回顾的其他代码一样。但在这里我们有一个优势,因为现在用于存储图形属性的相同程序和功能,将始终位于包含这些数据的结构上下文中。这就是我们所说的结构化编程。

目前,我们将忽略第 04 行定义的结构,而重点关注 OnStart 事件处理函数。在第 27 行,我们像之前一样声明了结构,这意味着创建我们的变量或特殊记录的方式将完全相同。但请注意第 29 行和第 37 行。看到这些代码行,你想到了什么?你可能在想:“嗯,在第 29 行,我请求保存某些内容,在第 37 行,我请求恢复某些内容。”如果你这么想,那我们就是走在正确的路上了。

再来看这些相同的行:我们要求保存和恢复的是什么?正是我们在第 27 行声明的变量。有趣,让我们来分析一下。第 27 行,我们声明一个变量。当执行第 29 行时,它请求保存同一个变量。好的,既然这个变量是图形属性记录类型的,

因此,在第 29 行,我们请求保存图形属性。这样,在第 31 行和第 32 行中,我们就可以修改属性,而不必担心可能带来的变化。“太好了,情况似乎越来越清楚了。执行第 37 行时,我们请求恢复那些已保存的属性,从而放弃第 29 行到第 37 行之间所做的所有更改。就是这样吗?我对 OnStart 事件处理程序中所做的操作理解正确吗?”是的,亲爱的读者们,你们的猜测确实相当准确。

“太好了!但我现在有些怀疑。对比代码 03 和代码 04,我注意到,关于 SAVE 和 RESTORE 过程,这里的声明方式有所不同。为什么这两个代码之间会有如此大的差异?因为原则上,两者具有相同的目标类型和行为。我还是不明白。”

我很高兴你注意到了这一点,因为现在,由于你对 OnStart 代码的理解,是时候解释第 04 行声明的结构代码了。所以,这次我希望你忽略代码 04 中的其他所有内容,只关注结构块。

请注意,为了简化流程,我更改了结构的名称。不过,你可以用任何你喜欢的名字。重要的是,这个结构是全局性的。它甚至可能存在于头文件中。但就目前而言,我们不必为此担心。只需注意将要解释的内容。

请注意,我们保留了与之前代码中相同的变量。这些变量仍然可以访问,并且功能完好,就像在代码 03 中一样。你甚至可以继续使用它们,不过我们以后再谈这个。重要的是子程序内部发生了什么。在本例中,第 09 行是 SAVE 过程,第15行是 RESTORE 过程。请注意,它们与代码 03 中的非常相似。

但有趣的是:如代码 03 所示,变量 View_DateScale 和 View_PriceScale 不再需要声明。原因在于,这些变量是编译器和程序员上下文的一部分。在这种情况下,上下文正是 st_PropertyGraphics 结构。

也就是说,由于我们是在结构中有意义的上下文中工作,因此无需像代码 03(第 29、30、37 和 38 行)那样声明变量,因为我们需要指定变量将关联的数据类型,因为在代码 03 中,SAVE 和 RESTORE 子例程都不属于结构的上下文。这在代码 04 中不再有意义,因为这两个子程序都属于该结构。

这就是我们所说的结构化编程,因为现在我们可以在完整的上下文中处理元素,而无需表示它们或通读所有代码来理解正在发生的事情。

请随意修改和尝试这段代码,以便真正理解其中的运作原理。但在结束这篇文章之前,我想展示点别的内容,这次用的是另一段代码。但由于这与其它问题相关,我们将在新的主题中对其进行讨论。


对结构进行简单操作

在上一主题中,我们讨论了如何通过创建结构化代码来获得代码上下文。尽管它很美,但还是有几点值得考虑。当然,正是由于这种“照护需求”,才产生了设立类的必要性。不过,我们下次再聊这个吧。现在,让我们来看看其中的一些“担忧”。

首先,在一个结构中,所有数据都遵循一个非常简单的准则:它可以是公有的,也可以是私有的。通常,在声明一个简单结构时,我们总是使用公有数据。但是,当我们进行结构化编程时,我们不想公开数据。在这种情况下,我们希望确保数据在其整个生命周期中保持完整和安全。

为了确保这种完整性,我们可以更改数据的访问类型。现在,请注意。我们将在这里看到的内容不应该用于简单的结构中,例如上面所示的结构。仅在实现结构化代码并希望对其操作有更多控制的情况下使用此方法。如果你缺乏必要的知识,那么使用这里展示的内容会使原本相当简单的事情变得复杂。

为了更准确地解释这一点,让我们来看一个简单的代码示例,但这个示例要与我们当前想要解释的内容相契合。如下所示:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. struct st_PropertyGraphics
05. {
06.     long    View_DateScale,
07.             View_PriceScale,
08.             Chart_Mode;
09. //+----------------+
10.     void SAVE(void)
11.     {
12.         View_DateScale = ChartGetInteger(0, CHART_SHOW_DATE_SCALE);
13.         View_PriceScale = ChartGetInteger(0, CHART_SHOW_PRICE_SCALE);
14.         Chart_Mode = ChartGetInteger(0, CHART_MODE);
15.     }
16. //+----------------+
17.     void RESTORE(void)
18.     {
19.         ChartSetInteger(0, CHART_SHOW_DATE_SCALE, View_DateScale);
20.         ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, View_PriceScale);
21.         ChartSetInteger(0, CHART_MODE, Chart_Mode);
22. 
23.         ChartRedraw();
24.     }
25. //+----------------+
26. };
27. //+------------------------------------------------------------------+
28. void OnStart(void)
29. {
30.     st_PropertyGraphics StyleGraphic;
31. 
32.     StyleGraphic.SAVE();
33. 
34.     StyleGraphic.Chart_Mode = CHART_LINE;
35. 
36.     ChartSetInteger(0, CHART_SHOW_DATE_SCALE, false);
37.     ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, false);
38.     ChartSetInteger(0, CHART_MODE, CHART_BARS);
39.     ChartRedraw();
40. 
41.     Sleep(2000);
42.     
43.     StyleGraphic.RESTORE();
44. }
45. //+------------------------------------------------------------------+

代码 05

请注意,代码 05 与代码 04 非常相似。然而,为了展示我们想要呈现的内容,我们为该结构增加了一个新的图形属性。该属性在代码 05 的第 08 行声明。请注意,SAVE 和 RESTORE 过程中也同时添加了新的代码行。这些更改并不很大,无需详细解释。OnStart 过程也进行了一些细微的更改,这些更改很简单,不需要详细解释。然而,当我们在图表上运行此脚本时,我们会看到类似以下的内容:

动画 02

“哇!让我们停下来,倒带一下,因为我们刚刚得到了一个意外的结果,而且我想弄清楚,既然我们遵循的原则和理念与代码 04 中的相同,为什么图表没有恢复到原始状态。但是,我认为错误可能出在我们刚刚添加的新属性上。”好了,差不多就是这样了。但问题其实并不完全在于此。这个问题被称为数据泄漏或封装破坏 —— 即正在进行一些以前无法做到的事情。这正是导致动画 02 中所示结果的原因。

请注意,第 32 行保存图形属性,第 43 行恢复它们,与代码 04 完全一样。但问题出在这里:第 34 行。“我不觉得这有什么问题。或许如果我们把那一行删掉,一切就会恢复正常?”是的,如果我们删除第 34 行,一切都会迎刃而解。但这不是关键。

问题是数据是如何存储在变量 StyleGraphics 中的。该变量直接与位于第 06 行和第 08 行之间的小型记录数据库相关联。我们对这些记录所做的任何更改都会影响 StyleGraphics 变量的内容。

因此,当我们在第 43 行请求数据恢复时,将使用日志中的所有数据。然而,由于第 34 行的更改,原始记录丢失了。因此,我们现在得到的一个值与之前保存的值不同,并且该值正在被应用于图表,导致图表被错误的信息重置。

这个问题非常严重,同时也很常见。为了解决这个问题,我们必须改变结构中声明值的条件。请记住,默认情况下,所有值都是公有的。但如果我们将代码 05 更改为如下所示的代码,一切都将不同:

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. struct st_PropertyGraphics
05. {
06.     private:
07. //+----------------+
08.         long    View_DateScale,
09.                 View_PriceScale,
10.                 Chart_Mode;
11. //+----------------+
12.     public:
13. //+----------------+
14.         void SAVE(void)
15.         {
16.             View_DateScale = ChartGetInteger(0, CHART_SHOW_DATE_SCALE);
17.             View_PriceScale = ChartGetInteger(0, CHART_SHOW_PRICE_SCALE);
18.             Chart_Mode = ChartGetInteger(0, CHART_MODE);
19.         }
20. //+----------------+
21.         void RESTORE(void)
22.         {
23.             ChartSetInteger(0, CHART_SHOW_DATE_SCALE, View_DateScale);
24.             ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, View_PriceScale);
25.             ChartSetInteger(0, CHART_MODE, Chart_Mode);
26. 
27.             ChartRedraw();
28.         }
29. //+----------------+
30. };
31. //+------------------------------------------------------------------+
32. void OnStart(void)
33. {
34.     st_PropertyGraphics StyleGraphic;
35. 
36.     StyleGraphic.SAVE();
37. 
38.     StyleGraphic.Chart_Mode = CHART_LINE;
39. 
40.     ChartSetInteger(0, CHART_SHOW_DATE_SCALE, false);
41.     ChartSetInteger(0, CHART_SHOW_PRICE_SCALE, false);
42.     ChartSetInteger(0, CHART_MODE, CHART_BARS);
43.     ChartRedraw();
44. 
45.     Sleep(2000);
46.     
47.     StyleGraphic.RESTORE();
48. }
49. //+------------------------------------------------------------------+

代码 06

在这种情况下,代码编译过程中会出现一个警告,与以下内容非常相似:

图 01

注意错误,因为在第 38 行,我们试图访问一个不再为公有的值;这是因为在第 6 行我们添加了私有条件。但是,如果我们从代码 06 中删除第 38 行,我们将能够编译代码,因为 SAVE 和 RESTORE 子例程是公有的,正是因为我们在第 12 行添加了公有条件。我知道此刻一切可能看起来很混乱,但相信我,它比你想象的要简单得多,尤其是因为从现在开始,我们将在代码中包含公有和私有部分,从而开始使用一种结构化编程的形式。


总结性思考

好了,今天的文章就讲到这里。这篇文章很特别。这是因为,在这个阶段,我们正在进入所谓的结构化编程阶段,在这个阶段,我们创建小型数据结构,并使用专门用于处理、维护和分析代码结构中现有数据的程序和函数来为它们构建上下文。

我知道,这一切乍一看可能显得非常复杂和令人困惑,尤其是对许多人而言,因为这可能是他们首次真正接触到这种代码实现方式。在应用程序中,你可以找到我们今天复习的主要代码,这样你就可以更从容地练习和研究本文中的每个细节。

正确理解本材料的内容非常重要。如果理解得当,接下来的步骤将会简单得多。此外,理解我们稍后将要讲解的内容也会变得更加容易和直接。总之,这只是对该主题的简要介绍。

下一篇文章中,我们将更详细地讨论我们今天所看到的内容。然而,不要忽视对这一基础知识的掌握,因为这将使你更容易理解后续文章的内容。

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

附加的文件 |
Anexo.zip (2.89 KB)
一维奇异谱分析(SSA) 一维奇异谱分析(SSA)
本文探讨了奇异谱分析(SSA)方法的理论与实践,该方法是一种高效的时间序列分析工具,能够将复杂序列的结构分解为趋势、季节性(周期性)波动及噪声等简单成分。
珊瑚礁优化算法(CRO) 珊瑚礁优化算法(CRO)
本文对珊瑚礁优化(CRO)算法进行了全面分析,该算法是一种受珊瑚礁形成与发育生物过程启发的元启发式方法。该算法对珊瑚进化的关键环节进行了建模,包括广播产卵(群体产卵)、体内受精(抱卵孵化)、幼虫附着、无性繁殖以及有限礁区空间的竞争。尤其关注该算法的改进版本。
新手在交易中的10个基本错误 新手在交易中的10个基本错误
新手在交易中会犯的10个基本错误: 在市场刚开始时交易, 获利时不适当地仓促, 在损失的时候追加投资, 从最好的仓位开始平仓, 翻本心理, 最优越的仓位, 用永远买进的规则进行交易, 在第一天就平掉获利的仓位,当发出建一个相反的仓位警示时平仓, 犹豫。
配对交易:基于Z值差异的自动优化算法交易 配对交易:基于Z值差异的自动优化算法交易
本文将深入探究配对交易的核心逻辑,以及相关性交易的运作机制。我们还将编写一套自动化配对交易EA,并为其加入基于历史数据的算法自动优化功能。此外,在整个项目中,我们还会学习如何通过 Z 值(Z-Score)计算两个交易品种之间的价差偏离度。