English Русский Español Deutsch 日本語 Português
preview
构建自动运行的 EA(第 09 部分):自动化(I)

构建自动运行的 EA(第 09 部分):自动化(I)

MetaTrader 5交易 | 8 五月 2023, 10:15
1 781 0
Daniel Jose
Daniel Jose

概述

在上一篇文章构建自动运行的 EA(第 08 部分):OnTradeTransaction 中,我曾解释过如何利用一个相当有趣的事件处理函数来发挥 MetaTrader 5 平台的优势。 我们现在开始在 EA 中构建初级自动化。

与许多现有机制不同,于此我们将研究一种不会令 EA 或平台超载的机制。 这种机制也可用于对冲账户,尽管它主要针对净持结算账户。

我们将从操控 OCO 订单的简单系统起步。 稍后我们将扩展功能,以便提供更可靠和有趣的系统,特别是对于那些喜欢在非常不稳定的市场中进行交易的人,那里错过订单的风险很高。


为 OCO 订单创建盈亏平衡和尾随停止

如果您还不熟悉这一点,请让我解释一下。 OCO(一笔订单取消另一笔订单)订单系统是一个在订单或持仓本身中设置止盈和止损的系统。 如果订单被取消或平仓,那么这些止盈或止损订单也会被取消。

止盈和止损订单可以随时删除或添加。 出于实际目的,为了不令代码复杂化,我们假设它们始终在 EA 向交易服务器发送订单时才创建,并且当满足其中一个限制而平仓时,它们将一同不复存在。

为了创建触发机制,我们将依靠 C_Manager 类来操控。 在此,我们已准备好了盈亏平衡和尾随停止的触发系统所需的几乎所有东西。 首先,我们添加一个函数,为持仓生成盈亏平衡价位。 该函数的完整代码如下所示:

inline void TriggerBreakeven(void)
                        {
                                if (PositionSelectByTicket(m_Position.Ticket))
                                        if (PositionGetDouble(POSITION_PROFIT) >= m_Trigger)
                                                m_Position.EnableBreakEven = (ModifyPricePoints(m_Position.Ticket, m_Position.PriceOpen, m_Position.PriceOpen, m_Position.TP) ? false : true);
                        }

您可能希望于此看到比所示代码复杂得多的函数,但相信我,这个简单的函数就能够触发持仓盈亏平衡价位。 如果您尚不明白这是怎么回事儿,我们分析一下这是如何发生的,以便您相信除了这个简单的功能之外,我们不需要其它任何东西。

我们要做的第一件事是调用 PositionSelectByTicket 函数。 该函数下载有关持仓的所有更新信息。 然后,我们调用 PositionGetDouble 函数,并配合 POSITION_PROFIT 参数,来获取由 PositionSelectByTicket 加载的最新财会数值。 我们将此数值与类初始化期间在构造函数中输入的数值进行比较。

如果该数值大于或等于它(这是触发器),这表明我们可能达到了盈亏平衡。 然后,我们将开仓的价格值发送到 C_Orders 类中的函数。 如果交互成功,该类将指示已达到盈亏平衡。

这个函数很简单,是不是? 然而,它的定义包含在代码的私密部分,而 EA 将访问该部分。 如下所示的是尾随停止函数:

inline void TriggerTrailingStop(void)
                        {
                                double price;
                                
                                if ((m_Position.Ticket == 0) || (m_Position.SL == 0)) return;
                                if (m_Position.EnableBreakEven) TriggerBreakeven(); else
                                {
                                        price = SymbolInfoDouble(_Symbol, (GetTerminalInfos().ChartMode == SYMBOL_CHART_MODE_LAST ? SYMBOL_LAST : (m_Position.IsBuy ? SYMBOL_ASK : SYMBOL_BID)));
                                        if (MathAbs(price - m_Position.SL) >= (m_Position.Gap * 2))
                                                ModifyPricePoints(m_Position.Ticket, m_Position.PriceOpen, (m_Position.SL + (m_Position.Gap * (m_Position.IsBuy ? 1 : -1))), m_Position.TP);
                                }
                        }

在盈亏平衡被触发并执行后,下次 EA 调用 TriggerTrailingStop 函数时,我们将检查移动(尾随)止损的可能性。

但在此之前,请注意盈亏平衡函数的实际调用所在。 尾随停止走势的触发机制比盈亏平衡走势稍微复杂一些。 在这种情况下,我们将以不同的方式进行操作。 盈亏平衡不依赖于资产、图表模式和市场类型,只有仓位的利润水平很重要;不同于盈亏平衡,尾随停止需要知道两件事:图表类型和仓位类型。

一些 EA 开发者有时不关心创建尾随停止触发器时所用的图表绘制方法。 在某些情况下,这是正确的做法。 如果资产在历史上曾有相对较高的点差(最佳卖家和最佳买家之间的差值),即使基于最后价格的图表,我们也可以忽略绘图模式。 因为如果走势在点差内,我们很可能会出现问题,因为止损订单会置于错误的点位。

这就是为什么若要正确开发这种触发器,应仔细地研究和理解资产如此重要的原因。 此处的所想就是捕捉资产价格,无论我们如何做。 但我们真的需要掌握这个价格。 一旦完成此操作后,我们将从止损所在的点位减去此价格。 在这种情况下,我们是在卖出还是买入并不重要 — 价格将自动转换为点数,替代以货币为单位的价格。 该数值应至少是我们在交易服务器上每次更新时始终计算的点数的两倍。 如果成功,我们将依据间隙值点数移动止损位置。 故此,间隙始终相同,周而往复。

这种触发机制在任何情况下都能很好地工作。 这有一个重要的细节:它极其轻量,非常迅捷,这非常重要。 这些触发器想象为捕鼠器。 如果机制太复杂、或执行时间长,老鼠最终会在陷阱触发之前抓起奶酪,并逃之夭夭。

还有一件事需要了解:为了调用上述函数,我们需要使用什么函数或事件处理程序? 许多人可能认为事件处理程序应该是 OnTick 函数。 对不对? 错! 为了解释这一点,我们移步到下一个主题。


为什么我们不应该使用 OnTick 作为触发器的调用者?

我知道,使用 OnTick 函数作为调用任何其它函数的这种方式可能非常诱人。 但这无疑是您能犯的最大错误。 正确的途径是使用 OnTime 事件,如下所示:

//+------------------------------------------------------------------+
int OnInit()
{
        manager = new C_Manager(def_MAGIC_NUMBER, user03, user02, user01, user04, user08);
        mouse = new C_Mouse(user05, user06, user07, user03, user02, user01);
        (*manager).CheckToleranceLevel();
        EventSetMillisecondTimer(100);

        return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
        delete manager;
        delete mouse;
        EventKillTimer();
}
//+------------------------------------------------------------------+
void OnTick() { }
//+------------------------------------------------------------------+
void OnTimer()
{
        (*manager).TriggerTrailingStop();
}
//+------------------------------------------------------------------+

请注意,在 OnInit 事件中,我们定义了一个 short 型数值,如此来生成 OnTime 事件。 我们调用 EventSetMillisecondTimer 函数来执行此操作。 在大多数情况下,您可以设置任何数值,从 50 毫秒开始。 但您还必须记住在 OnDeInit 事件中调用 EventKillTimer 函数。 以这种方式,EA 会解除 OnTime 事件,故无需 MetaTrader 5 平台再持续生成事件。 即使平台能设法解决了这个问题,并停止生成事件,释放系统也是一种很好的做法。 那么,在这种情况下,每 100 毫秒或每秒大约 10 次,我们将验证上面主题中显示的触发器。

但这并未回答这个问题:为什么我们不应该使用 OnTick 事件处理程序函数作为触发器调用方?其实上面的解释并没有回答这个问题。 但我们要更详细地研究一下,来理解为什么我们不应该这样做。

OnTick 事件在每次收到服务器交易的跳价时都会触发。 如果您查看柱线图,即使在 1 分钟图表上,您也不能真正了解正在发生的事情。 为此,有必要下调 HFT 等级(高频交易),更广为人知的是机构机器人。

许多人没有意识到,对于平台中运行的 EA 来说,若是安装在距离交易服务器数百公里的计算机上,这根本不可能。 与距离服务器几米远的专用服务器上运行的高频交易相比较,它们没有丝毫胜出的机会。 这是因为所谓的延迟,即数据到达服务器所需的时间。 那些玩在线游戏的人会明白我在说什么,但对于那些对此不熟悉的人,我会说延迟远高于交易服务器执行的操作频率。 换言之,不可能达到与高频交易相当的性能

回到 OnTick 事件的主题,我们可以说在短短 1 毫秒内,服务器可以触发 10 多次该类事件。 如果如此多的事件到达平台,并触发服务器通知的所有事件,那么您的 EA 一旦开始工作,平台就会崩溃。 这是因为它将陷于远超其处理器可以应对的太多事件。 这意味着无论一切如何组织,由于大量调用同一函数,它都无暇执行所需的操作,在本例中,它是尾随停止触发器。

它也许会发生,那么在这片刻间若不会实际发生,则平台将继续平稳运行。 不过,一旦系统检测到我们就位,就开始检查触发器,我们就会遇到严重的问题,因为平台崩溃的可能性非常高。

如果资产的波动性快速增长,这种可能性就会加剧。 这对于指数期货等资产尤其常见。 因此,不要尝试基于 OnTick 作为激发触发器的一种方式。 忘记这个 EA 事件处理程序。 它并非由我们凡人所用,而是让那些高频交易能够监控交易服务器。

如此,检查触发系统最合适的方法是使用 OnTime 事件。 它如此配置,令检查能在足够短的时间内完成,这般它就不会遭受品质损失,同时提供检查所有触发器的可能性。 以这种方式,我们就得到了一个安全、强大、安静和可靠的 EA。

还有另一个与触发尾随停止事件相关的问题。 一些 EA 系统在触发尾随停止之前实际上并不关心盈亏平衡。 它们从开仓的那一刻起就使用尾随停止。 这也许看起来有点奇怪,但实际上重点是操作系统或配置已经运用了这个概念。 在这种情况下,系统将与上面所示的系统非常相似,但所用的尾随距离有所不同。 不过,概念本身将保持不变。

除了这个模型之外,还有另一个模型,我们实际上没有尾随停止或盈亏平衡。 我们还有另一种系统,它保证在行情开始与我们的持仓相反的情况下离场。 它是一种不同类型的触发器,我们将在另一篇文章中对其进行研究。


使用挂单的尾随停止和盈亏平衡

如果您想拥有基于 OCO 订单系统的持仓管理,上面介绍的系统运行良好。 不过,这种 OCO 订单系统存在一个问题,即波动性。 当波动性非常高时,订单也许会被跳过,这可能导致不利的情况。

这个问题有一个“解决方案”,即利用挂单来保证离场。 然而,这个“解决方案”不能在对冲系统中实现,即它不能与所呈现的 EA 配套使用。 如果我们尝试在对冲账户上使用它,EA 将被踢出图表,因为它会让 C_Manager 类犯一个严重的错误。 不过,我们可以调整 C_Manager 类,以允许 EA 在对冲账户上有两笔相反方向的持仓。 如果您用的是净持结算账户,亦可做同样的事情,我将展示如何做。

但如果您仔细想想,在净持结算账户上开立一笔相反方向的持仓是没有意义的。 如果订单服务器捕获了挂单,最好向服务器发送两笔持仓的平仓请求。 这将令对冲账户上的 EA 表现与净持结算账户的行为相同。 它将利用挂单来平仓。

您喜欢这个想法吗? 在开始实施之前,还有一些细节和问题尚需考虑。

首先,挂单不一定会在您指定的点位执行。 挂单触发后都会按所处价位执行。 另一个问题是,如果 EA 出现严重故障,并且持仓或订单需要被取消或平仓,但此刻另一方也许没有交易对手。

但这也有一个优势:如果一切顺利,且与服务器的连接丢失,则具有相同交易量的相反方向的挂单将平仓(净持账户),或锁定价格(对冲账户)。

如您所见,这种方法各有其优点和缺点。

为了使用它,我们需要对 C_Manager 类进行一些修改。 这些修改很容易理解,如果您不想用它们,还可以复原。 不过,这里有一个重要的细节:如果您要用此方法,请注意不要删除 EA 已下达的挂单。 如果您这样做,则您就没有了负责平仓的支撑。

对于此系统,不建议在编译代码后再允许用户对其进行修改。 如果它不合适,您可以断开它与 EA 的连接。 它应该一直保持启用、或一直关闭。 为此,我们将在 C_Manager 类的代码中创建一个新定义。 参见下文:

//+------------------------------------------------------------------+
#define def_MAX_LEVERAGE                10
#define def_ORDER_FINISH                false
//+------------------------------------------------------------------+

当此定义设置为 true 时,系统将通过挂单使用停止方法。 这意味着您将不再有止盈点,因为这会令事情变得复杂很多,并可能导致另一方支撑不可用。 如果此参数设置为 false,您将用我们在本文初始主题中研究的盈亏平衡和尾随停止方法。 依此方式,您将用到 OCO 订单系统。 默认情况下,我将保留为 false。 如果您想采用本主题中介绍的方法,请将此值从 false 更改为 true,并重编译 EA。

现在我们需要修改按市价下单,或创建挂单的函数。 它们将如下所示:

//+------------------------------------------------------------------+
                void CreateOrder(const ENUM_ORDER_TYPE type, const double Price)
                        {
                                if ((m_StaticLeverage >= def_MAX_LEVERAGE) || (m_TicketPending > 0) || (m_bAccountHedging && (m_Position.Ticket > 0))) return;
                                m_TicketPending = C_Orders::CreateOrder(type, Price, (def_ORDER_FINISH ? 0 : m_InfosManager.FinanceStop), (def_ORDER_FINISH ? 0 : m_InfosManager.FinanceTake), m_InfosManager.Leverage, m_InfosManager.IsDayTrade);
                        }
//+------------------------------------------------------------------+  
                void ToMarket(const ENUM_ORDER_TYPE type)
                        {
                                ulong tmp;
                                
                                if ((m_StaticLeverage >= def_MAX_LEVERAGE) || (m_bAccountHedging && (m_Position.Ticket > 0))) return;
                                tmp = C_Orders::ToMarket(type, (def_ORDER_FINISH ? 0 : m_InfosManager.FinanceStop), (def_ORDER_FINISH ? 0 : m_InfosManager.FinanceTake), m_InfosManager.Leverage, m_InfosManager.IsDayTrade);
                                m_Position.Ticket = (m_bAccountHedging ? tmp : (m_Position.Ticket > 0 ? m_Position.Ticket : tmp));
                        }
//+------------------------------------------------------------------+

我们需要修改这些部分,以便无需实际创建止盈和止损价位。 当我们这样做时,服务器会明白不必创建这些价格,且您将拥有一个没有盈亏限价的订单。 您也许会害怕您发送的市价单实际上不包含止损,或所下挂单没有止损。 别担心。 为了了解到底发生了什么,您应该尝试该系统。 一旦此操作完成后,我们需要进行以下修改:

                void PendingToPosition(void)
                        {
                                ResetLastError();
                                if ((m_bAccountHedging) && (m_Position.Ticket > 0))
                                {
                                        if (def_ORDER_FINISH)
                                        {
                                                if (ClosePosition(m_Position.Ticket)) ZeroMemory(m_Position.Ticket);
                                                ClosePosition(m_TicketPending);                                         
                                        }else SetUserError(ERR_Unknown);
                                }else m_Position.Ticket = (m_Position.Ticket == 0 ? m_TicketPending : m_Position.Ticket);
                                m_TicketPending = 0;
                                if (_LastError != ERR_SUCCESS) UpdatePosition(m_Position.Ticket);
                                CheckToleranceLevel();
                        }

在此,当 EA 通知挂单已变成持仓时,如果我们在对冲账户上,且我们已有持仓,我们就可能会遇到问题。 在这种情况下,如果参数设置为 false,将生成错误消息。 如果设置为 true,我们发送一个请求来关闭原始持仓,并重置其内存区域。 我们还将关闭新的开仓。 请注意,如果与服务器的连接良好,我们应能够成功平仓,从而将我们在市场上的风险归零。

现在,我们需要系统创建一笔挂单,该挂单将作为平仓订单,即作为止损,该订单将保留在订单簿中。 这一点可能是整个系统中最关键的一点,因为如果没有很好地计划,您的帐户将遇到严重问题,即没有止损价位。 有因于此,您必须通过检查以下内容来了解 EA 将要做什么:

图例 01

图例 01. 我们所看到的挂单和持仓的点位

图例 01 中所示的窗口必须始终打开,以便您可以分析 EA 在服务器上执行的操作。 您不应该盲目相信 EA,无论它看起来多么可靠。

始终监控 EA 的意图。 如此,要令 EA 具有止损点,C_Manager 类必须创建一笔挂单。 它的创建方式如下:

                void UpdatePosition(const ulong ticket)
                        {
                                int ret;
                                double price;
                                
                                if ((ticket == 0) || (ticket != m_Position.Ticket)) return;
                                if (PositionSelectByTicket(m_Position.Ticket))
                                {
                                        ret = SetInfoPositions();
                                        if (def_ORDER_FINISH)
                                        {
                                                price = m_Position.PriceOpen + (FinanceToPoints(m_InfosManager.FinanceStop, m_Position.Leverage) * (m_Position.IsBuy ? -1 : 1));
                                                if (m_TicketPending > 0) if (OrderSelect(m_TicketPending))
                                                {
                                                        price = OrderGetDouble(ORDER_PRICE_OPEN);
                                                        C_Orders::RemoveOrderPendent(m_TicketPending);
                                                }
                                                m_TicketPending = C_Orders::CreateOrder(m_Position.IsBuy ? ORDER_TYPE_SELL : ORDER_TYPE_BUY, price, 0, 0, m_Position.Leverage, m_InfosManager.IsDayTrade);
                                        }
                                        m_StaticLeverage += (ret > 0 ? ret : 0);
                                }else
				{
					ZeroMemory(m_Position);
                                	if (def_ORDER_FINISH)
					{
						RemoveOrderPendent(m_TicketPending);
						m_TicketPending = 0;
					}
				}
                                ResetLastError();
                        }

首先,我们检查订单系统是否设置为 “true” 值。 如果满足此条件,我们计算价格点位以便开始组装,并使用挂单作为仓位止损。 接下来,我们检查订单是否已下。 如果是真,我们会捕获价格,并从账簿中删除订单。 一条或其它方式,我们都将尝试创建一笔新的挂单。 如果一切正确,我们将在订单簿中有一笔挂单,该挂单的作用是止损订单。

注意:如果平仓后,必须取消挂单。 这可以用以下代码行完成。

现在,我们需要修改 SetInfoPosition 函数,以便正确指示我们是否需要实现盈亏平衡,或者我们是否可以立即开始尾随停止。 新函数如下:

inline int SetInfoPositions(void)
                        {
                                double v1, v2;
                                int tmp = m_Position.Leverage;
                                
                                m_Position.Leverage = (int)(PositionGetDouble(POSITION_VOLUME) / GetTerminalInfos().VolMinimal);
                                m_Position.IsBuy = ((ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE)) == POSITION_TYPE_BUY;
                                m_Position.TP = PositionGetDouble(POSITION_TP);
                                v1 = m_Position.SL = PositionGetDouble(POSITION_SL);
                                v2 = m_Position.PriceOpen = PositionGetDouble(POSITION_PRICE_OPEN);
                                if (def_ORDER_FINISH) if (m_TicketPending > 0) if (OrderSelect(m_TicketPending)) v1 = OrderGetDouble(ORDER_PRICE_OPEN);
                                m_Position.EnableBreakEven = (def_ORDER_FINISH ? m_TicketPending == 0 : m_Position.EnableBreakEven) || (m_Position.IsBuy ? (v1 < v2) : (v1 > v2));
                                m_Position.Gap = FinanceToPoints(m_Trigger, m_Position.Leverage);

                                return m_Position.Leverage - tmp;
                        }

在此,我们进行一系列测试来捕获挂单所在的价格。 如果由于某种原因尚未创建挂单,则会导致盈亏平衡指标即刻启动,以便达到我们的目的。

到目前为止,在将挂单用作止损点位的系统中,盈亏平衡和尾随停止都不能在实际中使用。 为了实现这个系统,我们并不真正需要触发器,因为它已经配置好了:我们只需要实现一个移动挂单的系统。 对于盈亏平衡,为了实现走势,我们将添加以下内容

inline void TriggerBreakeven(void)
                        {
                                double price;
                                
                                if (PositionSelectByTicket(m_Position.Ticket))
                                        if (PositionGetDouble(POSITION_PROFIT) >= m_Trigger)
                                        {
                                                price = m_Position.PriceOpen + (GetTerminalInfos().PointPerTick * (m_Position.IsBuy ? 1 : -1));
                                                if (def_ORDER_FINISH)
                                                {
                                                        if (m_TicketPending > 0) m_Position.EnableBreakEven = !ModifyPricePoints(m_TicketPending, price, 0, 0);
                                                }else m_Position.EnableBreakEven = !ModifyPricePoints(m_Position.Ticket, m_Position.PriceOpen, price, m_Position.TP);
                                        }
                        }

在负责执行盈亏平衡的先前函数版本中,停止单价格正好等于持仓的开盘价。 许多交易者总是喜欢带着一些利润离开,即使是很小的利润。 故此,我决定修改函数,以便触发盈亏平衡时,EA 下达的订单距开盘价偏移 1 个基点。 因此,交易者将获得至少 1 个点数的利润。

该系统适用于任何资产或市场类型,因为我们用资产本身的数据来了解停止线应该在哪里。

一旦此操作完成后,我们检查是否基于挂单的止损模型。 如果是这样,我们检查挂单变量中是否有任何数值。如果有这样的值,我们会发送请求,将所下订单的点位更改到新位置。 如果我们是基于 OCO 订单的系统,我们将使用上述方法。 这些检查可能看起来毫无意义,但它们可以防止我们向服务器发送无效请求。

现在,我们来看看尾随停止函数在这种情况下是如何工作的:

inline void TriggerTrailingStop(void)
                        {
                                double price, v1;
                                
                                if ((m_Position.Ticket == 0) || (def_ORDER_FINISH ? m_TicketPending == 0 : m_Position.SL == 0)) return;
                                if (m_Position.EnableBreakEven) TriggerBreakeven(); else
                                {
                                        price = SymbolInfoDouble(_Symbol, (GetTerminalInfos().ChartMode == SYMBOL_CHART_MODE_LAST ? SYMBOL_LAST : (m_Position.IsBuy ? SYMBOL_ASK : SYMBOL_BID)));
                                        v1 = m_Position.SL;
                                        if (def_ORDER_FINISH) if (OrderSelect(m_TicketPending)) v1 = OrderGetDouble(ORDER_PRICE_OPEN);
                                        if (v1 > 0) if (MathAbs(price - v1) >= (m_Position.Gap * 2)) 
                                        {
                                                price = v1 + (m_Position.Gap * (m_Position.IsBuy ? 1 : -1));
                                                if (def_ORDER_FINISH) ModifyPricePoints(m_TicketPending, price, 0, 0);
                                                else ModifyPricePoints(m_Position.Ticket, m_Position.PriceOpen, price, m_Position.TP);
                                        }
                                }
                        }

这个函数乍一看似乎很奇怪,因为我用了对大多数人来说不寻常的东西。 我们看看这里发生了什么。 首先,我们检查是否有任何持仓,这是最简单的部分。 但奇怪的是三元运算符,在这里使用起来很不寻常。 我们在这里区分,检查是依据挂单票证、亦或止损价格值进行的。 此比较将与持仓比较结合使用。 如果测试表明不需要执行任何操作,我们就简单地返回到调用方。

如果需要做些事情,我们会测试盈亏平衡。 如果它已经被执行,我们开始捕获当前资产价格,以便检查我们是否可以激活尾随停止。 由于我们可能需要放置挂单的价格,且分解与此相同,因此我们把可能用作止损线的值赋予临时变量。 但它也许会发生,以便我们使用挂单作为止损点。 在这种情况下,它必须移动,以便我们捕获它所在的价格。 我们执行分解,以便检查是否应该移动止损价位。 如果可能,我们调整订单价格,至其应移到的位置,并相应地移动挂单或止损线。 实际的移动将取决于我们所用的系统。

下面的视频演示了该系统的操作情况。 对于那些想象这是不同或不起作用的人,请观看视频并得出自己的结论。 尽管为了理解正在发生的事情,最好的办法是编译 EA,并在模拟账户上自行测试。 以这样的方式,对整个系统的理解将更加扎实和清晰。

视频 01. 通过挂单的停止系统演示。


结束语

在本文中,我涵盖了最简单的触发系统,该系统可以内置到许多人喜欢、或他们希望拥有的 EA 当中。 不过,如果您想在投资组合设置中使用 EA,则不适合使用该系统。 在这种情况下,我建议采用手动系统。 但这只是我的建议,因为我不知道您将如何运用这些知识。

附件包含完整的代码,您可以研究,并了解有关此类机制的更多信息。 在此代码中,您最初将拥有一个使用止损线的 EA。 若要用挂单作为止损,您需要按照本文所述修改 EA。

现在,我们有了实现其余步骤所需的最低自动化。 在下一篇文章中,我们将看看如何创建 100% 自动化的 EA。 祝好运!

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

附加的文件 |
构建自动运行的 EA(第 09 部分):自动化(II) 构建自动运行的 EA(第 09 部分):自动化(II)
如果您无法控制其调度表,则自动化就意味着毫无意义。 没有工人能够一天 24 小时高效工作。 然而,许多人认为自动化系统理所当然地每天 24 小时运行。 但为 EA 设置工作时间范围总是有好处的。 在本文中,我们将研究如何正确设置这样的时间范围。
DoEasy. 控件(第三十一部分):滚动条控件内内容的滚动 DoEasy. 控件(第三十一部分):滚动条控件内内容的滚动
在本文中,我将实现通过按钮滚动水平滚动条容器内容的功能。
您应该知道的 MQL5 向导技术(第 05 部分):马尔可夫(Markov)链 您应该知道的 MQL5 向导技术(第 05 部分):马尔可夫(Markov)链
马尔可夫(Markov)链是一个强大的数学工具,能够针对包括金融在内的各个领域的时间序列数据进行建模和预测。 在金融时间序列建模和预测中,马尔可夫链通常用于模拟金融资产随时间的演变,例如股票价格或汇率。 马尔可夫链模型的主要优点之一是其简单性和易用性。
种群优化算法:萤火虫算法(FA) 种群优化算法:萤火虫算法(FA)
在本文中,我将研究萤火虫算法(FA)优化方法。 致谢优化修订,该算法已从局外人变成了评级表上的真正领先者。