文章 "通用智能交易系统:事件模型和交易策略原型(第二章)"

 

新文章 通用智能交易系统:事件模型和交易策略原型(第二章)已发布:

本文是通用智能交易模型系列文章的又一篇。这一部分详细介绍了基于数据集中处理的原始事件模型,并考虑了交易引擎CStrategy基类的结构。

本文包含对通用交易引擎CStrategy的进一步描述。在第一片文章通用智能交易系统:交易策略的模式(第一部分)中, 我们详细讨论了要实现的交易模型及函数。我们已经分析过一个由四种方法组成的通用EA框架,两个方法用于开新仓其他两个用于平仓。不同的方法调用组合可以 定义一个特定的交易模型。例如,只允许EA卖或者买,可以管理未平仓头寸或等待。使用这些方法,一个EA可以根据交易时间或者日期进行灵活的设置。

然而,交易模型并不是一个EA的全部。在第二部分我们将讨论基于事件集中处理的CStrategy交易模型的事件模型。提出的事件处理方案和所有事件聚集在一处的系统事件不同。这样实现的好处在后面会讲到。

此外,本文还介绍两个重要的交易引擎类 — CStrategyCPosition。第一个是整个EA交易逻辑的核心,它将事件和模型结合起来成为一个灵活的框架,自定义EA可以直接继承它。第二个类是通用交易操作的基类。它包含针对未平仓头寸的操作(如平仓或者修改止赢止损)。这样可以构成所有的交易操作并且使得它们独立于平台。

处理其他交易对象上发生的事件,MarketEvent结构体

当设计一个分析多货币对交易系统时,你需要创建一个可以追踪多货币对价格变化的机制。然而,标准的OnTick函数仅在EA运行货币对上新报价到来时被激活。另一方面,交易系统开发者可以使用OnBookEvent函数,它响应订单簿(市场深度)中的价格变化。和OnTick不同,OnBookEvent在订单簿中的任一对象发生价格变化时被调用,你可以使用MarketBookAdd 函数来订阅订单簿。

订单簿的改变非常频繁,这也是为何监控该事件是非常耗费资源的。一般,对于EA来说监控所需货币的报价变化足够了。另一方面,订单簿变化事件也包含了新报价的到来。除了OnBookEvent,你可以设置以一定的时间间隔调用OnTimer,并在其中分析多货币对的价格变化。

因此,在对NewTick,BookEvent 和 Timer 事件做出响应的系统函数中,你可以添加对某些中间件 的调用(我们称之为事件处理器EventProcessor),它将同时分析多个货币对的价格变化并产生与之对应的事件。每一个事件将有一个结构体形式的 统一描述,并将由策略的控制函数传递。接收到一个结构体的事件后,策略将对此做出相应或者忽略它。在这种情况下,为EA最终实际产生事件的系统函数将不可 知。

事实上,如果EA接收到一个新报价事件通知,至于通知通过OnTick, OnTimer 还是 OnBookEvent来 接收是无关紧要的。重要的是指定货币对上有新的报价到来。一个事件处理器可以给很多策略使用。例如,如果每个策略由一个自定义类代表,这些类的实例可以被 存储在特定的策略列表中。在这种情况下,列表中的任一策略将能够接收到由EventProcessor产生的新事件。下面的图表显示了事件是如何产生和发 送的:

图 1. 事件产生和发送图

作者:Vasiliy Sokolov

 
感谢作者。文章的素材非常有用,表述也非常出色。我早就想把自己的专业写作方法整理好,而在这里,文章作者已经经历了创作的所有痛苦,并提供了现成的解决方案。太棒了!期待续写。


让我们一起探讨交易系统自动化 的无路可走、创造力的折磨以及开发人员对 "交易 引擎 "的懈怠!

 

感谢作者提供的信息丰富的文章,但我对软件实现的可靠性有些怀疑。

在您建议的代码中,所有事件处理函数都会引用通用的 event_type 变量或CStrategy 通用实例中的 m_event 结构。

但这可能是危险的,因为事件是异步发生的,其处理程序的线程可能在时间上重叠,从而混乱地更改公共数据,或在访问相同内存区域时导致故障。

通常,线程的同步是通过使用 semaphores、mutexes、等待函数、关键代码段等来实现的,但 MQL 没有这些手段,因此在异步事件的函数处理程序中,显然有必要尽量减少对对象和变量全局实例的引用,而尽量使用本地引用。

在此基础上,文章中提出的将事件处理程序和数据块结合起来的做法,在我看来并不是一个好主意。

 
Eugene Myzrov:
感谢作者。文章的素材非常有用,表述也非常出色。我早就想把自己的专业写作方法整理一下,而在这里,文章作者已经经历了创作的所有痛苦,并提供了现成的解决方案。太棒了!期待续写。


让我们一起探讨交易系统自动化的无路可走、创造力的痛苦以及开发人员对 "交易引擎 "的懈怠!

谢谢

Ivan Negreshniy:

感谢作者提供的信息丰富的文章,但我对软件实现的可靠性有些怀疑。

在您建议的代码中,所有事件处理函数都会引用通用的 event_type 变量或 CStrategy 通用实例中的 m_event 结构。

但这可能是危险的,因为事件是异步发生的,其处理程序的线程可能会在时间上重叠,从而混乱地更改公共数据或在访问相同内存区域时导致故障。

...

谢谢您有趣的评论。的确,MetaTrader 中的事件是异步的。但是,用户线程的执行是严格按顺序进行的。这意味着,在 Expert Advisor 完成当前事件的处理之前,其他事件将不会被处理。下面的代码说明了这一点:

//+------------------------------------------------------------------+
//|TestAsynch.mq5
//|版权所有 2015 年,瓦西里-索科洛夫。|
//|http://www.mql5.com | |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Vasiliy Sokolov."
#property link      "http://www.mql5.com"
#property version   "1.00"
bool need_check = true;
#define  EVENT_CHECK_ASYNCH 1
//+------------------------------------------------------------------+
//| 专家勾选功能|
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   if(need_check)
   {
      EventChartCustom(ChartID(), EVENT_CHECK_ASYNCH, 0.0, 0.0, "异步检查");
   }
   if(need_check)
      printf("用户线程首先终止"。);
  }
//+------------------------------------------------------------------+
//| 图表事件函数|
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
   if(id == CHARTEVENT_CUSTOM+EVENT_CHECK_ASYNCH && need_check)
   {
      printf("然后调用 OnChartEvent 事件"。);
      need_check = false;
   }
  }
//+------------------------------------------------------------------+

其执行按以下顺序产生行:

2016.01.15 13:51:31.724 TestAsynch (NZDUSD,W1)  Потом вызывается событие OnChartEvent
2016.01.15 13:51:31.722 TestAsynch (NZDUSD,W1)  Сначала завершается пользовательский поток

因此,由于代码是按顺序执行的,m_event 共享变量的联合更改不会导致错误。我还应该指出,该结构本身是私有的,只有通过引用特殊方法才能访问。因此,它在CStrategy 中的实际位置并不重要,该结构可以很容易地直接在事件处理方法中创建,也可以传递给策略实例。

 
Vasiliy Sokolov:

谢谢!

感谢您提出的有趣意见。的确,MetaTrader 中的事件是异步的。但是,用户线程的执行是严格按顺序进行的。这意味着,在 Expert Advisor 完成当前事件的处理之前,其他事件将不会被处理。下面的代码说明了这一点:

其执行按以下顺序产生行:

因此,由于代码是按顺序执行的,m_event 共享变量的联合更改不会导致错误。我还应该指出,该结构本身是私有的,只有通过引用特殊方法才能访问。因此,它在 CStrategy 中的实际位置并不重要,该结构可以很容易地直接在事件处理方法中创建,也可以传递给策略实例。

您说得对,严格按顺序执行事件处理程序可以消除错误,但这本质上是单线程模式,很难实现高性能。

与此同时,有些时间紧迫的任务也需要并行化,例如使用 OpenCL 对大量价格和历史数据进行计算,或者与我相关的更具体的任务--借助我文章中描述的多线程引擎对不同符号和时期的神经网络进行训练。
https://www.mql5.com/zh/articles/706

Создание нейросетевых торговых роботов на базе MQL5 Wizard и Hlaiman EA Generator
Создание нейросетевых торговых роботов на базе MQL5 Wizard и Hlaiman EA Generator
  • 2013.08.29
  • Ivan Negreshniy
  • www.mql5.com
В статье рассматривается метод автоматизированного создания нейросетевых торговых роботов на базе MQL5 Wizard и Hlaiman EA Generator. Узнайте, как легко начать работать с нейронными сетями, минуя длительные этапы изучения теоретических материалов и написания собственного кода.
 
Ivan Negreshniy:

您说得对,严格按顺序执行事件处理程序可以消除错误,但这本质上是一种单线程模式,很难实现高性能。

同时,有些时间紧迫的任务需要并行化,例如,使用 OpenCL 执行大量价格和历史数据的计算,或者与我相关的更具体的任务--通过不同的符号和时期训练神经网络,这些都是在我的文章
https://www.mql5.com/zh/articles/706 中描述的多线程引擎的帮助下执行的。

MetaTrader 中的并行化是由多线程策略测试器完成的。因此,如果在策略测试器中运行借助所述引擎编写的策略,该策略将自动成为多线程策略。由于没有第三方 dll,您可以充分发挥 MQL Networl Cloud 的潜力。您提到的是 MetaTrader 本身。是的,引擎以及 MetaTrader 中的任何专家顾问或脚本都是单线程的,但优化器允许您对所提交的代码执行多线程和云计算。

至于引擎性能本身,一切正常。您可以通过执行剖析来确保这一点。基础设施和事件交付成本极低。主要执行时间集中在系统函数和自定义方法 BuyInit、SellInit、BuySupport、SellSupport 的调用上。根据剖析计算,该引擎每秒能处理数十个事件,并能毫不费力地同时将它们重定向到多个策略。

很抱歉,这篇文章所提供的并不是指手画脚。这是一个经过多年验证和测试的解决方案。所有调用和内部程序都是最佳和重要的。算法在剖析器中进行了测试。对用户代码的内部组织没有任何限制。总之,一切都能让你满意。拿去用吧。

 
非常感谢Vasiliy Sokolov 为推广良好的编程风格,特别是 OOP 所做的努力。
这篇文章陈述清楚,非常有用,至少对 MQL 初学者来说是这样,而我就是。:)
请回答以下问题:
在我的交易算法中,
买入/卖出类型的市场订单头寸是在特殊情况下打开的--如果价格已经超过相应的水平或 在交易时段结束之前。
一般情况下,通过下达 BuyStop/SelStop 止损,在向上/向下水平分解(多头)时建立/关闭头寸,这些止损单在新的条形图开始时重新计算。
您能否建议如何在所述类别中引入止损单的下达和更改?
 
Mike:
非常感谢Vasiliy Sokolov 为推广良好的编程风格,特别是 OOP 所做的努力。 这篇文章陈述清楚,非常有用,至少对 MQL 初学者来说是这样,而我就是。:) 请回答以下问题: 在我的交易算法中,


买入/卖出类型的市场订单头寸是在特殊情况下打开的--如果价格已经超过相应的水平或 在交易时段结束之前。
一般情况下,通过设置买入止损/卖出止损订单,在上涨/下跌水平分解(多头)时建立/关闭头寸,这些订单在新的条形图开始时重新计算。
您能建议我如何在所述类别中引入设置和更改止损订单的功能吗?

您好。目前正在研究管理挂单的算法,但在当前版本的引擎中还没有具体实施。目前我唯一能建议的是在 BuyInit 和 SellInit 方法中加入挂单代码。此外,还需要在其中枚举挂单,以及通常在常规智能交易系统中必须完成的所有操作。

未来计划在引擎中添加处理挂单的方法,并对其进行相应描述。它们将与仓位管理方法类似。

 
Vasiliy Sokolov:

您好。目前,我们正在研究挂单管理的算法,但当前版本的引擎尚未具体实施。目前我唯一能建议的是将挂单代码放在 BuyInit 和 SellInit 方法中。此外,还需要在其中枚举挂单,以及通常在常规智能交易系统中必须完成的所有操作。

未来计划在引擎中添加处理挂单的方法,并对其进行相应描述。它们的工作原理与仓位管理方法类似。

谢谢您,瓦西里,我们拭目以待。:)
 
瓦西里,非常感谢你的文章!非常棒,对初学者非常有用!
 

谢谢

*****