English Русский Español Deutsch 日本語 Português
preview
开发回放系统 — 市场模拟(第 28 部分):智能交易系统项目 — C_Mouse 类 (II)

开发回放系统 — 市场模拟(第 28 部分):智能交易系统项目 — C_Mouse 类 (II)

MetaTrader 5测试者 | 20 五月 2024, 11:08
196 0
Daniel Jose
Daniel Jose

概述

在上一篇文章《开发重放系统(第 27 部分):智能交易系统项目(II)》中,我们开始开发一个新类。然而,在文章的最后,我开始相信提出一种不同的编程方式的重要性。这只是为了好奇,以便更接近自然语言。

对于那些曾长期编程的人来说,我们在下面展示的内容也许并无太多意义。为什么要费尽心思让编程更接近自然语言呢?答案很简单:您不是在为机器编程,而是在为其他程序员编程。在出现第一个能够分解某些东西的系统时,一切都取决于工程师对项目的熟知程度。这是计算机技术诞生之初的现实,当时还没有能编程的终端。

随着它的发展,越来越多的人对能够创造一些东西感兴趣,涌现出新的思路和编程方式,取代了旧式风格的改变连接器位置。这就是第一个终端出现的时刻。随着时间的流逝,最初只能以二进制格式完成的编程不再是常态。发生这种情况是因为程序发展得非常迅速,这导致需要找到一种更有效的方法来阅读已有编程。这时,汇编语言应运而生。这个强大的框架将复杂的二进制代码工作转化为更具可读性的东西,即以操作码或助记符的形式。程序变得越来越复杂,所需代码也越来越多,第一代高级语言出现了。

此时不再需要直接与操作码打交道,使用更接近自然的语言已然成为可能。起初,这些语言的开发主要是为了创建和描述数学概念,即它们主要促使将公式翻译成计算机可读的形式。该过程不再需要由人工手动完成。这催生了一个新时代 — 编译器时代,它将人类语言翻译成机器可以理解的语言。多年来,我一直按这种方式编程,尝试解释程序是如何制作的,并让更多的人学会如何将他们的想法翻译为计算机可以理解的东西。然而,我意识到很多人很难理解一些概念,因为编程主要涉及组合,以及使用助记符来表达我们想要创建的东西。

但考虑到 MQL5 语言类似于 C/C++,并有能力令代码以更具可读性的方式做事,故它成为演示不同内容的理想选择。然后,在分析了事情之后,我意识到即使并未完全理解代码,我也能帮助爱好者理解正在编制的程序。因此,我决定改变代码的表达方式。最后,编译器会理解一切,故对于编译器来说这没啥。但这对爱好者来说非常重要,因为语言将更自然。虽然代码初看好似很奇怪和不寻常,但对于初学者来说更容易理解。

我邀请您即刻与我一起以更接近自然语言的方式使用 MQL5 语言。


创建 Defines.mqh 文件

前两篇文章,我们查看了编译指令 #define。我提到过,有一种特殊情况,即在文件末尾没有删除定义,然而当时我没有展示该指令这种用法的实际应用,因为没有正确的方式可以做到这一点。故此,我们把这个问题留待解决。此处的关键点是,如果您了解 MQL5 的一些内容和概念,知道它是从 C/C++ 派生而来,那么您也许希望开始用该语言执行某些操作,而不会有太多麻烦。对于无法理解所有这些助记符、及需要搞明白其所执行操作的程序员来说,这将令代码更具可读性。

令代码更具可读性的方式之一是使用 #define 指令。不过,这存在一些限制。初看,这好似很奇怪,但这一切都归结为如何掌握正确、且毫不夸张地遵照 MQL5 语言语法定义一些符号或符号组合。我们并非创造一种新的语言。我们只是以相当一致的方式替换一些现有符号。这就是 Defines.mqh 文件如何诞生的。它将包含一些语法定义,那么之前的象征性,就转化为对人类读者来说更具表现力的单词或定义。

以下是该文件的完整内容:

//+------------------------------------------------------------------+
#property copyright "Daniel Jose"
/*+------------------------------------------------------------------+
Definitions for increasing the level of the coded language in MQL5, for
more details see the article at the following link:
https://www.mql5.com/en/articles/11349
+------------------------------------------------------------------+*/
#define equal =
#define different !=
#define identical ==
#define and &&
//+------------------------------------------------------------------+

这小段几乎没有作用的代码实际做啥?若要理解这一点,您需要付诸实践。每一行代码都表示一个附加助记符,寻求代码更具可读性。即使是经验不足的人也能够理解,哪怕不是全部,至少是程序的某些方面。代码的可读性是我们始终需要改进的。最好有更具可读性的代码,即使这意味着前期需要更多的工作。但最终这是值得的,因为没有人愿意和看似象形文字的代码打交道,即便作者自己过后也看不懂。一旦编写这段代码的途径消失,无论是因为语言亦或人员不复存在,其中包含的所有知识也随即丢失。

令代码更具可读性的方式之一是使用注释。不过,如果您查看我文章中的代码,您会注意到我未加注释。这是因为,在我看来,这些代码太简单了,且可读性极佳。如果没有文章中的讲述,您能理解这些代码吗?这恰恰是重点。在某些时候,代码可能会变得如此复杂,以至于如果没有一个良好的结构,它就彻底变得不可读,甚至我也无法维护和改进它。

一旦 Defines.mqh 文件创建完毕,我们需要以某种方式强制编译器使用它。为此,我们将该文件包含在构建整个系统的最基础文件之一当中 — C_Terminal.mqh。在 C_Terminal.mqh 里包含部分如下行:

#include "Macros.mqh"
#include "..\..\Defines.mqh"

要小心,因为这非常重要。我们用双引号声明 Macros.mqh 文件,其告诉编译器该文件与 C_Terminal.mqh 文件位于同一文件夹之中。不过,当我们包含 Defines.mqh 文件时,它也用双引号括起来,但有一个特定的功能。这种区别在于 ..\,它告诉编译器有多少个层次,自 C_Terminal.mqh 所在的目录开始,我们需要在目录结构中向上层查找 Defines.mqh 文件。在这种情况下,我们需要往上两个层次,因为目录结构包含不同的代码层次。故此,Defines.mqh 文件位于该项目的根目录下。如果出于某种原因项目的根目录发生变化,其不会影响编译器,编译器会始终在同一位置查找 Defines.mqh 文件。

这种组织非常有趣,尤其是当您开始组织头文件库,以便令其易于查找和规划事项。这将令我们能够轻松分发我们的代码或部分代码,且不必担心丢失特定文件。一切都井井有条,并准备好分发代码,令我们的生活变得更加轻松。现在我们已经解释了如何在系统中包含 Defines.mqh 文件,我们能开始使用它了。您可以增加定义的数量,令一切更具可读性。好了,目前的定义足以满足我们的目的。但要真正理解这样做在何种程度上有助于代码更具可读性,并更容易解决浮现的问题,我建议您查看下面的示例:

if (m_Info.Study == eStudyExecute) ExecuteStudy(memPrice);
if (m_Info.Study identical eStudyExecute) ExecuteStudy(memPrice);
if_case m_Info.Study identical eStudyExecute then ExecuteStudy(memPrice);

这三行的意思相同,编译器将按相同的方式解释它们,生成完全相同的代码。不过,在这种情况下,Defines.mqh 文件将无法告诉编译器该做什么。我们需要添加两个新定义:

#define if_case if(
#define then )

如果您将这两行添加到 Defines.mqh 文件中,编译器就能够正确理解示例中的三行。注意高亮显示的行。此处,我们的陈述与自然语言非常相似。在所示的三行中,这行与自然语言最相似,那它即为三行中的最高级别。这就是我所说的,代码要么是高级代码,要么是低级代码的含义。对于编译器来说,没有任何区别,但对于人的肉眼,第三行要简单得多。这是一个简单的情况,但我们来看一个更复杂的情况,其中所有代码都如图例所示编写,不要忘记即使是前几篇文章中所示的代码也经历了类似的修改,以便令其更具可读性。这是为了当下。

我们回到我们在上一篇文章中停步的所在。我们曾打算查看 C_Mouse 类中的最后一个函数。


DispatchMessage:与外界沟通

所有必须以某种方式从 MetaTrader 5 平台接收事件的类,都将在其代码组合中拥有 DispatchMessage 函数。有了它,类就能够接收和响应生成的事件。最重要的是要明白 MetaTrader 5 是一个基于事件的程序,即 REAL TIME 类型的程序。委婉地说,操控这个是相当困难的。因此,在操控这种事件时,任何代码都必须非常具体。但在我们查看 DispatchMessage 函数之前,我们需要熟悉将出现在 C_Terminal 类中的其它代码。这段代码如下所见:

const double AdjustPrice(const double arg) const { return NormalizeDouble(round(arg / m_Infos.PointPerTick) * m_Infos.PointPerTick, m_Infos.nDigits); }

这段代码本来可以放在 C_Mouse 类中,但由于其它因素,我决定把它放在 C_Terminal 类中。此段代码只是一个因子分解,寻求调整价格,如此令其始终等于交易服务器的预期值。由于指定的价格经常不正确,订单会被服务器拒绝。许多人拒绝考虑创建 EA,仅因为当他们尝试将订单发送到交易服务器时,他们会收到一个出错响应。一些资产类别的价格调整具有更简单的因子分解,而其它资产类别则具有更复杂的因子分解,涉及多个问题。然而,在实践中,上述功能管理所有这些因子,确保价格始终相适,无论所用的资产类型如何。这对我们来说非常重要,因为若在回放/模拟系统中创建和使用 EA,无论资产如何,价格都必须是正确的,模拟亦或实盘账户上均如此。因此,您可以使用甚至滥用此功能。如果您这样做了,您就能看到系统如何适配任何类型的市场和资产。故此,请使用并研究此能力。

现在我们已经看过一个可以根据需要调整价格的函数,我们能够开始查看 DispatchMessage 函数了。其完整代码如下所示:

virtual void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam)
   {
      int w equal 0;
      static double memPrice equal 0;
                                
      C_Terminal::DispatchMessage(id, lparam, dparam, sparam);
      switch (id)
      {
         case (CHARTEVENT_CUSTOM + ev_HideMouse):
            ObjectSetInteger(GetInfoTerminal().ID, def_NameObjectLineH, OBJPROP_COLOR, clrNONE);
            break;
         case (CHARTEVENT_CUSTOM + ev_ShowMouse):
            ObjectSetInteger(GetInfoTerminal().ID, def_NameObjectLineH, OBJPROP_COLOR, m_Info.corLineH);
            break;
         case CHARTEVENT_MOUSE_MOVE:
            ChartXYToTimePrice(GetInfoTerminal().ID, m_Info.Data.Position.X equal (int)lparam, m_Info.Data.Position.Y equal (int)dparam, w, m_Info.Data.Position.dt, m_Info.Data.Position.Price);
            ObjectMove(GetInfoTerminal().ID, def_NameObjectLineH, 0, 0, m_Info.Data.Position.Price equal AdjustPrice(m_Info.Data.Position.Price));
            if (m_Info.Study different eStudyNull) ObjectMove(GetInfoTerminal().ID, def_NameObjectLineV, 0, m_Info.Data.Position.dt, 0);
            m_Info.Data.ButtonStatus equal (uint) sparam;
            if (CheckClick(eClickMiddle) and ((color)ObjectGetInteger(GetInfoTerminal().ID, def_NameObjectLineH, OBJPROP_COLOR) different clrNONE)) CreateStudy();
            if (CheckClick(eClickLeft) and (m_Info.Study identical eStudyCreate))
            {
               ChartSetInteger(GetInfoTerminal().ID, CHART_MOUSE_SCROLL, false);
               ObjectMove(GetInfoTerminal().ID, def_NameObjectLineT, 0, m_Info.Data.Position.dt, memPrice equal m_Info.Data.Position.Price);
               m_Info.Study equal eStudyExecute;
            }
            if (m_Info.Study identical eStudyExecute) ExecuteStudy(memPrice);
            break;
         case CHARTEVENT_OBJECT_DELETE:
            if (sparam identical def_NameObjectLineH) CreateLineH();
            break;
      }
   }

即使没有太多的编程经验,也可以通过查看代码来理解其中的大部分内容。若没有太多编程知识,您怎样才能理解代码?当您用一种语言编程,如此您的代码开始接近自然语言时,代码就会变得更容易理解。以这种方式,即使不懂编程的人也能理解正在编程之处。事实上,那里发生的很多事情都很容易理解,它是如此简单,甚至不需要详细的解释。现在,请看以下几行。

int w equal 0;
static double memPrice equal 0;

尽管代码是以这种方式声,但您应该按照编写代码相同的方式阅读。编译器将按如下方式解释该段代码:

int w = 0;
static double memPrice = 0;

如您所见,没有区别。在这两种情况下,任何人都可以理解代码。在第一种情况下,我们得到一个“字面”形式。但别担心,我们才刚刚开始。为了代码更具可读性,该示例并未完全反映我们的所有选项。

我们看看另一段代码。这部分与代码的可读性没有直接关系,但仍需要澄清。

case (CHARTEVENT_CUSTOM + ev_HideMouse):
   ObjectSetInteger(GetInfoTerminal().ID, def_NameObjectLineH, OBJPROP_COLOR, clrNONE);
   break;

有时我们需要隐藏图表上的价格线。那些遵循《如何从头开始开发 EA》 系列中展示的订单系统的人发现,在某些时候价格线是隐藏的。在实施的代码中,这是通过调用特定方法做到的,由此导致线被隐藏起来。不过,现在我们将使用消息,发送到 C_Mouse 类来隐藏价格线。我决定诉求于消息替代方法,因为我想构建一个更加模块化、且易于移植的系统,或其它东西。故此,我们还有另一条消息,亦符合相同准则。它如下所示:

case (CHARTEVENT_CUSTOM + ev_ShowMouse):
   ObjectSetInteger(GetInfoTerminal().ID, def_NameObjectLineH, OBJPROP_COLOR, m_Info.corLineH);
   break;

暂时不要担心如何使用这些消息。我们会在将来研究这一点。事实上,如果您认为这两条消息可以是方法或函数,则更容易理解它们。不过,宁可不为此目的添加公开方法或函数,我们却将所有内容集中在一个中心点:消息处理函数。仅在特殊情况下,我们才会使用不同的方法。

出现这些事件是特殊调用的结果,稍后会更详细地讨论,因为我认为许多人不知道这是如何做到的。这些不是 MetaTrader 5 平台发射的事件,而是我们的代码在非常特定的时间发射的事件,以便执行某些动作。但我们还需要操控来自 MetaTrader 5 平台的事件。具体做法如下:

C_Terminal::DispatchMessage(id, lparam, dparam, sparam);

来自 C_Mouse 类的 DispatchMessage 函数中的这行代码把调用转发给 C_Terminal 类,如此我们就不必在代码的其它部分干这件事。这有助于避免编程疏忽,以及代码的标准化,从而更快地进行编程、分析、创建和修复。不过,并非所有事件都会在 C_Terminal 类中处理:其中一些事件将在局部解决,即在我们所用的类中。此类事件的示例如下所示:

case CHARTEVENT_OBJECT_DELETE:
   if (sparam identical def_NameObjectLineH) CreateLineH();
   break;

这是面向读者的事件代码。我认为您能够理解编译器解释如下:

case CHARTEVENT_OBJECT_DELETE:
   if (sparam == def_NameObjectLineH) CreateLineH();
   break;

无论代码如何表现,其结果如下:当对象从交易品种图表中删除时,平台会触发一条消息,或与其说是一个事件。它通知请求此类消息的程序,该对象已从图表中删除。满足 CHART_EVENT_OBJECT_DELETE 处理程序,则程序必须执行其中存在的代码。如果 param 常量中指定的对象名称匹配正在测试的对象名称,则执行的代码将重新创建价格线。

现在我们有了略微扩展的 CHART_EVENT_MOUSE_MOVE 事件。尽管范围更广,但并不是很复杂。即使没有编程知识,您也可以理解下面的大部分代码,只需尝试阅读每一行字面意思即可。试试看,告诉我理解我们正在做什么是更容易还是更困难。您无法明白所有的代码也没关系,只要您尝试尽可能多地理解,无需超额努力。

case CHARTEVENT_MOUSE_MOVE:
   ChartXYToTimePrice(GetInfoTerminal().ID, m_Info.Data.Position.X equal (int)lparam, m_Info.Data.Position.Y equal (int)dparam, w, m_Info.Data.Position.dt, m_Info.Data.Position.Price);
   ObjectMove(GetInfoTerminal().ID, def_NameObjectLineH, 0, 0, m_Info.Data.Position.Price equal AdjustPrice(m_Info.Data.Position.Price));
   if (m_Info.Study different eStudyNull) ObjectMove(GetInfoTerminal().ID, def_NameObjectLineV, 0, m_Info.Data.Position.dt, 0);
   m_Info.Data.ButtonStatus equal (uint) sparam;
   if (CheckClick(eClickMiddle) and ((color)ObjectGetInteger(GetInfoTerminal().ID, def_NameObjectLineH, OBJPROP_COLOR) different clrNONE)) CreateStudy();
   if (CheckClick(eClickLeft) and (m_Info.Study identical eStudyCreate))
   {
      ChartSetInteger(GetInfoTerminal().ID, CHART_MOUSE_SCROLL, false);
      ObjectMove(GetInfoTerminal().ID, def_NameObjectLineT, 0, m_Info.Data.Position.dt, memPrice equal m_Info.Data.Position.Price);
      m_Info.Study equal eStudyExecute;
   }
   if (m_Info.Study identical eStudyExecute) ExecuteStudy(memPrice);
   break;

除了我们调用 MQL5 函数的那些时刻,我认为您能够阅读整体代码,且对您来讲也不难理解某些要点。例如:

  • 如果 m_Info.StudyeStudyNull 不同,则应执行某些操作。
  • m_Info.Data.ButtonStatus 等于 sparam
  • 如果按下了中间按钮,并且任何内容(价格线颜色)都与 clrNONE 不同,请执行以下操作。
  • 如果用鼠标左键按下它并且 m_Info.Study 等于 eStudyCreate,则将执行此动作。
  • 将 eStudyExecute 设置为 m_Info.Study。
  • 如果 m_Info.Study 等于 eStudyExecute,运行它。

您能看到,即使您阅读了上面所有已演示的要点,它仍然表明我们可以在 Defines.mqh 文件中添加更多的东西,从而令语言比我所演示的更具可读性。我们可以简单地添加更多元素,并令程序更具可读性。这是好的编程语言应有的品质,它将永远存在于技术品控优良的程序当中。令代码具有相当可读性的另一种方,式是始终为最重要的函数或关键处添加注释,在这方面,MQL5 明显优于 C/C++。尝试为变量和过程添加注释。使用 MetaEditor 时,它会将这些注释显示为工具提示,这非常实用。

上面的代码实际是如何编译的?或者更准确地说,编译器实际上会如何看待上面的代码?它如下所示:

case CHARTEVENT_MOUSE_MOVE:
   ChartXYToTimePrice(GetInfoTerminal().ID, m_Info.Data.Position.X = (int)lparam, m_Info.Data.Position.Y = (int)dparam, w, m_Info.Data.Position.dt, m_Info.Data.Position.Price);
   ObjectMove(GetInfoTerminal().ID, def_NameObjectLineH, 0, 0, m_Info.Data.Position.Price = AdjustPrice(m_Info.Data.Position.Price));
   if (m_Info.Study != eStudyNull) ObjectMove(GetInfoTerminal().ID, def_NameObjectLineV, 0, m_Info.Data.Position.dt, 0);
   m_Info.Data.ButtonStatus = (uint) sparam;
   if (CheckClick(eClickMiddle) && ((color)ObjectGetInteger(GetInfoTerminal().ID, def_NameObjectLineH, OBJPROP_COLOR) != clrNONE)) CreateStudy();
   if (CheckClick(eClickLeft) && (m_Info.Study == eStudyCreate))
   {
      ChartSetInteger(GetInfoTerminal().ID, CHART_MOUSE_SCROLL, false);
      ObjectMove(GetInfoTerminal().ID, def_NameObjectLineT, 0, m_Info.Data.Position.dt, memPrice = m_Info.Data.Position.Price);
      m_Info.Study = eStudyExecute;
   }
   if (m_Info.Study == eStudyExecute) ExecuteStudy(memPrice);
   break;

两段代码都做同样的事情。因此,对于那些尚未完全理解 MQL5 语言中的函数之人,我将解释我们在这里做什么。我们做的第一件事是将平台报告的图形坐标转换为价格和时间坐标。以这种方式,我们就可以知道鼠标指针相对于图表的位置。接下来,我们调整价格从而匹配交易服务器的预期。与此类似,我们可以将价格线放在图表上的所需位置。如果我们正在做分析,我们需要正确地移动时间线。我们保存鼠标按钮的状态,并检查是否按下中间按钮进行滚动。不过,仅当价格线在图表上可见时,才会执行分析。只要按下左键,分析就会开始。因此,我们需要告诉平台不要移动图表,这样我们就可以在按下左键的情况下轻松拖动鼠标。按住按钮时,进行分析时,会用到我们打算放置在图表上的所有对象。

在本文完成之前,我们简要看看这个开发阶段的 EA 代码。完整代码如下:

#property copyright "Daniel Jose"
#property description "Generic EA for use on Demo account, replay system/simulator and Real account."
#property description "This system has means of sending orders using the mouse and keyboard combination."
#property description "For more information see the article about the system."
#property version   "1.28"
#property link "https://www.mql5.com/en/articles/11349"
//+------------------------------------------------------------------+
#include <Market Replay\System EA\Auxiliar\C_Mouse.mqh>
//+------------------------------------------------------------------+
input group "Mouse";
input color     user00 equal clrBlack;          //Price Line
input color     user01 equal clrDarkGreen;      //Positive Study
input color     user02 equal clrMaroon;         //Negative Study
//+------------------------------------------------------------------+
C_Mouse *mouse;
//+------------------------------------------------------------------+
int OnInit()
{
   mouse equal new C_Mouse(user00, user01, user02);
                
   return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   delete mouse;
}
//+------------------------------------------------------------------+
void OnTick() {}
//+------------------------------------------------------------------+
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
   (*mouse).DispatchMessage(id, lparam, dparam, sparam);
   ChartRedraw();
}
//+------------------------------------------------------------------+

注意,代码非常简单。因此,在这个阶段,我不会详细解释这个过程,因为这并无特别必要。


结束语

从现在开始,我们可用系统中包含的 EA 监控系统的运行。不过,该 EA 的操作仅配合鼠标。但现在我们不仅可以在回放/模拟系统中使用它,还可以在模拟和真实账户上使用它。尽管 EA 在这种情况下还不是很实用,但它非常有趣,因为它可以在任何市场、交易品种、或任何状况下使用。

另一个重要的细节:在附件中,您可以找到用到 Defines.mqh 文件内容的最后两个类(C_Terminal 和 C_Mouse)。这令代码更具可读性。然而,这与我们在文章开头所说的不同,于该处,我们暗示所有代码都将遵循这种格式。实际上,如果您愿意,可以使用此技术。在我作为 C/C++ 程序员的职业生涯早期,有一段时间我曾用这种方式来更好地理解语言的语法。我知道一开始可能会十分困惑,但随着时间的推移,您就习惯了。这种技艺非常有用,尤其是在需要分析大量布尔和逻辑组合的复杂项目当中。在这一点上,双重符号(译者按:”&&“、”||“、等等)的存在,对于初学者来说,可能会令事情复杂化。例如,参阅以下事实:

即使在经验丰富的程序员当中,有谁从未混淆过“逻辑与”(&)和“布尔与”(&&)的用法?它们几乎是一样的。但在第一种情况下,操作是按位执行的;在第二种情况下,解析整个变量,并返回 true 或 false。当我们需要非常快速地创建程序时,这吸引了很多人。

因此,不要低估某些技艺的知识。尽管它们也许看似很简单,但它们实际上为程序的更具可读性做出了重大贡献,并因此加快其开发进度。我想我已经以一种非常有趣的方式演示了如何更快地执行任务,同时仍然确保代码始终正确,而不必浪费时间试图弄清楚为什么某个特定部分没有按预期工作。


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

附加的文件 |
Files_-_BOLSA.zip (1358.24 KB)
Files_-_FOREX.zip (3743.96 KB)
Files_-_FUTUROS.zip (11397.51 KB)
如何利用 MQL5 创建简单的多币种智能交易系统(第 2 部分):指标信号:多时间帧抛物线 SAR 指标 如何利用 MQL5 创建简单的多币种智能交易系统(第 2 部分):指标信号:多时间帧抛物线 SAR 指标
本文中的多币种智能交易系统是智能交易系统或交易机器人,它仅在一个品种图表上就能交易(开单、平单、和管理订单,例如:尾随停损和止盈)超过 1 个交易品种对。这次我们只用 1 个指标,即抛物线 SAR 或 iSAR, 将其应用在 PERIOD_M15 到 PERIOD_D1 的多个时间帧。
开发回放系统(第32部分):订单系统(一) 开发回放系统(第32部分):订单系统(一)
在我们迄今为止开发的所有东西中,正如你可能会注意到并最终同意的那样,这个系统是最复杂的。现在我们需要做一些非常简单的事情:让我们的系统模拟交易服务器的操作。准确实现交易服务器操作方式似乎是一件轻而易举的事情。至少说起来是这样。但我们需要这样做,以便对回放/模拟系统的用户来说,一切都是无缝和透明的。
机器学习中的量化(第1部分):使用 CatBoost 的理论、示例代码和实现分析 机器学习中的量化(第1部分):使用 CatBoost 的理论、示例代码和实现分析
本文探讨了量化在树模型构建中的理论应用,并展示了使用 CatBoost 实现的量化方法。不使用复杂的数学方程。
将您自己的LLM集成到EA中(第2部分):环境部署示例 将您自己的LLM集成到EA中(第2部分):环境部署示例
随着人工智能的快速发展,语言模型(LLMs)是人工智能的重要组成部分,因此我们应该思考如何将强大的语言模型集成到我们的算法交易中。对大多数人来说,很难根据他们的需求对这些强大的模型进行微调,在本地部署,然后将其应用于算法交易。本系列文章将采取循序渐进的方法来实现这一目标。