English Русский Español Deutsch 日本語 Português
preview
实现 Deus EA:使用 MQL5 中的 RSI 和移动平均线进行自动交易

实现 Deus EA:使用 MQL5 中的 RSI 和移动平均线进行自动交易

MetaTrader 5交易 | 21 三月 2025, 08:55
966 0
Duke825
[删除]

概述

在本文中,我们将研究 Deus EA 的基本组件,包括其交易逻辑、参数设置和实现所需的 MQL5 代码。本文旨在为您提供开发和增强交易算法所需的知识和工具。通过使用 Deus EA,您将能够探索自动交易的世界,并能够为您的交易努力发现新的机会。      

我们将研究 Deus EA 的功能,这是一种使用 MQL5 构建的自动交易技术。我们的讨论将集中在 Deus EA 如何结合移动平均线和相对强弱指数(RSI)来做出交易选择。通过分析这些指标,EA 确定了市场中的最佳入场和退出点,以最大限度地提高交易盈利能力,同时最大限度地降低风险。

Deus EA 是为 MetaTrader 5 平台设计的自动交易系统,可根据移动平均线和相对强弱指数(RSI)生成买入和卖出信号。通过识别市场趋势和检测超买或超卖情况,它试图增强交易决策。此外,它还包括风险管理工具,如止损、止盈订单和追踪止损。 


Deus EA 概述 

Deus EA 依靠相对强弱指数 (RSI) 和移动平均线等指标来自动做出交易决策。该 EA 的目标是通过使用这些指标来产生可操作的买入和卖出建议,从而提高交易绩效并有效管理风险。

以下是 Deus EA 的关键要素:

  1. 技术措施:
  • 相对强弱指数(RSI):这个动量振荡指标衡量价格变动的速度和方式,这有助于确定市场何时超买或超卖,并对市场走势做出迅速反应。在我们的案例中,EA 将采用简短的 7 天 RSI 时间范围,超买阈值设置为 35,超卖阈值设置为 15。
  • 移动平均线(MA):为了找到一段时间内的趋势,移动平均线将价格数据调平。我们将在 Deus EA 中使用 25 期简单移动平均线(SMA)来过滤交易信号并确定市场的总体方向。 


          2.交易逻辑:
    • 买入信号:当价格高于移动平均线和 RSI 时,它显示超卖状态(低于15),表明价格可能上涨,并发出买入订单。

    • 卖出信号:如果价格低于移动平均线和 RSI,则表示超买状态(超过 35),表明可能呈下跌趋势,并发出卖出订单。


         3.风险管理:
    • 止损与止盈:在我们的 EA 中,我们包含可定制的止损水平和止盈参数,每个参数设置为 50 点,以帮助管理风险和锁定利润。
    • 追踪止损:我们使用 25 个点的追踪止损来调整止损水平,因为价格走势有利,旨在确保利润,同时只要市场朝着预期的方向发展,交易就会保持开放。

          4.订单管理:

    • 仓位管理:EA 根据交易信号,在开立新头寸之前关闭任何现有头寸,以确保一次只开立一个头寸。

    Deus EA 具有初始化、分时处理、开仓和平仓以及追踪止损调整等功能。它是使用 MetaTrader5 中使用的脚本语言 MQL5 实现的。该编程确保遵循风险管理指南并有效处理交易信号。

    Deus 有助于自动化交易程序,减少情绪性决策,并通过使用这些功能来改善交易结果。本文将为理解 Deus EA 的设计思想和功能提供基础。 


      MQL5 中的实现

      首先,我们需要建立交易头寸。我们通过包含一个专门用于开立头寸的文件来开立交易头寸。 

      #include <Trade\Trade.mqh>
      CTrade trade;

      在这里,我们使用 include 文件来包含 trade 库。这将使 Deus EA 能够访问交易操作功能。此时,我们还定义了 CTrade 类,它为开展交易活动提供了高级别的支持。由于包含了这个文件,EA 就可以使用 CTrade 类来管理交易。在整个 EA 中,该对象将用于执行各种交易任务,包括开仓、修改仓位和平仓。

      在本节中,我们将研究 Deus EA 的关键输入参数。Deus EA 是一种复杂的交易算法,它使用移动平均线和 RSI 指标来寻找交易机会。通过调整这些参数,交易者可以使 EA 的行为最适合他们独特的交易策略和风险承受能力。

      输入参数如下:

      input double Lots = 0.1;                     // Lot size
      input double StopLoss = 50;                  // Stop loss in points
      input double TakeProfit = 50;                // Take profit in points
      input double TrailingStop = 25;              // Trailing stop in points
      

      1. Lots(交易量)

      input double Lots = 0.1;                     // Lot size

      每笔交易的交易量由 Lots 选项指定。在此实例中,EA 配置为每次交易 0.1 手。交易者可以通过调整手数来管理其市场风险敞口。较小的手数降低了可能的风险和利润,而较大的手数不仅提高了可能的利润,还增加了风险。为了平衡风险和收益,选择正确的手数至关重要。 

             2.StopLoss(止损点数)

      input double StopLoss = 50;                  // Stop loss in points         

      每笔交易的最大允许损失由 StopLoss 选项定义,在我们的例子中,它设置为 50 点。为了阻止未来的损失,如果市场在这一点之后不利于交易,头寸将自动关闭。这将保护您的交易账户免受重大损失。  

             3.TakeProfit(止盈点数)

      input double TakeProfit = 50;                // Take profit in points

      我们通过 TakeProfit 参数将每笔交易的利润目标设置为 50 点。为了确保利润,当市场向有利于交易的方向发生如此大的变化时,头寸将自动关闭。这将确保在市场状况出现任何潜在逆转之前获得收益,因此,这将提高盈利能力。

             4.TrailingStop(追踪止损点数)

      input double TrailingStop = 25;              // Trailing stop in points

      我们通过 TrailingStop 参数引入止损,该参数的变化有利于交易。当市场向有利于交易的方向波动时,最初设定在入场价 25 个点的追踪止损会进行调整以锁定利润。此功能将帮助交易者从长期的市场波动中获利,同时保障他们的收益。

      RSI 指标参数:

      input int RSI_Period = 7;                   // RSI period
      input double RSI_Overbought = 35.0;         // RSI overbought level
      input double RSI_Oversold = 15.0;           // RSI oversold level

              5.RSI_Period (RSI 计算周期数)

      input int RSI_Period = 7;                   // RSI period
            

      用于生成相对强弱指数 (RSI) 的周期数由 RSI_period 参数指定,在我们的例子中将其设置为 7。衡量价格变动速度和变化的动量振荡指标是 RSI。RSI 对短时间段内(例如 7)的近期价格走势更为敏感,这有助于快速识别超买或超卖的情况。

             6.RSI_Overbought (RSI 超买水平)

      input double RSI_Overbought = 35.0;  

      判断超买情况的阈值由 RSI_Overbought 参数定义,设置为 35.0。一般来说,超买水平可能是 70,但使用这种技术,35.0 表示更激进的卖出仓位。当 RSI 高于此阈值时,EA 会触发卖出操作,表明市场可能即将出现下跌逆转。  

               7.RSI_Oversold(RSI 超卖水平) 

      input double RSI_Oversold = 15.0;           // RSI oversold level
      

      超卖条件阈值由 RSI_Oversold 参数定义,其值为 15.0。尽管这种方法采用了更保守的水平来指示可能的买入机会,但典型的超卖水平可能是 30。当 RSI 跌破该阈值时,EA 会触发买入操作,因为它预感到市场可能出现上行逆转。

      移动平均线参数

      input int MA_Period = 25;                   // Moving Average period
      input ENUM_MA_METHOD MA_Method = MODE_SMA// Moving Average method
      input ENUM_APPLIED_PRICE MA_Price = PRICE_CLOSE; // Applied price for MA

             8.MA_Period (移动平均周期数)

      input int MA_Period = 25;                   // Moving Average period

       移动平均线 (MA) 的计算周期数由 MA_Period 参数决定,其值为 25。MA 对价格数据进行平滑处理,以发现趋势。25 个周期数的窗口将为市场趋势提供全面的视角,它不仅会消除短期噪音,还会对值得注意的价格变化做出反应。    

             9.MA_Method (移动平均方法)

      Moving Average period
      input ENUM_MA_METHOD MA_Method = MODE_SMA// Moving Average method

         在这种情况下使用的移动平均线类型,即简单移动平均线(SMA),由 MA_Method 选项决定。SMA 是一个简单的趋势指标,计算给定时期的收盘价平均值。对于不同的敏感度,可以采用指数移动平均线(EMA)等替代技术,但简单移动平均线(SMA)是一种可靠且稳定的趋势指标。

            10.MA_Price (应用于 MA 的价格)

      input ENUM_APPLIED_PRICE MA_Price = PRICE_CLOSE; // Applied price for MA
      

      移动平均线计算所使用的价格类型由 MA_Price 选项指定,该选项设置为价格 PRICE_CLOSE。这表明 MA 是使用收盘价确定的,由于收盘价代表交易时段的收盘价,因此经常使用收盘价。通过做出这一决定,MA 可以保证提供对总体市场趋势的可靠指示。

      Deus EA 的交易行为和风险管理在很大程度上取决于其输入参数。交易者可以通过调整这些参数来调整 EA,以更好地适应他们独特的交易目标和当前的市场状况,这些参数包括交易量、风险控制、指标周期数和阈值。为了在自动交易中充分利用 Deus EA,理解和适当修改这些设置至关重要。

      然后,我们要根据移动平均线和 RSI 指标讨论我们的 EA 新变量。通过了解这些因素,我们将能够了解 EA 如何处理交易执行和分析市场数据。 

      //--- Variables
      double rsiValue;  // RSI value
      double maValue;   // Moving Average value
      double Ask;
      double Bid;
      double Close; // Initializing Close array with two elements

      RSI 值:

      double rsiValue;                            // RSI value

      相对强弱指数 (RSI) 的当前值存储在 rsiValue 变量中。作为动量振荡指标,RSI 通过计算价格变化的速率和变化来帮助确定市场何时超买或超卖。

      价格类型和指定的 RSI 周期用于确定 RSI 值。Deus EA 使用用户定义的参数和最新的价格数据来计算 RSI。

      当 RSI 值低于 RSI_Oversold 水平时,EA 将其解释为买入信号。这意味着市场可能超卖,并可能出现上行逆转。

      另一方面,如果 RSI 值超过 RSI_Overbought 水平,则是卖出信号。这意味着市场可能超买,并可能向下回落。 

      移动平均值:

      double maValue;                             // Moving Average value

      移动平均线 (MA) 的当前值存储在 maValue 变量中。通过在预定的时间框架内平滑价格数据,该指标有助于识别趋势。

      移动平均线是使用技术、价格类型和选定的周期数来计算的。指定周期数的收盘价用于计算我们的 EA 中的 MA。

      趋势:目前的市场趋势得到了 MA 值的支持。当价格高于 MA 时,EA 认为市场处于上涨趋势,而当价格低于 MA 时,EA 认为市场处于下跌趋势。

      入场信号:交易信号的产生取决于 RSI 和 MA 值之间的关系。例如,如果之前的收盘价高于 MA 值且 RSI 低于 RSI_Oversold 水平,则买入信号被视为合法。RSI 和 MA 值在 Deus EA 中结合在一起,以帮助其做出明智的交易决策。

      double Ask;

      资产的当前要价存储在 Ask 变量中,这是交易者购买该资产的价格。它设置了 OpenPosition 函数中买入订单的入场价格。要价是当时购买该资产所能找到的最佳价格,对这一成本的精确监控保证了买入订单的适当提交。 

      double Bid;

      资产的当前出价记录在 Bid 变量中,这是该资产向交易者出售的价格。它设置了 OpenPosition 函数中卖出订单的入场价格。出售资产所能获得的最佳价格反映在出价中,

      double Close[];

      这个时期的资产收盘价存储在 Close 数组中。在此 EA 中,它被放大以存储最新使用的值。该数组用于产生交易信号并分析价格走势。为了决定是否进入买入或卖出信号,需要将该值与前一时期(Close[1])和最近一时期(Close[0])的收盘价进行比较。这种比较将帮助我们判断价格是上涨还是下跌。 

      void ApplyTrailingStop();

      此函数将有助于实现追踪止损机制。如果当前市场价格有利于仓位的止损,该函数将遍历所有未平仓仓位并修改止损。该函数通过设置追踪止损,确保即使市场价格发生与交易相反的变化,止损仍保持在最有利的位置。

      void OpenPosition(CTrade trade, int orderType);

      根据订单类型,该方法用于开设新的交易头寸。该函数根据订单类型确定止盈、止损和入场价格。交易是通过使用 CTrade 对象计算的参数来执行的。这将有助于 EA 生成可能对启动市场交易至关重要的信号。

      void ClosePositions(int orderType);

      通过此函数,可以关闭特定订单类型的交易头寸。所有未平仓头寸都会被迭代,符合指定订单类型的头寸将被该函数关闭。这将有助于消除不再符合交易策略或市场状况的头寸,从而加强交易管理。

      //--- Function prototypes
      void ApplyTrailingStop();
      void OpenPosition(CTrade trade, int orderType);

      然后,我们将这些函数原型结合起来,使 EA 能够有效地处理交易头寸。OpenPosition 方法根据市场情况开始交易,ClosePositions 函数根据需要控制并关闭交易,ApplyTrailingStop 函数通过修改止损来改善交易管理。所有这些函数的结合使得 EA 能够对市场变化做出快速反应并有效地开展交易。 

      现在让我们转到 OnInit 函数,Deus EA 使用 OnInit 函数来启动交易。其目的是根据移动平均线和 RSI 指标进行交易。 

      //+------------------------------------------------------------------+
      //| Expert initialization function                .        |
      //+------------------------------------------------------------------+
      int OnInit()
        {
         Print("Deus  EA initialized successfully.");
         return(INIT_SUCCEEDED);
        }

      当终端启动或 EA 加载到图表中时,OnInit 函数都会被调用一次。初始化变量、建立指标句柄以及执行任何其他需要使用此函数的配置操作。然后我们将其各部分分解如下:  

       
         Print("Deus  EA initialized successfully.");

      这行代码的目的是将确认初始化成功完成的消息打印到专家 (EA) 日志中。日志记录是每个 EA 的关键组成部分,这样,我们就将能够验证 EA 是否已加载并初始化且没有任何问题。在调试和确保 EA 已准备好开始处理市场数据和执行交易时它也很有用。 

      return(INIT_SUCCEEDED);
        }

      return (INIT_SUCCEEDED); 语句用于通知 MetaTrader 平台初始化过程已完成。EA 需要返回 INIT_SUCCEEDED 才能进入下一阶段,例如 OnTick 函数,这是执行主要交易逻辑的地方。如果初始化因任何原因失败,该函数可能会返回 INIT_FAILED,停止 EA 运行并避免运行期间的潜在故障。 

      然后,我们来看看 OnDeinit 函数,这个函数对于保持 EA 的可靠性和完整性至关重要。我们将讨论此函数的作用。当 EA 重新编译时,它会被从图表中删除。此操作将激活 OnDeinit 函数并为其提供执行清理任务的机会,并确保适当释放资源并完成任何最后一刻的步骤。 

      //+------------------------------------------------------------------+
      //| Expert deinitialization function                                 |
      //+------------------------------------------------------------------+
      void OnDeinit(const int reason)
        {
         Print("Deus  EA deinitialized. Reason: ", reason);
        }

      OnDeinit 函数中的 reason 参数提供了取消初始化背后的原因。调试和找出 EA 被取消初始化的原因可以得到帮助。我们使用 Deus EA 中的 print 函数来记录这个原因。

      void OnDeinit(const int reason)
        {
         Print("Deus  EA deinitialized. Reason: ", reason);
        }

      您可以通过查看此简单的日志来确定EA是否被明确删除、重新编译或终端关闭的结果,该日志可以在开发和测试阶段提供有见地的信息。

      尽管去初始化原因是我们当前的 OnDeinit 实现记录的唯一原因,但此函数可以扩展到任何必要的清理程序。例如,您可能需要关闭任何打开的资源、释放文件句柄或保存当前状态。可以避免资源泄漏,并且可以通过适当的清理来保证EA的干净重新初始化。在可靠性和稳定性至关重要的实时交易情况下,这一点至关重要。正确的处理保证了早期运行的性能问题不会干扰 EA 重新加载或重启的能力。

      我们现在转到 OnTick 函数,OnTick 函数对于 EA 的实时决策过程至关重要。每次收到新的价格报价时,都会调用此函数,然后它使 EA 能够评估市场状态并使用预先建立的技术进行交易。以下是 OnTick 函数的主要功能以及它如何组合 Deus EA 的策略组件:

      • 获取市场信息; 

      当 OnTick 函数首次启动时,它帮助获取尽可能多的市场数据。

          Ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
          Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
          ArrayResize(Close, 2);
          Close[0] = iClose(_Symbol, _Period, 0);
          Close[1] = iClose(_Symbol, _Period, 1);

        此代码保存最近的收盘价并获取卖价和买价。为了确保 Close 数组有足够的空间来存储最近的收盘价,使用了 ArrayResize。

        • 技术指标的计算; 

        移动平均线和相对强弱指数由算法计算。

         //--- Calculate RSI value
           rsiValue = iRSI(_Symbol, _Period, RSI_Period, PRICE_CLOSE, 0);
           if (rsiValue == WRONG_VALUE)
             {
              Print("Error calculating RSI");
              return;
             }
           
           //--- Calculate Moving Average value
           maValue = iMA(_Symbol, _Period, MA_Period, 0, MA_Method, MA_Price, 0);
           if (maValue == WRONG_VALUE)
             {
              Print("Error calculating Moving Average");
              return;
             }

          MA 值有助于确定趋势方向,RSI 值指示超买或超卖情况。在继续检查之前,要确保数字准确。

          • 交易信号的生成;计算指标后,该函数寻找买入和卖出信号:
            //--- Check for Buy Signal
             if(rsiValue < RSI_Oversold && Close[1] > maValue)
               {
                if(PositionsTotal() == 0)
                  {
                   ClosePositions(ORDER_TYPE_SELL);
                   OpenPosition(ORDER_TYPE_BUY);
                  }
               }
             
             //--- Check for Sell Signal
             if(rsiValue > RSI_Overbought && Close[1] < maValue)
               {
                if(PositionsTotal() == 0)
                  {
                   ClosePositions(ORDER_TYPE_BUY);
                   OpenPosition(ORDER_TYPE_SELL);
                  }
             }

            当现在的收盘价高于移动平均线且 RSI 低于超卖阈值时,发出买入信号。这种情况预示着可能出现上行逆转。 

            当现在的收盘价低于移动平均线且 RSI 低于超买阈值时,发出卖出信号。这种情况预示着可能出现下行逆转。

            • 追踪止损的应用;为了最大限度地减少损失并确保盈利,OnTick 函数采用了应用追踪止损的逻辑。
               //--- Apply trailing stop if specified
               if (TrailingStop > 0)
                 {
                  ApplyTrailingStop();
                 }

              当设置了追踪止损参数时,此部分确保追踪止损机制已启动。为了锁定收益,ApplyTrailingStop 函数会在价格朝期望方向变动时修改止损水平。

              • 开仓和平仓:使用开仓,OpenPosition 函数在确定入场价、止损和止盈水平后尝试开仓。平仓;ClosePositions 函数会迭代所有仓位,并关闭与给定订单类型对应的仓位。

              这解释了 Deus EA 如何通过 OnTick 函数动态地适应市场情况。此函数使用 RSI 和 MA 指标产生交易信号和追踪止损以保障盈利。通过这种策略,EA 既能保证保护收益,又能对市场变化做出反应。以下是 OnTick 函数的完整代码:

              //+------------------------------------------------------------------+
              //| Expert tick function                                             |
              //+------------------------------------------------------------------+
              void OnTick()
                {
                  Ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
                  Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
                  ArrayResize(Close, 2);
                  Close[0] = iClose(_Symbol, _Period, 0);
                  Close[1] = iClose(_Symbol, _Period, 1);
                  
                  
                 //--- Calculate RSI value
                 rsiValue = iRSI(_Symbol, _Period, RSI_Period, PRICE_CLOSE, 0);
                 if (rsiValue == WRONG_VALUE)
                   {
                    Print("Error calculating RSI");
                    return;
                   }
                 
                 //--- Calculate Moving Average value
                 maValue = iMA(_Symbol, _Period, MA_Period, 0, MA_Method, MA_Price, 0);
                 if (maValue == WRONG_VALUE)
                   {
                    Print("Error calculating Moving Average");
                    return;
                   }
              
                 //--- Check for Buy Signal
                 if(rsiValue < RSI_Oversold && Close[1] > maValue)
                   {
                    if(PositionsTotal() == 0)
                      {
                       ClosePositions(ORDER_TYPE_SELL);
                       OpenPosition(ORDER_TYPE_BUY);
                      }
                   }
                 
                 //--- Check for Sell Signal
                 if(rsiValue > RSI_Overbought && Close[1] < maValue)
                   {
                    if(PositionsTotal() == 0)
                      {
                       ClosePositions(ORDER_TYPE_BUY);
                       OpenPosition(ORDER_TYPE_SELL);
                      }
                 }
                 
                 //--- Apply trailing stop if specified
                 if (TrailingStop > 0)
                   {
                    ApplyTrailingStop();
                   }

              既然我们已经完成了 OnTick 函数,现在让我们自由地看一下我们的 EA 的功能函数。对于 Deus EA 根据 RSI 和移动平均指标的信号执行交易来说,open 函数至关重要。该函数可确保准确下达买卖订单,并考虑到风险管理因素。

              void OpenPosition(int orderType)

              要下达的订单类型由 OpenPosition 函数接受的唯一参数订单类型决定。对于买入和卖出订单,这可能分别是 ORDER_TYPE_BUY 或 ORDER_TYPE_SELL。订单类型决定函数内的订单价格。

              double price = (orderType == ORDER_TYPE_BUY) ? Ask : Bid;

              使用 {Ask} 价格作为买入订单,使用 {Bid} 价格作为卖出订单。

              为了控制风险,确保利润,止损(SL)和止盈(TP)阈值确定为: 

              double sl = (orderType == ORDER_TYPE_BUY) ? price - StopLoss * _Point : price + StopLoss * _Point;
              double tp = (orderType == ORDER_TYPE_BUY) ? price + TakeProfit * _Point : price - TakeProfit * _Point;

              对于买入订单,止盈设置在订单价格上方,止损设置在订单价格下方。卖单的止盈和止损分别位于订单价格的下方和上方。CTrade 类中的 PositionOpen 函数用于开立真实仓位:

              bool result = trade.PositionOpen(_Symbol, orderType, Lots, price, sl, tp, "Deus  EA");
                 

              该技术需要几个参数: 

              • -{ Symbol}:用于交易的交易品种,例如 EURUSD。
              • -{ orderType}:订单类型(卖出或买入)。
              • -"Lots":订单的手数大小。
              • -{price}:订单的买入价或卖出价。
              • -{sI}:计算止损的水平 
              • -{tp}:确定的获利阈值。
              • -“Deus EA”:与订单相关的声明。

              在尝试打开该仓位后,该函数会验证结果,并在必要时记录一条消息。

              if(result)
                   {
                    Print("Order opened successfully. Type: ", orderType, ", Price: ", price);
                   }
                 else
                   {
                    Print("Failed to open order. Error code: ", GetLastError());
                   }
                }

              如果订单成功打开,则会打印出确认信息。如果订单无法打开,则使用 GetLastError 来获取问题代码,然后记下该代码以进行故障排除。 

              开仓函数完整代码如下:

              //+------------------------------------------------------------------+
              //| Function to open a position                          |
              //+------------------------------------------------------------------+
              void OpenPosition(int orderType)
                {
                 double price = (orderType == ORDER_TYPE_BUY) ? Ask : Bid;
                 double sl = (orderType == ORDER_TYPE_BUY) ? price - StopLoss * _Point : price + StopLoss * _Point;
                 double tp = (orderType == ORDER_TYPE_BUY) ? price + TakeProfit * _Point : price - TakeProfit * _Point;
                 
                 bool result = trade.PositionOpen(_Symbol, orderType, Lots, price, sl, tp, "Deus  EA");
                 
                 if(result)
                   {
                    Print("Order opened successfully. Type: ", orderType, ", Price: ", price);
                   }
                 else
                   {
                    Print("Failed to open order. Error code: ", GetLastError());
                   }
                }  
               )    

              我们已经完成了一个功能函数,现在让我们看一下另一个功能函数,即平仓函数。为了保证通过交易策略参数终止不需要的仓位,Deus EA 的 ClosePositions 函数至关重要。当满足某些条件时,此功能用于管理特定类型(买入或卖出)的平仓逻辑。让我们来研究一下此函数的操作及其对更广泛计划的意义。 

              void OpenPosition(int orderType)

              要关闭的仓位类型由单个参数 orderType 指定,该参数由 Closepositions 函数采用。ORDER_TYPE_SELL 或 ORDER_TYPE_BUY 是此参数的可能值。此函数循环遍历此时所有未平仓头寸并关闭相关头寸。  

              for(int i = PositionsTotal() - 1; i >= 0; i--)
                   {
                    if(PositionSelectByIndex(i))
                      {
                       if(PositionGetInteger(POSITION_TYPE) == orderType)
                         {
                          if(!trade.PositionClose(ticket)
                            {
                             Print("Failed to close position. Error code: ", GetLastError());
                            }
                        }
                   }
                }

              循环从最后一点开始向后推进。由于关闭一个仓位会降低仓位的总数,因此前向迭代循环可能会被中断,从而需要进行反向迭代。PositionSelectByIndex(i) 用于选择给定索引 {i} 处的仓位。

              该函数验证所选位置是否与循环中给定的 {orderType} 匹配。

              if(PositionGetInteger(POSITION_TYPE) == orderType)

              如果 {orderType} 不等于该值,则不应平仓。如果类型匹配,该函数将尝试平仓。

              if(!trade.PositionClose(ticket)
                            {
                             Print("Failed to close position. Error code: ", GetLastError());
                            }
                        }
                   }
                }

              通过尝试根据其编号 {trade.PositionClose(ticket)}) 来识别仓位,可以关闭仓位。如果平仓失败,则会打印一条错误消息,其中包含通过 GetLastError() 获取的错误代码。这有助于找出无法平仓的原因并有助于排除故障。

              当达到一定的利润水平时,Deus EA 可以通过平仓获利仓位来锁定利润。这是通过确保在特定条件下关闭选定的仓位来实现的。

              平仓函数完整代码如下:

              //+------------------------------------------------------------------+
              //| Function to close positions                                      |
              //+------------------------------------------------------------------+
              void ClosePositions(int orderType)
                {
                 for(int i = PositionsTotal() - 1; i >= 0; i--)
                   {
                    if(PositionSelectByIndex(i))
                      {
                       if(PositionGetInteger(POSITION_TYPE) == orderType)
                         {
                          if(!trade.PositionClose(ticket)
                            {
                             Print("Failed to close position. Error code: ", GetLastError());
                            }
                        }
                   }
                }
              

              最后,让我们转到最后一个功能函数,它是一个应用追踪止损的函数。您可以通过关闭亏损交易来停止进一步的损失。遵循指导原则,例如不要同时持有买入和卖出仓位,以及进行对冲。当市场价格转向有利于未平仓头寸时,追踪止损会修改止损水平。Deus EA 中的 ApplyTrabingStop 方法可确保有效应用此功能。追踪止损限制了潜在损失,同时通过跟踪市场波动锁定了利润。让我们讨论一下该函数的工作原理。

              void ApplyTrailingStop()

              由于这适用于当前交易品种上的所有未平仓头寸,因此 ApplyTrailingStop 方法不需要任何参数。与 ClosePositions 函数类似,该函数首先迭代所有未平仓头寸: 

              for (int i = PositionsTotal() - 1; i >= 0; i--)
                   {
                    if (PositionSelectByIndex(i) && PositionGetSymbol() == _Symbol)

              循环从最后一个位置开始向后推进。 

              -{PositionSelectByIndex(i)}:此函数选择索引{i} 处的条目。使用 {PositionGetSymbol()==_Symbol} 验证该仓位是否与活跃交易品种相关联。

              该函数使用追踪止损的距离和当前市场价格来确定新的止损水平:

               double price = (PositionGetInteger(POSITION_TYPE) == ORDER_TYPE_BUY) ? Bid : Ask;
               double sl = (PositionGetInteger(POSITION_TYPE) == ORDER_TYPE_BUY) ? price - TrailingStop * _Point : price + TrailingStop * _Point;
                       

              买入仓位的追踪止损设置在 {Bid} 价格下方。对于卖出交易,追踪止损位于 {Ask} 价格上方。然后,该函数在确定是否合适后,使用 PositionModify 应用新的止损水平: 

              if (PositionGetInteger(POSITION_TYPE) == ORDER_TYPE_BUY && PositionGetDouble(POSITION_SL) < sl)
                         {
                          if (!trade.PositionModify(PositionGetInteger(POSITION_TICKET), sl, PositionGetDouble(POSITION_TP)))
                            {
                             Print("Failed to modify position. Error code: ", GetLastError());
                            }
                         }
                       else if (PositionGetInteger(POSITION_TYPE) == ORDER_TYPE_SELL && PositionGetDouble(POSITION_SL) > sl)
                         {
                          if (!trade.PositionModify(PositionGetInteger(POSITION_TICKET), sl, PositionGetDouble(POSITION_TP)))
                            {
                             Print("Failed to modify position. Error code: ", GetLastError());
                            }
                         }
                      }

              仅当新的止损水平({sI}) 超过现有止损时,您仓位的止损才会发生变化。此外,当新的止损水平低于现有止损水平时,卖出仓位的止损也会更新。

              如果仓位修改不成功,则会打印包含错误代码的错误消息。这有助于排除故障,也有助于弄清未使用追踪止损的原因。

              应用追踪止损函数的完整代码如下:

              //+------------------------------------------------------------------+
              //| Function to apply trailing stop                                  |
              //+------------------------------------------------------------------+
              void ApplyTrailingStop()
                {
                 for (int i = PositionsTotal() - 1; i >= 0; i--)
                   {
                    if (PositionSelectByIndex(i) && PositionGetSymbol() == _Symbol)
                      {
                       double price = (PositionGetInteger(POSITION_TYPE) == ORDER_TYPE_BUY) ? Bid : Ask;
                       double sl = (PositionGetInteger(POSITION_TYPE) == ORDER_TYPE_BUY) ? price - TrailingStop * _Point : price + TrailingStop * _Point;
                       
                       if (PositionGetInteger(POSITION_TYPE) == ORDER_TYPE_BUY && PositionGetDouble(POSITION_SL) < sl)
                         {
                          if (!trade.PositionModify(PositionGetInteger(POSITION_TICKET), sl, PositionGetDouble(POSITION_TP)))
                            {
                             Print("Failed to modify position. Error code: ", GetLastError());
                            }
                         }
                       else if (PositionGetInteger(POSITION_TYPE) == ORDER_TYPE_SELL && PositionGetDouble(POSITION_SL) > sl)
                         {
                          if (!trade.PositionModify(PositionGetInteger(POSITION_TICKET), sl, PositionGetDouble(POSITION_TP)))
                            {
                             Print("Failed to modify position. Error code: ", GetLastError());
                            }
                         }
                      }

              文章完整代码如下:

              //+------------------------------------------------------------------+
              //|                     Deus  EA                                      |
              //|     Copyright 2024, MetaQuotes Ltd.                              |
              //|                    https://www.mql5.com                          |
              //+------------------------------------------------------------------+
              #include <Trade\Trade.mqh>
              CTrade trade;
              
              //--- Input parameters
              input double Lots = 0.1;                 // Lot size
              input double StopLoss = 50;              // Stop loss in points
              input double TakeProfit = 50;            // Take profit in points
              input double TrailingStop = 25;          // Trailing stop in points
              
              //--- RSI parameters
              input int RSI_Period = 7;                // RSI period
              input double RSI_Overbought = 35.0;      // RSI overbought level
              input double RSI_Oversold = 15.0;        // RSI oversold level
              
              //--- Moving Average parameters
              input int MA_Period = 25;                // Moving Average period
              input ENUM_MA_METHOD MA_Method = MODE_SMA;  // Moving Average method
              input ENUM_APPLIED_PRICE MA_Price = PRICE_CLOSE; // Applied price for MA
              
              //--- Variables
              double rsiValue;  // RSI value
              double maValue;   // Moving Average value
              double Ask;
              double Bid;
              double Close[2];  // Initializing Close array with two elements
              
              //--- Function prototypes
              void ApplyTrailingStop();
              void OpenPosition(CTrade &trade, int orderType); // Pass CTrade by reference
              void ClosePositions(int orderType);           // pass orderType directly
               
              //+------------------------------------------------------------------+
              //| Expert initialization function                                   |
              //+------------------------------------------------------------------+
              int OnInit()
                {
                 Print("Deus  EA initialized successfully.");
                 return(INIT_SUCCEEDED);
                }
               
              //+------------------------------------------------------------------+
              //| Expert deinitialization function                                 |
              //+------------------------------------------------------------------+
              void OnDeinit(const int reason)
                {
                 Print("Deus  EA deinitialized. Reason: ", reason);
                }
              
              //+------------------------------------------------------------------+
              //| Expert tick function                                             |
              //+------------------------------------------------------------------+
              void OnTick()
                {
                //--- Update current prices
                  Ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
                  Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
                  ArrayResize(Close, 2);
                   Close[0] = iClose(_Symbol, Period(), 0);
                  Close[1] = iClose(_Symbol, Period(), 1);
                 
                  
                 //--- Calculate RSI value
                 rsiValue = iRSI(_Symbol, _Period, RSI_Period, PRICE_CLOSE, 0);
                 if (rsiValue == WRONG_VALUE)
                   {
                    Print("Error calculating RSI");
                    return;
                   
                 //--- Calculate Moving Average value
                 maValue = iMA(_Symbol, _Period, MA_Period, 0, MA_Method, MA_Price, 0);
                 if (maValue == WRONG_VALUE)
                   {
                    Print("Error calculating Moving Average");
                    return;
                   }
              
                 //--- Check for Buy Signal
                 if(rsiValue < RSI_Oversold && Close[1] > maValue)
                   {
                    if(PositionsTotal() == 0)
                      {
                       ClosePositions(ORDER_TYPE_SELL);
                       OpenPosition(ORDER_TYPE_BUY);
                      }
                   }
                 
                 //--- Check for Sell Signal
                 if(rsiValue > RSI_Overbought && Close[1] < maValue)
                   {
                    if(PositionsTotal() == 0)
                      {
                       ClosePositions(ORDER_TYPE_BUY);
                       OpenPosition(ORDER_TYPE_SELL);
                      }
                    }
                 
                 //--- Apply trailing stop if specified
                 if(TrailingStop > 0)
                   {
                    ApplyTrailingStop();
                   }
                 }
                 
              //+------------------------------------------------------------------+
              //| Function to open a position                                      |
              //+------------------------------------------------------------------+
              void OpenPosition(int orderType)
                {
                 //--- Determine price stop loss, and take profit levels 
                 double price = (orderType == ORDER_TYPE_BUY) ? Ask : Bid;
                 double sl = (orderType == ORDER_TYPE_BUY) ? price - StopLoss * _Point : price + StopLoss * _Point;
                 double tp = (orderType == ORDER_TYPE_BUY) ? price + TakeProfit * _Point : price - TakeProfit * _Point;
                 
                 
                 bool result = trade.PositionOpen(_Symbol, orderType, Lots, price, sl, tp, "Deus  EA");
                 
                 if(result)
                   {
                    Print("Order opened successfully. Type: ", orderType, ", Price: ", price);
                   }
                 else
                   {
                    Print("Failed to open order. Error code: ", GetLastError());
                   }
                }
              
              //+------------------------------------------------------------------+
              //| Function to close positions                                      |
              //+------------------------------------------------------------------+
              void ClosePositions(int orderType)
                {
                 for(int i = PositionsTotal() - 1; i >= 0; i--)
                   {
                    if(PositionSelectByIndex(i))
                      {
                      //--- Check if the positions type matches the order type to be closed
                       if(PositionGetInteger(POSITION_TYPE) == orderType)
                         {
                         ulong ticket = PositionGetInteger(POSITION_TICKET);
                          if(!trade.PositionClose(ticket)
                            {
                             Print("Failed to close position. Error code: ", GetLastError());
                            }
                          }
                        }
                     }
                   }
              
              
              //+------------------------------------------------------------------+
              //| Function to apply trailing stop                                  |
              //+------------------------------------------------------------------+
              void ApplyTrailingStop()
                {
                 for (int i = PositionsTotal() - 1; i >= 0; i--)
                   {
                    if (PositionSelectByIndex(i) && PositionGetSymbol() == _Symbol)
                      {
                       double price = (PositionGetInteger(POSITION_TYPE) == ORDER_TYPE_BUY) ? Bid : Ask;
                       double sl = (PositionGetInteger(POSITION_TYPE) == ORDER_TYPE_BUY) ? price - TrailingStop * _Point : price + TrailingStop * _Point;
                       
                       //--- Trailing  stop logic for buy positions 
                       if (PositionGetInteger(POSITION_TYPE) == ORDER_TYPE_BUY && PositionGetDouble(POSITION_SL) < sl)
                         {
                          if (!trade.PositionModify(PositionGetInteger(POSITION_TICKET), sl, PositionGetDouble(POSITION_TP)))
                            {
                             Print("Failed to modify position. Error code: ", GetLastError());
                            }
                         }
                      
                       //--- Trailing stop logic for sell positions
                       else if (PositionGetInteger(POSITION_TYPE) == ORDER_TYPE_SELL && PositionGetDouble(POSITION_SL) > sl)
                         {
                          if (!trade.PositionModify(PositionGetInteger(POSITION_TICKET), sl, PositionGetDouble(POSITION_TP)))
                            {
                             Print("Failed to modify position. Error code: ", GetLastError());
                            }
                         }
                      }
                    }
                     

              恭喜我们吧!到目前为止,我们已经实现了 Deus EA 来实现交易自动化。

              以下是我们的测试结果;



              获得的结果:


              测试的是 USDJYP,回测是在 1H 图上从 2024.07.10 到 2024.08.06。模式是每一分时。使用的参数是我们用来研究实现的参数。  

              这种策略最适合 EUR/USD 和 USD/JPY,但只适合那些不需要高胜率的人。以下是我们用于测试 EA 的参数:


              结论

              Deus EA 使用移动平均线和相对强弱指数 (RSI) 来生成交易信号,展示了一种集成技术指标来管理和利用市场机会的先进交易策略。本指南详细介绍了交易逻辑、风险控制和支撑 EA 的 MQL5 代码,该代码自动化了交易决策,以提高一致性并减少情绪偏差。

              从图中我们可以看出,优化的小参数不仅降低了风险,而且增加了损失。因此,在实时交易中部署 EA 之前,对不同交易品种进行彻底的测试和优化至关重要。这将有助于确保它在不同的市场条件下表现良好,并与特定的交易目标保持一致。

              定期监测和调整对于保持 Deus EA 和类似自动化系统的有效性是必要的。本文提供了有效实现和优化 Deus EA 交易所需的基本见解和工具。您将能够从 MQL5 访问所需的任何额外支持。


              本文由MetaQuotes Ltd译自英文
              原文地址: https://www.mql5.com/en/articles/15431

              附加的文件 |
              Deus_EA.mq5 (9.28 KB)
              交易中的神经网络:基于双注意力的趋势预测模型 交易中的神经网络:基于双注意力的趋势预测模型
              我们继续讨论时间序列的分段线性表示的运用,这在前一篇文章中已经开始。今天,我们要看看如何将该方法与其它时间序列分析方法相结合,从而提高价格趋势预测品质。
              交易中的混沌理论(第二部分):深入探索 交易中的混沌理论(第二部分):深入探索
              我们继续深入探讨金融市场的混沌理论,这一次我将考虑其对货币和其他资产分析的适用性。
              创建 MQL5-Telegram 集成 EA 交易 (第一部分):从 MQL5 发送消息到 Telegram 创建 MQL5-Telegram 集成 EA 交易 (第一部分):从 MQL5 发送消息到 Telegram
              在本文中,我们在 MQL5 中创建一个 EA 交易,以使用机器人向 Telegram 发送消息。我们设置必要的参数,包括机器人的 API 令牌和聊天 ID,然后通过执行 HTTP POST 请求来传递消息。之后,我们将处理响应以确保成功传达,并排除故障时出现的任何问题。这确保我们能够通过创建的机器人将消息从 MQL5 发送到 Telegram。
              将 MQL5 与数据处理包集成(第 1 部分):高级数据分析和统计处理 将 MQL5 与数据处理包集成(第 1 部分):高级数据分析和统计处理
              集成实现了无缝的工作流程,来自 MQL5 的原始金融数据可以导入到 Jupyter Lab 等数据处理包中,用于包括统计测试在内的高级分析。