English Русский Deutsch 日本語
preview
价格行为分析工具包开发(第七部分):信号脉冲智能交易系统(EA)

价格行为分析工具包开发(第七部分):信号脉冲智能交易系统(EA)

MetaTrader 5示例 |
137 0
Christian Benjamin
Christian Benjamin

内容



概述

在本文中,我们将探讨如何使用MQL5开发一款“信号脉冲EA”。该EA将结合三个不同时间框架下的布林带和随机震荡器来识别买入和卖出信号。这款EA的目的是,通过在入场交易前确认来自多个时间框架的信号,帮助交易者做出明智的决策。我们纳入了多个时间框架、布林带(BB)和随机震荡器来进行信号生成。我们的目标是尽量减少虚假信号,这些信号往往会让交易者感到沮丧。通过结合这些要素,我们旨在提高交易信号的准确性。以下,我列出了信号生成工具中各组成部分的重要性。

  • 多时间框架
优势 描述
风险管理 采用多时间框架分析,可使EA从不同角度审视市场,从而降低虚假信号的影响,并提升风险管理水平。
信号可信度 通过在多个时间框架上确认信号,EA能增强对交易方向的信心,减少因信号微弱或虚假而入场交易的可能性。
多元化分析 分析多个时间框架能提供对市场更为多元化的视角,使得EA能够适应不断变化的市场环境,并做出更为明智的交易决策。
  • 随机震荡器
优势 描述
超买/超卖情况
随机震荡器有助于识别超买和超卖情况,表明市场中潜在的反转点。
确认工具
随机震荡器可作为布林带的确认工具,确保EA不会仅基于布林带信号就入场交易。
过滤虚假信号
通过使用随机震荡器,EA可以过滤掉布林带在高波动期间产生的虚假信号。

  • 布林带
优势 描述
波动性指标
布林带能够指示市场的波动水平,帮助EA了解市场情绪和潜在的交易机会。
支撑/阻力位
布林带充当动态的支撑和阻力位,为EA提供潜在的入场和出场点。
趋势确认 
布林带的宽度可以确认或否定趋势的存在,帮助EA做出明智的交易决策。

多个时间框架、随机震荡器和布林带(BB)之间的相互作用显著提高了EA生成可靠交易信号和管理风险的能力。通过分析不同时间框架的信号,EA确保交易机会得到随机震荡器和布林带指标的强烈信号汇聚的确认。这种多维方法降低了虚假信号的可能性,因为EA仅在有充分证据支持决策时才识别潜在交易。因此,这些要素的结合提高了生成信号的可靠性,并改善了整体风险管理,使交易者能够基于更高程度的信心和精确度做出更明智的决策。 


策略解析

信号脉冲脚本根据布林带和随机震荡器在三个时间框架(M15、M30和H1)上的一致性生成交易信号。每种信号的条件如下:

买入信号

  1. 布林带条件:在所有三个时间框架上,价格触及布林带的下轨。
  2. 随机震荡器条件:在所有三个时间框架上,随机震荡器显示超卖情况,通常低于20。
  3. 确认要求:必须同时在M15、M30和H1时间框架上满足上述两个条件,才能生成买入信号。

买入条件

图例1. 买入条件

卖出信号

  1. 布林带条件:在所有三个时间框架(M15、M30和H1)上,价格触及布林带的上轨。
  2. 随机振荡器条件:在所有三个时间框架上,随机震荡器显示超买情况,通常高于80。
  3. 确认要求:必须同时在M15、M30和H1时间框架上满足上述两个条件,才能生成卖出信号。

卖出条件

图例2. 卖出条件

让我们通过以下图表来可视化这一过程。  

信号生成图表

图例3. 信号生成过程


MQL5代码

//+------------------------------------------------------------------+
//|                                              Signal Pulse EA.mq5 |
//|                                  Copyright 2025, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

// Input parameters
input ENUM_TIMEFRAMES Timeframe1 = PERIOD_M15; // M15 timeframe
input ENUM_TIMEFRAMES Timeframe2 = PERIOD_M30; // M30 timeframe
input ENUM_TIMEFRAMES Timeframe3 = PERIOD_H1;  // H1 timeframe
input int BB_Period = 20;                      // Bollinger Bands period
input double BB_Deviation = 2.0;               // Bollinger Bands deviation
input int K_Period = 14;                       // Stochastic %K period
input int D_Period = 3;                        // Stochastic %D period
input int Slowing = 3;                         // Stochastic slowing
input double SignalOffset = 10.0;              // Offset in points for signal arrow
input int TestBars = 10;                       // Number of bars after signal to test win condition
input double MinArrowDistance = 5.0;          // Minimum distance in points between arrows to avoid overlapping

// Signal tracking structure
struct SignalInfo
  {
   datetime          time;
   double            price;
   bool              isBuySignal;
  };

// Arrays to store signal information
datetime signalTimes[];
double signalPrices[];
bool signalBuySignals[];

//+------------------------------------------------------------------+
//| Retrieve Bollinger Band Levels                                   |
//+------------------------------------------------------------------+
bool GetBollingerBands(ENUM_TIMEFRAMES timeframe, double &upper, double &lower, double &middle)
  {
   int handle = iBands(Symbol(), timeframe, BB_Period, 0, BB_Deviation, PRICE_CLOSE);

   if(handle == INVALID_HANDLE)
     {
      Print("Error creating iBands for timeframe: ", timeframe);
      return false;
     }

   double upperBand[], middleBand[], lowerBand[];

   if(!CopyBuffer(handle, 1, 0, 1, upperBand) ||
      !CopyBuffer(handle, 0, 0, 1, middleBand) ||
      !CopyBuffer(handle, 2, 0, 1, lowerBand))
     {
      Print("Error copying iBands buffer for timeframe: ", timeframe);
      IndicatorRelease(handle);
      return false;
     }

   upper = upperBand[0];
   middle = middleBand[0];
   lower = lowerBand[0];

   IndicatorRelease(handle);
   return true;
  }

//+------------------------------------------------------------------+
//| Retrieve Stochastic Levels                                       |
//+------------------------------------------------------------------+
bool GetStochastic(ENUM_TIMEFRAMES timeframe, double &k_value, double &d_value)
  {
   int handle = iStochastic(Symbol(), timeframe, K_Period, D_Period, Slowing, MODE_SMA, STO_CLOSECLOSE);

   if(handle == INVALID_HANDLE)
     {
      Print("Error creating iStochastic for timeframe: ", timeframe);
      return false;
     }

   double kBuffer[], dBuffer[];

   if(!CopyBuffer(handle, 0, 0, 1, kBuffer) ||  // %K line
      !CopyBuffer(handle, 1, 0, 1, dBuffer))   // %D line
     {
      Print("Error copying iStochastic buffer for timeframe: ", timeframe);
      IndicatorRelease(handle);
      return false;
     }

   k_value = kBuffer[0];
   d_value = dBuffer[0];

   IndicatorRelease(handle);
   return true;
  }

//+------------------------------------------------------------------+
//| Check and Generate Signal                                        |
//+------------------------------------------------------------------+
void CheckAndGenerateSignal()
  {
   double upper1, lower1, middle1, close1;
   double upper2, lower2, middle2, close2;
   double upper3, lower3, middle3, close3;
   double k1, d1, k2, d2, k3, d3;

   if(!GetBollingerBands(Timeframe1, upper1, lower1, middle1) ||
      !GetBollingerBands(Timeframe2, upper2, lower2, middle2) ||
      !GetBollingerBands(Timeframe3, upper3, lower3, middle3))
     {
      Print("Error retrieving Bollinger Bands data.");
      return;
     }

   if(!GetStochastic(Timeframe1, k1, d1) ||
      !GetStochastic(Timeframe2, k2, d2) ||
      !GetStochastic(Timeframe3, k3, d3))
     {
      Print("Error retrieving Stochastic data.");
      return;
     }

// Retrieve the close prices
   close1 = iClose(Symbol(), Timeframe1, 0);
   close2 = iClose(Symbol(), Timeframe2, 0);
   close3 = iClose(Symbol(), Timeframe3, 0);

   bool buySignal = (close1 <= lower1 && close2 <= lower2 && close3 <= lower3) &&
                    (k1 < 5 && k2 < 5 && k3 < 5); // Oversold condition
   bool sellSignal = (close1 >= upper1 && close2 >= upper2 && close3 >= upper3) &&
                     (k1 > 95 && k2 > 95 && k3 > 95); // Overbought condition

// Check if an arrow already exists in the same region before placing a new one
   if(buySignal && !ArrowExists(close1))
     {
      Print("Buy signal detected on all timeframes with Stochastic confirmation!");

      string arrowName = "BuySignal" + IntegerToString(TimeCurrent());
      ObjectCreate(0, arrowName, OBJ_ARROW, 0, TimeCurrent(), close1);
      ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, 241);
      ObjectSetInteger(0, arrowName, OBJPROP_COLOR, clrGreen);
      ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, 2);

      // Store signal data
      ArrayResize(signalTimes, ArraySize(signalTimes) + 1);
      ArrayResize(signalPrices, ArraySize(signalPrices) + 1);
      ArrayResize(signalBuySignals, ArraySize(signalBuySignals) + 1);

      signalTimes[ArraySize(signalTimes) - 1] = TimeCurrent();
      signalPrices[ArraySize(signalPrices) - 1] = close1;
      signalBuySignals[ArraySize(signalBuySignals) - 1] = true;
     }

   if(sellSignal && !ArrowExists(close1))
     {
      Print("Sell signal detected on all timeframes with Stochastic confirmation!");

      string arrowName = "SellSignal" + IntegerToString(TimeCurrent());
      ObjectCreate(0, arrowName, OBJ_ARROW, 0, TimeCurrent(), close1);
      ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, 242);
      ObjectSetInteger(0, arrowName, OBJPROP_COLOR, clrRed);
      ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, 2);

      // Store signal data
      ArrayResize(signalTimes, ArraySize(signalTimes) + 1);
      ArrayResize(signalPrices, ArraySize(signalPrices) + 1);
      ArrayResize(signalBuySignals, ArraySize(signalBuySignals) + 1);

      signalTimes[ArraySize(signalTimes) - 1] = TimeCurrent();
      signalPrices[ArraySize(signalPrices) - 1] = close1;
      signalBuySignals[ArraySize(signalBuySignals) - 1] = false;
     }
  }

//+------------------------------------------------------------------+
//| Check if an arrow already exists within the MinArrowDistance     |
//+------------------------------------------------------------------+
bool ArrowExists(double price)
  {
   for(int i = 0; i < ArraySize(signalPrices); i++)
     {
      if(MathAbs(signalPrices[i] - price) <= MinArrowDistance)
        {
         return true; // Arrow exists in the same price region
        }
     }
   return false; // No arrow exists in the same region
  }

//+------------------------------------------------------------------+
//| OnTick Event                                                     |
//+------------------------------------------------------------------+
void OnTick()
  {
   CheckAndGenerateSignal();
  }

//+------------------------------------------------------------------+
//| OnDeinit Function                                                |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
// Clean up the objects
   long chart_id = 0;
   for(int i = ObjectsTotal(chart_id) - 1; i >= 0; i--)
     {
      string name = ObjectName(chart_id, i);
      if(StringFind(name, "Signal") != -1)
        {
         ObjectDelete(chart_id, name);
        }
     }

   Print("Multitimeframe Bollinger-Stochastic Analyzer deinitialized.");
  }
//+------------------------------------------------------------------+



代码分解

我们将逐步深入剖析信号脉冲EA的各个组成部分、其运行机制以及功能背后的逻辑。
  • 头部信息、属性及输入参数

在EA的开头部分,我们添加了一个头部信息,用于提供重要的基础数据。这包括EA的名称、版权详情以及一个可以了解我们更多成果的链接。但对于作为交易者的您而言,真正有帮助的是输入参数。这些可自定义的设置使您能够根据自身的交易风格调整EA的行为。

//+------------------------------------------------------------------+
//|                                              Signal Pulse EA.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Christian Benjamin"
#property link      "https://www.mql5.com/en/users/lynnchris"
#property version   "1.00"

// Input parameters
input ENUM_TIMEFRAMES Timeframe1 = PERIOD_M15; // M15 timeframe
input ENUM_TIMEFRAMES Timeframe2 = PERIOD_M30; // M30 timeframe
input ENUM_TIMEFRAMES Timeframe3 = PERIOD_H1;  // H1 timeframe
input int BB_Period = 20;                      // Bollinger Bands period
input double BB_Deviation = 2.0;               // Bollinger Bands deviation
input int K_Period = 14;                       // Stochastic %K period
input int D_Period = 3;                        // Stochastic %D period
input int Slowing = 3;                         // Stochastic slowing
input double SignalOffset = 10.0;              // Offset in points for signal arrow
input int TestBars = 10;                       // Number of bars after signal to test win condition
input double MinArrowDistance = 5.0;          // Minimum distance in points between arrows to avoid overlapping
在此部分,我们指定了不同的时间框架(M15、M30 和 H1),以便您能够分析多个时间段内的价格走势。我们还定义了布林带的参数,例如其周期和偏差,同时也设置了随机震荡器的参数,包括其%K和%D周期。我们甚至包含了图表上标记买卖信号箭头的可视化设置,以及通过防止箭头重叠来减少视觉干扰的参数。
  •  信号追踪与结构

接下来,我们定义了SignalInfo结构体,它在整理交易信号方面发挥着至关重要的作用。该结构体收集有关信号发生时间、当时价格以及是买入还是卖出信号的信息。此外,我们还设置了数组来动态存储这些信息。 

// Signal tracking structure
struct SignalInfo {
   datetime time;
   double price;
   bool isBuySignal;
};

// Arrays to store signal information
datetime signalTimes[];
double signalPrices[];
bool signalBuySignals[];
通过signalTimes、signalPrices和signalBuySignals数组,我们能够清晰记录EA随时间生成的交易信号,从而更轻松地处理多个信号,避免混淆。
  •  指标获取函数

现在,让我们详细阐述用于获取指标值的函数——具体来说,就是布林带和随机震荡器指标。 

//+------------------------------------------------------------------+
//| Retrieve Bollinger Band Levels                                   |
//+------------------------------------------------------------------+
bool GetBollingerBands(ENUM_TIMEFRAMES timeframe, double &upper, double &lower, double &middle) {
   int handle = iBands(Symbol(), timeframe, BB_Period, 0, BB_Deviation, PRICE_CLOSE);

   if(handle == INVALID_HANDLE) {
      Print("Error creating iBands for timeframe: ", timeframe);
      return false;
   }

   double upperBand[], middleBand[], lowerBand[];

   if(!CopyBuffer(handle, 1, 0, 1, upperBand) ||
      !CopyBuffer(handle, 0, 0, 1, middleBand) ||
      !CopyBuffer(handle, 2, 0, 1, lowerBand)) {
      Print("Error copying iBands buffer for timeframe: ", timeframe);
      IndicatorRelease(handle);
      return false;
   }

   upper = upperBand[0];
   middle = middleBand[0];
   lower = lowerBand[0];

   IndicatorRelease(handle);
   return true;
}

//+------------------------------------------------------------------+
//| Retrieve Stochastic Levels                                       |
//+------------------------------------------------------------------+
bool GetStochastic(ENUM_TIMEFRAMES timeframe, double &k_value, double &d_value) {
   int handle = iStochastic(Symbol(), timeframe, K_Period, D_Period, Slowing, MODE_SMA, STO_CLOSECLOSE);

   if(handle == INVALID_HANDLE) {
      Print("Error creating iStochastic for timeframe: ", timeframe);
      return false;
   }

   double kBuffer[], dBuffer[];

   if(!CopyBuffer(handle, 0, 0, 1, kBuffer) ||  // %K line
      !CopyBuffer(handle, 1, 0, 1, dBuffer)) { // %D line
      Print("Error copying iStochastic buffer for timeframe: ", timeframe);
      IndicatorRelease(handle);
      return false;
   }

   k_value = kBuffer[0];
   d_value = dBuffer[0];

   IndicatorRelease(handle);
   return true;
}
第一个函数GetBollingerBands()用于获取指定时间框架下布林带的上轨、中轨和下轨水平。该函数会创建布林带指标的句柄,并检查句柄是否创建成功。如果一切正常,它会将布林带各轨的值复制到数组中,以便我们后续在交易逻辑中使用。类似地,GetStochastic()函数用于获取随机震荡器的%K和%D值。该函数采用相同的错误检查和数据复制流程,确保我们获取到的数据准确无误,从而为决策提供可靠依据。

  • 信号检查与生成

处理完指标后,我们现在转向CheckAndGenerateSignal()函数,该函数包含了我们EA的核心逻辑。此函数会调用我们先前定义的指标函数,从所有指定时间框架中收集布林带和随机震荡器指标的数据。此外,它还会获取这些时间框架的最新收盘价。

该函数会根据当前市场状况检查买入和卖出信号。当收盘价低于布林带下轨,且随机震荡指标值显示超卖状态(小于5)时,触发买入信号。相反,当价格超过布林带上轨,且随机震荡指标读数超过95,表明市场处于超买状态时,则产生卖出信号。

//+------------------------------------------------------------------+
//| Check and Generate Signal                                        |
//+------------------------------------------------------------------+
void CheckAndGenerateSignal() {
   double upper1, lower1, middle1, close1;
   double upper2, lower2, middle2, close2;
   double upper3, lower3, middle3, close3;
   double k1, d1, k2, d2, k3, d3;

   if(!GetBollingerBands(Timeframe1, upper1, lower1, middle1) ||
      !GetBollingerBands(Timeframe2, upper2, lower2, middle2) ||
      !GetBollingerBands(Timeframe3, upper3, lower3, middle3)) {
      Print("Error retrieving Bollinger Bands data.");
      return;
   }

   if(!GetStochastic(Timeframe1, k1, d1) ||
      !GetStochastic(Timeframe2, k2, d2) ||
      !GetStochastic(Timeframe3, k3, d3)) {
      Print("Error retrieving Stochastic data.");
      return;
   }

   // Retrieve the close prices
   close1 = iClose(Symbol(), Timeframe1, 0);
   close2 = iClose(Symbol(), Timeframe2, 0);
   close3 = iClose(Symbol(), Timeframe3, 0);

   bool buySignal = (close1 <= lower1 && close2 <= lower2 && close3 <= lower3) &&
                    (k1 < 5 && k2 < 5 && k3 < 5); // Oversold condition
   bool sellSignal = (close1 >= upper1 && close2 >= upper2 && close3 >= upper3) &&
                     (k1 > 95 && k2 > 95 && k3 > 95); // Overbought condition

   // Check if an arrow already exists in the same region before placing a new one
   if(buySignal && !ArrowExists(close1)) {
      Print("Buy signal detected on all timeframes with Stochastic confirmation!");
      string arrowName = "BuySignal" + IntegerToString(TimeCurrent());
      ObjectCreate(0, arrowName, OBJ_ARROW, 0, TimeCurrent(), close1);
      ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, 241);
      ObjectSetInteger(0, arrowName, OBJPROP_COLOR, clrGreen);
      ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, 2);

      // Store signal data
      ArrayResize(signalTimes, ArraySize(signalTimes) + 1);
      ArrayResize(signalPrices, ArraySize(signalPrices) + 1);
      ArrayResize(signalBuySignals, ArraySize(signalBuySignals) + 1);

      signalTimes[ArraySize(signalTimes) - 1] = TimeCurrent();
      signalPrices[ArraySize(signalPrices) - 1] = close1;
      signalBuySignals[ArraySize(signalBuySignals) - 1] = true;
   }

   if(sellSignal && !ArrowExists(close1)) {
      Print("Sell signal detected on all timeframes with Stochastic confirmation!");
      string arrowName = "SellSignal" + IntegerToString(TimeCurrent());
      ObjectCreate(0, arrowName, OBJ_ARROW, 0, TimeCurrent(), close1);
      ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, 242);
      ObjectSetInteger(0, arrowName, OBJPROP_COLOR, clrRed);
      ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, 2);

      // Store signal data
      ArrayResize(signalTimes, ArraySize(signalTimes) + 1);
      ArrayResize(signalPrices, ArraySize(signalPrices) + 1);
      ArrayResize(signalBuySignals, ArraySize(signalBuySignals) + 1);

      signalTimes[ArraySize(signalTimes) - 1] = TimeCurrent();
      signalPrices[ArraySize(signalPrices) - 1] = close1;
      signalBuySignals[ArraySize(signalBuySignals) - 1] = false;
   }
}

此外,在图表上放置信号箭头之前,该函数会调用ArrowExists()函数,确保没有现有箭头与新信号重叠。如果一切确认无误,就会创建相应的箭头,并将信号信息存储在我们之前定义的数组中。

  • 箭头存在性检查

为了保持图表整洁,ArrowExists()函数发挥着重要作用,它会检查当前信号价格附近是否已存在箭头。这可以防止多个箭头重叠,从而避免造成混淆。通过将新信号价格与存储在signalPrices数组中的价格进行比较,我们可以判断是否已有箭头距离足够近,从而无需再创建新箭头。

//+------------------------------------------------------------------+
//| Check if an arrow already exists within the MinArrowDistance     |
//+------------------------------------------------------------------+
bool ArrowExists(double price) {
   for(int i = 0; i < ArraySize(signalPrices); i++) {
      if(MathAbs(signalPrices[i] - price) <= MinArrowDistance) {
         return true; // Arrow exists in the same price region
      }
   }
   return false; // No arrow exists in the same region
}

  • OnTickOnDeinit函数

最后,我们来看一下OnTick()和OnDeinit()函数。每当市场有新的报价(tick)时,都会调用OnTick()函数,确保我们的EA能够保持响应并及时更新。调用CheckAndGenerateSignal()函数,根据最新数据重新评估潜在的交易信号。

相比之下,当EA被移除或交易终端关闭时,会调用 OnDeinit() 函数。该函数负责清理EA创建的任何图形对象,特别是标记买入和卖出信号的箭头,从而保持图表整洁无杂乱。

//+------------------------------------------------------------------+
//| OnTick Event                                                     |
//+------------------------------------------------------------------+
void OnTick() {
   CheckAndGenerateSignal();
}

//+------------------------------------------------------------------+
//| OnDeinit Function                                                |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
   // Clean up the objects
   long chart_id = 0;
   for(int i = ObjectsTotal(chart_id) - 1; i >= 0; i--) {
      string name = ObjectName(chart_id, i);
      if(StringFind(name, "Signal") != -1) {
         ObjectDelete(chart_id, name);
      }
   }

   Print("Multitimeframe Bollinger-Stochastic Analyzer deinitialized.");
}

此外,在信号脉冲EA中,我们调整了随机震荡器的阈值水平,以确保仅生成最可靠的信号。这些调整侧重于在采取行动前确认市场处于极端状态——即买入信号对应超卖状态,卖出信号对应超买状态。

  • 超卖状态:买入信号
bool buySignal = (close1 <= lower1 && close2 <= lower2 && close3 <= lower3) &&
                 (k1 < 5 && k2 < 5 && k3 < 5); // Oversold condition

对于买入信号,价格必须在所有三个时间框架(M15、M30、H1)上处于或低于布林带下轨,这表明存在强烈的下行压力。此外,随机震荡器的%K值必须在所有三个时间框架上均小于5。该数值表明市场处于极端超卖状态,极有可能向上反转。将阈值严格设定为<5,可确保EA仅考虑反转概率显著较高的信号。

  • 超买状态:卖出信号

bool sellSignal = (close1 >= upper1 && close2 >= upper2 && close3 >= upper3) &&
                  (k1 > 95 && k2 > 95 && k3 > 95); // Overbought condition

对于卖出信号,价格必须在所有三个时间框架上处于或高于布林带上轨,这表明存在强劲的上行势头,且可能即将反转。随机震荡器的%K值必须在所有时间框架上均超过95,这表明市场处于极端超买状态,很可能转为看跌。这一严格条件确保EA在价格温和波动或盘整期间避免产生虚假的卖出信号。


测试结果

  • 历史数据回测
回测是EA开发过程中的重要环节,它允许交易者基于历史价格数据分析其EA的表现。这一过程有助于识别EA的盈利能力、准确性和稳健性,使交易者能够完善其策略并优化性能。
1. 加载历史数据

开始回测时,必须为所选交易品种和时间框架加载高质量、逐笔级别的历史数据。这些数据将作为评估EA表现的基础。确保数据准确可靠至关重要,因为任何差异都可能导致对EA表现的错误结论。

2. 设置测试参数

加载数据后,接下来需要在MetaTrader的策略测试器中配置必要的参数。这包括:
  • 交易品种:选择要交易的货币对或资产。
  • 时间周期:使用与EA设置相同的时间框架(例如,M15、M30、H1)。
  • 点差:设置实际或固定点差以模拟交易成本,并确保结果能够反映真实交易环境。
  • 优化:测试输入参数(例如,布林带周期、随机震荡器阈值)以实现最优性能。
3. 评估结果
设置测试参数后,接下来需要分析输出指标:
  • 盈利能力:评估EA的净利润和盈利因子以确定其整体盈利能力。
  • 风险:评估最大回撤以衡量EA的风险承受能力。
  • 胜率与交易频率:分析盈利交易数量和交易频率以了解EA在不同市场条件下的表现。

让我们回顾下面提供的测试结果。

测试结果1

图例4. 测试结果1

结果2

图例5. 测试结果2

上述图表展示了该EA的性能测试情况。在动态图像(GIF)中,我们可以看到每个检测到的信号都被记录下来。您可以通过更改输入参数、时间框架和随机震荡水平进行进一步测试,直到获得满足您要求的结果。


结论

在本文中,我们开发了“信号脉冲(Signal Pulse)”智能交易系统(EA),该系统结合了布林带和随机震荡指标,在M15、M30和H1三个时间框架上生成交易信号。该系统仅在多个时间框架一致显示超买或超卖状态时才确定交易信号,从而提高了成功的概率。在各种市场条件下进行全面回测至关重要。未来的改进可能包括添加趋势方向过滤器、高级风险管理以及针对不同市场类型优化信号逻辑。我们鼓励交易者将“信号脉冲”与自己的策略和技术结合使用,从而实现综合性的交易方式。

日期 工具名  描述 版本  更新  备注
01/10/24 图表展示器 以重影效果覆盖前一日价格走势的脚本 1.0 初始版本 Lynnchris工具箱的第一个工具
18/11/24 分析评论 以表格形式提供前一日的信息,并预测市场的未来方向 1.0 初始版本 Lynnchris工具箱的第二个工具
27/11/24 分析大师 每两小时定期更新市场指标  1.01 第二个版本 Lynnchris工具箱的第三个工具
02/12/24 Analytics Forecaster  集成Telegram通知功能,每两小时定时更新市场指标 1.1 第三个版本 工具数4
09/12/24 波动率导航仪 该EA通过布林带、RSI和ATR三大指标综合分析市场状况 1.0 初始版本 工具数5
19/12/24 均值回归信号收割器  运用均值回归策略分析市场并提供交易信号  1.0  初始版本  工具数6 
9/01/2025  信号脉冲  多时间框架分析器 1.0  初始版本  工具数7 

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

附加的文件 |
从基础到中级:联合(二) 从基础到中级:联合(二)
今天我们有一篇非常有趣的文章。我们将研究联合并尝试解决之前讨论的问题。我们还将探讨在应用程序中使用联合时可能出现的一些不寻常的情况。此处提供的材料仅用于教学目的。在任何情况下,除了学习和掌握所提出的概念外,都不应出于任何目的使用此应用程序。
开发回放系统(第 74 部分):新 Chart Trade(一) 开发回放系统(第 74 部分):新 Chart Trade(一)
在本文中,我们将修改本系列关于 Chart Trade 中显示的最后一段代码。这些变化对于使代码适应当前的回放/模拟系统模型是必要的。此处提供的内容仅用于教育目的。在任何情况下,除了学习和掌握所提出的概念外,都不应出于任何目的使用此应用程序。
新手在交易中的10个基本错误 新手在交易中的10个基本错误
新手在交易中会犯的10个基本错误: 在市场刚开始时交易, 获利时不适当地仓促, 在损失的时候追加投资, 从最好的仓位开始平仓, 翻本心理, 最优越的仓位, 用永远买进的规则进行交易, 在第一天就平掉获利的仓位,当发出建一个相反的仓位警示时平仓, 犹豫。
交易中的神经网络:搭配区段注意力的参数效率变换器(终篇) 交易中的神经网络:搭配区段注意力的参数效率变换器(终篇)
在之前的工作中,我们讨论了 PSformer 框架的理论层面,其中包括经典变换器架构的两大创新:参数共享(PS)机制,以及时空区段注意力(SegAtt)。在本文中,我们继续实现所提议方式的 MQL5 版本。