English Русский Español Deutsch 日本語 Português
preview
构建K线图趋势约束模型(第九部分):多策略EA(第一部分)

构建K线图趋势约束模型(第九部分):多策略EA(第一部分)

MetaTrader 5交易系统 |
311 0
Clemence Benjamin
Clemence Benjamin

核心内容:



概述

从本系列文章的开始,我们就强调将EA与每日(D1)K线图所反映的主流市场情绪保持一致。每日K线图的形状一直是关键的指导特征。然而,我们需要缩短时间周期,查看更小的时间框架,以便在日线(D1)市场走势中确定入场点位。例如,在1分钟(M1)时间框架上,我们希望市场在相对强弱指数(RSI)上达到极端水平,以便向EA发出潜在的交易信号。在这个早期阶段,我们没有引入太多策略,从而保持内容对于初学者而言易于理解。

然而,有一个庞大的策略集合可供研究,并整合到我们趋势约束EA的算法中。今天,我们将审慎研究一些由交易领域的有影响力的人物开发的著名策略,我称他们为“市场之父”。这一阶段的探讨将提升我们的理解水平,同时仍然保持标题的原始主题。我们还将探讨在之前的开发中提到的策略的局限性,这些策略主要集中在RSI和约束逻辑上。此外,我们也将探讨如何将新策略整合到EA中。

在深入探讨七大顶级策略之前,让我们回顾并总结代码中的约束逻辑: 

 在MQL5中,看涨K线图的条件是:

void OnTick()
{
    // Determine current daily trend (bullish )
    double daily_open = iOpen(_Symbol, PERIOD_D1, 0);
    double daily_close = iClose(_Symbol, PERIOD_D1, 0);

    bool is_bullish = daily_close > daily_open;
}

在MQL5中,看跌K线图的条件是:

void OnTick()
{
    // Determine current daily trend (bearish)
    double daily_open = iOpen(_Symbol, PERIOD_D1, 0);
    double daily_close = iClose(_Symbol, PERIOD_D1, 0);

    
    bool is_bearish = daily_close < daily_open;
}

在上述代码中,较高时间框架上的市场情绪作为我们的约束因素。在这种情况下,我们选择了D1时间框架。

约束条件的实现:

现在我们已经确定了每日K线图的看跌和看涨情绪,我们可以使用if()函数以及入场条件逻辑。 

对于看涨的一天:

 if (is_bullish)
    {
        // Logic for bullish trend
        Print("The daily trend is bullish.");

   // You can add your trading logic here, for example:
        // if (OrderSelect(...)) { /* Place buy order */ }
    }

对于看跌的一天:

 if (is_bearish)
    {
        // Logic for bearish trend
        Print("The daily trend is bearish.");
        // You can add your trading logic here, for example:
        // if (OrderSelect(...)) { /* Place sell order */ }
    }

在本次讨论结束时,您可能会注意到:

1. 其他策略以及背后的创造者。

2. 将新策略整合到现有EA的模块中。

3. 实现一个魔法数字。

总而言之,上述三个关键点将为交易者提供对各种策略及其背后的动机的更好理解,以及如何使用MQL5将新策略整合到现有代码中。

在开始开发主要代码之前,让我们专注于在下一部分讨论这些策略,这些策略会基于我的研究。您会看到扩展EA策略的必要性,特别是因为市场在不断变化。这些复合策略对于适应任何市场情况至关重要。当一个策略失败时,总会有另一个可以采用。我已竭尽全力去揭示支撑每种策略背后的数学原理,因为这些数学函数是高效算法开发的基础要素。

在回顾最近的EA时,我遇到了一些警告错误,如果您跟随了我的步骤,那么可能也注意到了。请查看下面的图片:

警告错误

编译警告

该错误出现在第78行第28列,具体位置已在下方高亮显示:

警告

第78行,第28列的警告

这一警告信息简单明了,解决起来也最为容易。以下是附带修复的代码段:

long position_type = PositionGetInteger(POSITION_TYPE);

上述修复涉及将int替换为long

在此提供我们的最新趋势约束EA源代码,您也可以回顾上一篇文章获取源文件。在实现新功能之前,一定要像我们上面所做的那样练习调试代码。

//+------------------------------------------------------------------+
//|                                      Trend Constraint Expert.mq5 |
//|                                Copyright 2024, Clemence Benjamin |
//|             https://www.mql5.com/en/users/billionaire2024/seller |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, Clemence Benjamin"
#property link      "https://www.mql5.com/en/users/billionaire2024/seller"
#property version   "1.00"
#property strict

#include <Trade\Trade.mqh>  // Include the trade library

// Input parameters
input int    RSI_Period = 14;            // RSI period
input double RSI_Overbought = 70.0;      // RSI overbought level
input double RSI_Oversold = 30.0;        // RSI oversold level
input double Lots = 0.1;                 // Lot size
input double StopLoss = 100;             // Stop Loss in points
input double TakeProfit = 200;           // Take Profit in points
input double TrailingStop = 50;          // Trailing Stop in points

// Global variables
double rsi_value;
int rsi_handle;
CTrade trade;  // Declare an instance of the CTrade class

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   // Create an RSI indicator handle
   rsi_handle = iRSI(_Symbol, PERIOD_CURRENT, RSI_Period, PRICE_CLOSE);
   if (rsi_handle == INVALID_HANDLE)
     {
      Print("Failed to create RSI indicator handle");
      return(INIT_FAILED);
     }

   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   // Release the RSI indicator handle
   IndicatorRelease(rsi_handle);
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   // Determine current daily trend (bullish or bearish)
   double daily_open = iOpen(_Symbol, PERIOD_D1, 0);
   double daily_close = iClose(_Symbol, PERIOD_D1, 0);

   bool is_bullish = daily_close > daily_open;
   bool is_bearish = daily_close < daily_open;

   // Get the RSI value for the current bar
   double rsi_values[];
   if (CopyBuffer(rsi_handle, 0, 0, 1, rsi_values) <= 0)
     {
      Print("Failed to get RSI value");
      return;
     }
   rsi_value = rsi_values[0];

   // Close open positions if the trend changes
   for (int i = PositionsTotal() - 1; i >= 0; i--)
     {
      if (PositionSelect(PositionGetSymbol(i)))  // Corrected usage
        {
         long position_type = PositionGetInteger(POSITION_TYPE);
         ulong ticket = PositionGetInteger(POSITION_TICKET);  // Get the position ticket

         if ((position_type == POSITION_TYPE_BUY && is_bearish) ||
             (position_type == POSITION_TYPE_SELL && is_bullish))
           {
            trade.PositionClose(ticket);  // Use the ulong variable directly
           }
        }
     }

   // Check for buy condition (bullish trend + RSI oversold)
   if (is_bullish && rsi_value < RSI_Oversold)
     {
      // No open positions? Place a buy order
      if (PositionsTotal() == 0)
        {
         double price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
         double sl = price - StopLoss * _Point;
         double tp = price + TakeProfit * _Point;

         // Open a buy order
         trade.Buy(Lots, _Symbol, price, sl, tp, "TrendConstraintExpert Buy");
        }
     }

   // Check for sell condition (bearish trend + RSI overbought)
   if (is_bearish && rsi_value > RSI_Overbought)
     {
      // No open positions? Place a sell order
      if (PositionsTotal() == 0)
        {
         double price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
         double sl = price + StopLoss * _Point;
         double tp = price - TakeProfit * _Point;

         // Open a sell order
         trade.Sell(Lots, _Symbol, price, sl, tp, "TrendConstraintExpert Sell");
        }
     }

   // Apply trailing stop
   for (int i = PositionsTotal() - 1; i >= 0; i--)
     {
      if (PositionSelect(PositionGetSymbol(i)))  // Corrected usage
        {
         double price = PositionGetDouble(POSITION_PRICE_OPEN);
         double stopLoss = PositionGetDouble(POSITION_SL);
         double current_price;

         if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
           {
            current_price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
            if (current_price - price > TrailingStop * _Point)
              {
               if (stopLoss < current_price - TrailingStop * _Point)
                 {
                  trade.PositionModify(PositionGetInteger(POSITION_TICKET), current_price - TrailingStop * _Point, PositionGetDouble(POSITION_TP));
                 }
              }
           }
         else if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
           {
            current_price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
            if (price - current_price > TrailingStop * _Point)
              {
               if (stopLoss > current_price + TrailingStop * _Point || stopLoss == 0)
                 {
                  trade.PositionModify(PositionGetInteger(POSITION_TICKET), current_price + TrailingStop * _Point, PositionGetDouble(POSITION_TP));
                 }
              }
           }
        }
     }
  }
//+------------------------------------------------------------------+


七大精选知名策略探讨

外汇市场交易需要技巧和策略的结合。多年来,已经出现了各种方法,可以帮助交易者最大化成功的可能性。这里,我将简要探讨七种有效的外汇交易策略,每种策略都基于由有影响力经济学家和交易者开发的重要数学原理和理论。一旦将策略牢记在心,实施编码技能并为策略创建算法就变得更容易。

(一)趋势跟踪策略

趋势跟踪策略基于查尔斯·道(道琼斯指数创始人之一及其理论提出者)的原则,他在19世纪末(1896年)制定了道氏理论。道氏认为市场按照趋势运作,识别这些趋势可以提供大量的交易机会。趋势跟踪背后的数学原理通常使用移动平均线,交易者使用简单移动平均线(SMA)来平滑价格波动。

简单移动平均线(SMA)的实际公式是:

SMA

其中:

  • 是周期数(或数据点数)。
  • (P_i) 是第i个周期的价格(或价值)。

该公式计算了过去N个周期的平均价格。支持性研究,例如 理查德·丹尼斯(Richard Dennis)及其在1980年代的“乌龟实验”,表明趋势跟踪可以在强劲的趋势市场中产生可观的利润。

(二)区间交易

区间交易基于支撑位和阻力位的概念,这是技术分析中的关键要素。这些概念由J. 韦尔斯·怀尔德(J. Welles Wilder)在其著作《技术交易系统新概念》( "New Concepts in Technical Trading Systems" )(1978年)中进行了详细阐述。交易者将支撑位视为一个价格水平,在该水平上,买盘兴趣会阻止价格下跌,而阻力位则会阻碍价格上涨。计算枢轴点(一种常见的识别这些水平的方法)的数学基础如下:

枢轴点(PP)的实际公式是:

枢轴

其中:

  • High是前一交易周期的最高价。
  • Low是前一交易周期的最低价。
  • Close是前一交易周期的收盘价。

该公式计算了用于技术分析的中心枢轴点,以确定即将到来的交易周期的潜在支撑位和阻力位。例如,约翰·墨菲(John Murphy)在《金融市场技术分析》(1986年)中的研究强调,支撑位和阻力位通常作为心理指标,可以帮助交易者做出明智的决策。

(三)突破交易

突破交易利用了当价格突破既定的支撑位或阻力位时会发生重大价格变动的信念。理查德·唐奇安(Richard Donchian)在20世纪50年代引入了这种策略,他在唐奇安通道(Donchian Channels)方面的研究强调利用波动性来识别突破点。交易者使用指定周期内的最高价(HH)和最低价(LL)来计算唐奇安通道:

(Upper Band = HH)

(Lower Band = LL)

唐奇安通道

唐奇安通道

行为金融学的研究支持了这样一种观点,即交易者常常由于从众行为而追随突破行情,这进一步强化了突破方向上的动量。丹尼尔·卡尼曼(Daniel Kahneman)和阿莫斯·特沃斯基(Amos Tversky)等研究人员在1979年发表的论文《前景理论:风险下的决策分析》("Prospect Theory: An Analysis of Decision under Risk")中,强调了心理因素如何在突破行情期间影响交易行为。

(四)套息交易

套息交易利用两种货币之间的利率差异,其理论基础是利率平价理论(IRP)。这一原则根植于20世纪初形成的经济理论,尤其是保罗·萨缪尔森(Paul Samuelson)在其著作《经济分析基础》(1947年)中提出的理论。

计算套息交易预期收益的基本公式如下:

ER

其中:

  • (i_high)(i_low) 分别是高收益货币和低收益货币的利率。
  • (ΔS)表示预期汇率变动。 
 肯尼斯·罗格夫(Kenneth Rogoff)在其1998年的论文中强调了利率平价偏离如何创造盈利的交易机会。

(五)剥头皮交易(Scalping)

剥头皮交易是一种高频交易策略,它利用市场微观结构理论(MMT)捕捉微小的价格波动。这一理论经过包括劳伦斯·哈里斯(Lawrence Harris)在内的多位研究人员的不断发展,在哈里斯1998年的论文《做市与纳斯达克公司的财务业绩》("Market Making and the Financial Performance of Nasdaq Firms" )中有所阐述。剥头皮交易者在短时间内执行多笔交易,试图从微小的价格变化中获利。

对于剥头皮交易者而言,重要的指标包括买卖价差和订单流分析,这些通常通过以下指标来计算:

盈利

其中:

  • (卖出价格) 是资产被出售时的价格。

  • (买入价格)是资产最初被购买时的价格。

  • (交易成本) 是与买卖过程相关的任何费用或成本(例如,经纪费、税费)。

风险管理变得至关重要,因为少数几笔不利的交易就可能会导致重大的损失。

(六) 基本面分析

基本面分析涉及对影响货币估值的经济指标和地缘政治因素进行考察。本杰明·格雷厄姆(Benjamin Graham)大卫·多德(David Dodd)在1934年出版的《证券分析》("Security Analysis")一书中开创了这一方法,该方法强调评估货币内在价值的重要性。交易者利用各种指标,如国内生产总值(GDP)增长率和失业率等,来做出明智的决策。此外,还可以借鉴一些数学技巧,例如股票的市盈率(P/E)比率等;

P^E

其中:

  • (每股市场价格)是指公司每一股股票的当前价格。

  • 每股收益(EPS) 是指公司利润分配到每一股流通在外的普通股上的金额。

大量研究支持基本面分析的有效性,特别是在发布重要经济报告或央行公告期间,这些事件往往会导致市场出现大幅波动。


(七)使用技术指标

技术分析以查尔斯·道(Charles Dow)等人的理念为基础,它假定过去的价格走势能够为预测未来市场行为提供线索。人们运用各种技术指标,如相对强弱指数(RSI),来衡量市场动量。相对强弱指数(RSI)的计算公式为: 

RSI

其中:

  • (RS) 表示在特定时间段内的平均涨幅和平均跌幅。

RS

支持性研究,例如托马斯·布尔科夫斯基(Thomas Bulkowski)在2008年出版的《K线图百科全书》("Encyclopedia of Candlestick Charts")中的研究,表明某些特定的图表形态和指标能够提高交易的精确度,使交易者能够根据历史价格走势预测市场动向。这些策略中的每一种都以基础理论、数学原理和广泛的研究为支撑,这些理论、原理和研究为外汇市场的交易者决策提供了依据。理解这些策略的复杂性可以显著提升交易者应对外汇交易复杂性的能力,最终带来更明智且更有利可图的交易结果。经过深思熟虑后运用这些策略,交易者可以开发出一种稳健的交易方法,这种方法可以根据他们的个人偏好和风险承受能力进行定制。


魔法数字的引入

在MQL5中,魔法数字是一个关键的组织工具,类似于EA用来标记其交易的一种独特签名。可以将其想象为每个EA都有自己独特的标识符,它会将其印在所开设的每一笔交易上。这在同时运行多个策略的账户中特别有用,因为它有助于EA将其操作与其他策略的操作清晰地分隔开来。

通过将魔法数字定义为输入参数,您可以获得灵活性,从而无需深入源代码即可调整EA的设置。当EA扫描未平仓头寸时,它会使用这个数字来快速找出哪些交易是属于其本身的。

函数PositionGetInteger(POSITION_MAGIC)用于检索附加到每笔交易上的魔法数字,使EA能够决定其下一步行动:是修改、监控还是平仓。对于交易者或开发者来说,这意味着无需担心不同策略之间的意外干扰,并且调试也更加容易,因为每笔交易都可以追溯到其来源策略。因此,有效地引入和管理魔法数字可以确保您的交易策略在金融市场中保持精确且组织有序。

以下是一个展示如何引入魔法数字的代码段:

input int MagicNumber = 12345678; // Define a unique magic number for the EA

// Within the OnTick() or relevant function
for (int i = 0; i < PositionsTotal(); i++) {
    if (PositionGetSymbol(i) == _Symbol && PositionSelect(PositionGetSymbol(i))) {
        long currentMagicNumber = PositionGetInteger(POSITION_MAGIC);

        if (currentMagicNumber == MagicNumber) { // Check if the position belongs to this EA
            // Perform actions on this position, like closing or modifying
        }
    }
}

// When opening a new trade
double price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double sl = price - StopLoss * _Point;
double tp = price + TakeProfit * _Point;

if (trade.Buy(Lots, _Symbol, price, sl, tp, "TrendFollowing Buy")) {
    Print("Buy order placed with Magic Number: ", MagicNumber);
} else {
    Print("Error placing buy order: ", GetLastError());


趋势跟踪策略的实现

在上述选定的策略中,大部分策略由于当前缺乏必要的数据而无法在我们的程序中实现。例如,套息交易(Carry Trade)在当前仅凭此代码是无法实现的,因为它涉及利率差额,而基本面分析则需要外部经济数据源来提供详细的GDP、就业率等信息。我们将专注于最可行的策略,其余将在未来做进一步探索。

趋势跟踪是一种方法,它通过识别并顺应持续的市场趋势方向进行交易,利用移动平均线等技术来确认趋势方向。我们的EA代码已经使用了相对强弱指数(RSI)来衡量超买或超卖情况,但整合移动平均线可以进一步优化决策过程。这里,我们使用短期移动平均线(50周期)和长期移动平均线(200周期)来确定趋势的方向。如果短期平均线向上穿越长期平均线,是一个上升趋势的信号;相反,如果短期平均线向下穿越长期平均线,则是一个下降的趋势。整合这种方法有助于确认看涨或看跌趋势,结合RSI条件提高交易进场的准确性。

 以下是我们用于计算移动平均线的代码段,该代码将在整合到主程序之前使用。

//Calculate moving averages
double ma_short = iMA(_Symbol, PERIOD_CURRENT, 50, 0, MODE_EMA, PRICE_CLOSE, 0);
double ma_long = iMA(_Symbol, PERIOD_CURRENT, 200, 0, MODE_EMA, PRICE_CLOSE, 0);

//Determine the trend  direction
bool is_uptrend = ma_short > ma_long;
bool is_downtrend = ma_short < ma_long;

if (is_bullish && is_uptrend && rsi_value < RSI_Oversold)
{
   // Implement buy order logic here
}

if (is_bearish && is_downtrend && rsi_value > RSI_Overbought)
{
   // Implement sell order logic here
}

为了有效地将趋势跟踪策略整合到现有的EA中,我们首先从增强其模块内的初始化和处理逻辑开始。从OnInit()函数入手,我们使用iMA函数引入两个关键指数移动平均线(EMAs)的计算,通常一个是50周期的短期趋势EMA,另一个是200周期的长期趋势EMA。

当我们进入到OnTick()方法时,这些EMAs会在每个新的市场跳动(tick)时重新计算,使EA能够确定当前的市场趋势方向;短期EMA上升穿越长期EMA表明是一个上升趋势,而短期EMA下降穿越长期EMA则表明是一个下降趋势。

将这些趋势信号与现有的RSI分析相结合,我们构建了算法条件,使得在确认的上升趋势中,当RSI处于超卖状态时,算法会开设买入订单;而在下降趋势中,当RSI处于超买状态时,算法会开设卖出订单。

使用CTrade类来执行交易,我们审慎设置了止损、止盈和追踪止损的参数,以确保稳健的风险管理。此外,在同一个OnTick()循环中,还融入了一个系统,用于在识别出的趋势反转时顺利地平仓,从而使每一笔交易都与经过验证的市场方向保持一致。通过这些战略性的更新,巧妙地定制EA以便采用趋势跟踪策略,并将其与当前功能无缝集成,从而提高了整体交易效率。

以下是一个完全整合的程序示例:

//+------------------------------------------------------------------+
//|                                      Trend Constraint Expert.mq5 |
//|                                Copyright 2024, Clemence Benjamin |
//|             https://www.mql5.com/en/users/billionaire2024/seller |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, Clemence Benjamin"
#property link      "https://www.mql5.com/en/users/billionaire2024/seller"
#property version   "1.00"
#property strict

#include <Trade\Trade.mqh>  // Include the trade library

// Input parameters
input int    RSI_Period = 14;            // RSI period
input double RSI_Overbought = 70.0;      // RSI overbought level
input double RSI_Oversold = 30.0;        // RSI oversold level
input double Lots = 0.1;                 // Lot size
input double StopLoss = 100;             // Stop Loss in points
input double TakeProfit = 200;           // Take Profit in points
input double TrailingStop = 50;          // Trailing Stop in points
input int    MagicNumber = 12345678;     // Magic number for this EA

// Global variables
double rsi_value;
int rsi_handle;
CTrade trade;  // Declare an instance of the CTrade class

// Variables for moving averages
double ma_short;
double ma_long;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   // Create an RSI indicator handle
   rsi_handle = iRSI(_Symbol, PERIOD_CURRENT, RSI_Period, PRICE_CLOSE);
   if (rsi_handle == INVALID_HANDLE)
     {
      Print("Failed to create RSI indicator handle");
      return(INIT_FAILED);
     }

   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   // Release the RSI indicator handle
   IndicatorRelease(rsi_handle);
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   // Calculate moving averages
   ma_short = iMA(_Symbol, PERIOD_CURRENT, 50, 0, MODE_EMA, PRICE_CLOSE);
   ma_long  = iMA(_Symbol, PERIOD_CURRENT, 200, 0, MODE_EMA, PRICE_CLOSE);

   // Determine trend direction
   bool is_uptrend = ma_short > ma_long;
   bool is_downtrend = ma_short < ma_long;

   // Get the RSI value for the current bar
   double rsi_values[];
   if (CopyBuffer(rsi_handle, 0, 0, 1, rsi_values) <= 0)
     {
      Print("Failed to get RSI value");
      return;
     }
   rsi_value = rsi_values[0];

   // Close open positions if the trend changes
   for (int i = 0; i < PositionsTotal(); i++) // Correct loop initialization
     {
      if (PositionGetSymbol(i) == _Symbol && PositionSelect(PositionGetSymbol(i)))  // Select position by symbol
        {
         long position_type = PositionGetInteger(POSITION_TYPE);
         long currentMagicNumber = PositionGetInteger(POSITION_MAGIC);
         ulong ticket = PositionGetInteger(POSITION_TICKET);

         if (currentMagicNumber == MagicNumber) // Ensure only this EA's orders are checked
           {
            if ((position_type == POSITION_TYPE_BUY && is_downtrend) ||
                (position_type == POSITION_TYPE_SELL && is_uptrend))
              {
               trade.PositionClose(ticket);
              }
           }
        }
     }

   // Check for buy condition (uptrend + RSI oversold)
   if (is_uptrend && rsi_value < RSI_Oversold)
     {
      // No open positions? Place a buy order
      bool open_position = false;

      for (int i = 0; i < PositionsTotal(); i++) // Correct loop initialization
        {
         if (PositionGetSymbol(i) == _Symbol && PositionSelect(PositionGetSymbol(i)))
           {
            long currentMagicNumber = PositionGetInteger(POSITION_MAGIC);

            if (currentMagicNumber == MagicNumber)
              {
               open_position = true;
               break;
              }
           }
        }

      if (!open_position)
        {
         double price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
         double sl = price - StopLoss * _Point;
         double tp = price + TakeProfit * _Point;

         // Open a buy order
         if (trade.Buy(Lots, _Symbol, price, sl, tp, "TrendFollowing Buy"))
            Print("Buy order placed with Magic Number: ", MagicNumber);
         else
            Print("Error placing buy order: ", GetLastError());
        }
     }

   // Check for sell condition (downtrend + RSI overbought)
   if (is_downtrend && rsi_value > RSI_Overbought)
     {
      // No open positions? Place a sell order
      bool open_position = false;

      for (int i = 0; i < PositionsTotal(); i++) // Correct loop initialization
        {
         if (PositionGetSymbol(i) == _Symbol && PositionSelect(PositionGetSymbol(i)))
           {
            long currentMagicNumber = PositionGetInteger(POSITION_MAGIC);

            if (currentMagicNumber == MagicNumber)
              {
               open_position = true;
               break;
              }
           }
        }

      if (!open_position)
        {
         double price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
         double sl = price + StopLoss * _Point;
         double tp = price - TakeProfit * _Point;

         // Open a sell order
         if (trade.Sell(Lots, _Symbol, price, sl, tp, "TrendFollowing Sell"))
            Print("Sell order placed with Magic Number: ", MagicNumber);
         else
            Print("Error placing sell order: ", GetLastError());
        }
     }

   // Apply trailing stop
   for (int i = 0; i < PositionsTotal(); i++) // Correct loop initialization
     {
      if (PositionGetSymbol(i) == _Symbol && PositionSelect(PositionGetSymbol(i))) // Select position by symbol
        {
         long currentMagicNumber = PositionGetInteger(POSITION_MAGIC);

         if (currentMagicNumber == MagicNumber) // Apply trailing stop only to this EA's positions
           {
            double price = PositionGetDouble(POSITION_PRICE_OPEN);
            double stopLoss = PositionGetDouble(POSITION_SL);
            double current_price;

            if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
              {
               current_price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
               if (current_price - price > TrailingStop * _Point)
                 {
                  if (stopLoss < current_price - TrailingStop * _Point)
                    {
                     trade.PositionModify(PositionGetInteger(POSITION_TICKET), current_price - TrailingStop * _Point, PositionGetDouble(POSITION_TP));
                    }
                 }
              }
            else if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
              {
               current_price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
               if (price - current_price > TrailingStop * _Point)
                 {
                  if (stopLoss > current_price + TrailingStop * _Point || stopLoss == 0)
                    {
                     trade.PositionModify(PositionGetInteger(POSITION_TICKET), current_price + TrailingStop * _Point, PositionGetDouble(POSITION_TP));
                    }
                 }
              }
           }
        }
     }
  }
//+------------------------------------------------------------------+


测试结果

我在B00M 500指数上测试了该EA并观察了订单情况。然而,要防止同时放置多个订单,仍有许多工作要做。在一个10,000美元的模拟账户上,该系统的表现显示出积极的结果,但在真实账户以及资金规模较小的账户上,结果可能并不相同。重要的是要注意,该系统并不能保证盈利;它仅用于教学目的、实验和研究。

启动EA

在Boom 500指数上启动EA

测试器

2019年Boom 500指数测试结果


结论

总而言之,我们关于使用MQL5构建多策略EA的讨论,着重于理解现有顶级策略的起源,并将趋势跟踪策略与关键要素(如相对强弱指数,RSI)相结合。趋势跟踪组件利用移动平均线来确定市场趋势方向,使交易者能够将其头寸常常与更稳定且可能更有利可图的长期市场走势保持一致。通过运用这些移动平均线,我们的系统能够识别上升趋势和下降趋势,从而基于明确的市场方向做出明智的交易决策。

趋势跟踪方法的战略性融入,与用于识别超买和超卖市场条件的RSI相辅相成。这两者共同构成了一种全面的方法,既捕捉了趋势动量,又与本系列的核心概念——趋势约束(Trend Constraint)相契合。在我们开发过程中进行的另一项关键改进是整合了魔法数字(Magic Numbers)——这是一个最初缺失但在多策略环境中对精确交易管理至关重要的功能。魔法数字作为唯一标识符,有助于将不同策略分隔开来,使交易者能够独立跟踪和管理每一个策略。

在我们考虑的七种策略中,到目前为止我们只实现了一种,因此还有许多潜在的发展方向有待未来探索。请编译并测试所附加的源代码文件,以评估其性能,并为您自己的项目实现收集理念。祝您交易顺利!

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

附加的文件 |
如何使用 Controls 类创建交互式 MQL5 仪表盘/面板(第 2 部分):添加按钮响应。 如何使用 Controls 类创建交互式 MQL5 仪表盘/面板(第 2 部分):添加按钮响应。
在本文中,我们将聚焦于实现按钮的响应,把静态的 MQL5 面板转变为一个交互式工具。我们将探讨如何自动化 GUI 组件的功能,确保它们能够恰当地响应用户的点击操作。最终,我们将建立一个动态界面,提升交互性和交易体验。
您应当知道的 MQL5 向导技术(第 39 部分):相对强度指数 您应当知道的 MQL5 向导技术(第 39 部分):相对强度指数
RSI 是一款流行的动量震荡指标,衡量证券近期价格变化的速度和规模,从而评估证券价格中被高估和低估的情况。这些对速度和幅度的洞察是定义反转点的关键。我们将这个振荡器放入另一个自定义信号类中工作,并验证其信号的一些特征。不过,我们先从总结我们之前在布林带的内容开始。
ALGLIB库优化方法(第一部分) ALGLIB库优化方法(第一部分)
在本文中,我们将了解适用于MQL5的ALGLIB库的优化方法。本文包含了使用ALGLIB解决优化问题的简单且清晰的示例,旨在使读者能够尽可能轻松地掌握这些方法。我们将详细探讨BLEIC、L-BFGS和NS等算法的连接方式,并使用它们来解决一个简单的测试问题。
创建 MQL5-Telegram 集成 EA 交易(第 6 部分):添加响应式内联按钮 创建 MQL5-Telegram 集成 EA 交易(第 6 部分):添加响应式内联按钮
在本文中,我们将交互式内联按钮集成到 MQL5 EA 交易中,允许通过 Telegram 进行实时控制。每次按下按钮都会触发特定的操作,并将响应发送回用户。我们还模块化了函数,以便有效地处理 Telegram 消息和回调查询。