English Русский Español Deutsch 日本語 Português
preview
使用MQL5实现布林带交易策略:逐步指南

使用MQL5实现布林带交易策略:逐步指南

MetaTrader 5交易 | 24 二月 2025, 09:07
611 0
Kikkih25
Kikkih25

引言

在金融交易的动态世界中,技术指标的使用可以产生重大影响。布林带是这样一种有效的技术手段,交易者可以利用它根据价格波动和趋势强度来确定可能的入场和离场点。本文探讨了如何使用MQL5编程语言在MetaTrader 5中实现基于布林带交易策略的自动化交易决策。

通过遵循这个逐步教程,交易者可以构建一个使用布林带来执行买卖订单的专家顾问(Expert Advisor,EA),基于特定的市场条件。本教程将涵盖重要的主题,包括配置布林带指标、控制交易头寸,以及处理订单执行和错误管理。无论您是开发经验丰富的专业人士,还是对算法交易不太熟悉的新手,本教程都将为交易者提供一个坚实的基础,以设计和改进他们的交易方法。

本教程将涵盖以下主题:

  1. 布林带策略的定义
  2. 布林带策略描述
  3. 使用MQL5的逐步实现
  4. 结论


布林带策略的定义

布林带策略是一种技术分析方法,通过围绕移动平均线绘制一组带状线来确定效用和可能的交易机会。该策略由三条带组成:下带(中间带减去标准差的倍数)、上带(中间带加上标准差的倍数)和中间带(简单移动平均线)。根据价格与带状线的交互方式,交易者可以利用这种设置来识别超买或超卖情况,确定可能的买入或卖出信号,并预测价格的突破或反转。


布林带策略描述 

布林带策略是一种流行的用于评估市场波动和发现可能交易机会的技术分析工具。这一策略由约翰·布林格(John Bollinger)提出,由以下三个主要部分组成:

  1. 中间带(SMA):这是资产收盘价在给定期间的简单移动平均线(SMA)。它代表了在指定期间的平均价格,并作为带状线的核心参考点。
  2. 上带:该带通过将标准差乘以简单移动平均线计算得出,并显示在中间带上方。它表示价格范围的上限,并表明市场处于超买或更高波动性的状态。它由以下公式提供:[{Upper Band} = {Middle Band} + {Standard Deviation} {Band Deviation&}]
  3. 下带(Lower Band):该带通过从简单移动平均线(SMA)中减去标准差的倍数来计算,并显示在中间带的下方。当波动性降低或出现超卖情况时,它表示价格范围的下限。公式为:[{下带} = {中间带} - {标准差}] 

策略的关键要点:

价格走势与带的交互:当价格接近或触及下带时,通常被视为超卖;当价格接近或触及上带时,通常被视为超买。这种交互可以帮助交易者识别可能的买入或卖出信号。

  • 带的收缩(Band Squeeze):布林带收缩并相互靠近时会发生“带的收缩”,这是布林带的一个重要概念。这表明市场处于低波动性状态,并可能预示着即将出现大幅价格波动或突破。交易者会在这些收缩期间寻找可能的交易机会。



  • 趋势确认:结合其他指标时,布林带可用于趋势确认。例如,如果价格在成交量放大的情况下突破上带,则可能确认强劲的上升趋势;如果价格跌破下带,则可能确认下降趋势。                                       

策略的应用:

通过利用布林带周围的价位,交易者可以利用布林带策略做出明智的决策。一种常见的策略是在价格触及或跌破下带时买入(假设会出现反弹),在价格触及或突破上带时卖出(假设会出现回调)。该策略还可以帮助识别波动性的突然变化和可能的趋势反转。


使用MQL5的逐步实现 

我们首先设置交易操作。在MQL5中实现布林带策略时,需要处理订单的放置和管理。MQL5语言内置的交易库简化了这些操作。让我们讨论如何初始化交易库以及它如何支持主要的交易逻辑。

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

为了使用交易库提供的功能,我们需要创建一个CTrade类的实例。

CTrade trade; // Create an instance of the CTrade class  

通过引入交易库并初始化CTrade对象,我们可以使用其方法进行交易操作,例如开仓、平仓和修改订单。CTrade对象提供了多种执行交易的方式。我们在布林带专家顾问(EA)中使用它,根据onTick函数中指定的交易条件来发起买入和卖出订单。交易对象用于开启买入和卖出订单。当价格跌破下布林带时,EA会开启一个买入订单。

通过这种配置,我们可以有效地监督交易活动,并专注于创建强大的交易逻辑。交易者可以通过学习如何使用CTrade的订单放置方法,改进他们的EA对市场条件的反应和执行交易的方式。

我们现在通过自定义交易策略来配置输入参数。MQL5中的input和const声明允许交易者修改和设置他们交易策略的不同方面。根据市场状况和交易偏好,这些输入参数可以进行调整。让我们讨论这些参数的重要性,以及它们如何影响布林带交易方法。

变量输入可以在MetaTrader终端中进行更改,无需修改代码。使用input关键字来声明它们。布林带EA使用以下输入参数:

 // Input parameters for the Bollinger Bands strategy
 input int BandPeriod = 30;
 input double BandDeviation = 2.0;
 input double LotSize = 0.2;
 input int Slippage = 3;
 const double StopLoss = 70;
 const double TakeProfit = 140;

BandPeriod(布林带周期)是布林带计算中使用的周期数。较低的周期会增加布林带对价格波动的敏感性,而较大的周期会使布林带更加平滑,并可能减少交易信号。根据市场的波动性或交易计划的需求进行调整。

BandDeviation(布林带标准差),上下带通过计算与移动平均线的标准差偏差来确定。较大的标准差会使布林带更宽且更难触及,从而可能减少交易信号。较小的标准差会使布林带更窄,信号频率更高。通过调整此值来控制布林带对价格变化的响应。

LotSize(交易手数)是交易资产的交易量。设置每次交易的交易量。较大的手数可以增加潜在收益,但也需要根据账户规模和风险承受能力进行调整。

Slippage(滑点),执行订单时允许的最大滑点点数。帮助确保订单在接近预期价格的水平上成交,考虑订单放置时的小幅价格波动。根据市场状况和资产的流动性进行调整。

Constants(常量)是在编译时设置的不可变值,运行时无法更改。使用const关键字来定义它们:

const double StopLoss = 70;           
const double TakeProfit = 140;   

Stop Loss(止损)止损与开仓价格之间的点数差。如果市场向不利方向移动指定的点数,可以通过关闭交易来限制可能的损失。根据市场波动性和风险管理规则确定此数值。

Take Profit(止盈)止盈与开仓价格之间的点数差。当市场转向时,通过退出交易来锁定收益。自定义一些点数。根据期望的利润水平和市场状况进行调整。

通过配置输入参数和常量,交易者可以将布林带交易策略调整为适合自己的交易风格和市场状况。通过修改参数,可以微调EA的性能,使其符合交易目标。理解这些因素及其对策略的影响至关重要,以最大化交易表现并有效管理风险。

接着,我们来看下一个整型变量。在脚本中,此句柄用于引用和操作指标。

int Bb_Handle; // Handle for the Bollinger Bands indicator

此句柄是处理MQL5中布林带指标的重要部分它通过简化指标数据和资源的管理,确保交易策略能够平稳高效地运行。

现在我们进入本教程中基于布林带的专家顾问(EA)的OnInit函数部分。当EA被重新初始化或附加到图表时,OnInit函数会被调用一次。这个函数会创建任何必要的指标句柄,并设置初始参数。

在OnInit函数之前,EA定义了多个使用的输入参数。这些参数包括布林带的周期、标准差、手数、滑点和止损等。

OnInit函数的主要职责是通过iBands函数创建布林带指标的句柄。通过使用iBands函数完成这项工作。

int OnInit()
  {
   Bb_Handle = iBands(_Symbol, _Period, BandPeriod, BandDeviation, 0, PRICE_CLOSE);

这里我们尝试创建具有指定参数的布林带指标,并将句柄分配给Bb_Handle。

验证句柄创建是否成功至关重要。如果句柄无效,说明指标创建失败。为妥善处理此问题,EA应返回INIT_FAILED并打印错误信息。

if(Bb_Handle == INVALID_HANDLE)
     {
      Print("Error creating Bollinger Bands indicator");
      return(INIT_FAILED);
     }

如果指标句柄有效,OnInit函数应该返回INIT_SUCCEEDED以表示初始化过程已成功完成。

return(INIT_SUCCEEDED);
  }

将所有步骤整合在一起后的OnInit函数如下:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   // Create the Bollinger Bands indicator handle
   Bb_Handle = iBands(_Symbol, _Period, BandPeriod, BandDeviation, 0, PRICE_CLOSE); 
    { 
    if(Bb_Handle == INVALID_HANDLE)
     {
      Print("Error creating Bollinger Bands indicator"); 
      return(INIT_FAILED);
     }
   return(INIT_SUCCEEDED);
  }

OnInit函数对于配置构成EA(专家顾问)的元素至关重要。该算法通过为布林带指标建立句柄并管理任何风险,确保其准备好执行其交易逻辑。

接下来,我们来看OnDeinit函数,这个函数对于算法交易逻辑至关重要。确保您的专家顾问清理资源可能会避免问题并保持交易稳定。当EA从图表中删除或平台关闭时,会触发OnDeinit函数。它的职责是释放EA操作期间分配的任何资源,如指标句柄。这保证了平台的性能不会因内存泄漏或持续进程而受到影响。

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   // Release the Bollinger Bands indicator hande
   IndicatorRelease(Bb_Handle);
  }

释放布林带指标的句柄是我们EA中OnDeinit函数的主要职责。使用IndicatorRelease函数来完成这一操作。

接下来,我们来看OnTick函数,这是我们EA的核心。每当当前交易品种的价格更新接收到新的报价时,该函数就会被触发。控制EA对市场条件反应的基本交易逻辑包含在此函数中。

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
    double upperBand[], lowerBand[], middleBand[];
   
    // Copy the Bollinger Bands values into arrays
    if(CopyBuffer(Bb_Handle, 0, 0, 1, upperBand) <= 0||
      (CopyBuffer(Bb_Handle, 1, 0, 1, middleBand) <= 0||
      (CopyBuffer(Bb_Handle, 2, 0, 1, lowerBand) <= 0||
   {
     Print("Error copying band values");
     return;
    
     double upper = upperBand[0];
     double lower = lowerBand[0];
     double middle = middleBand[0];
     double price = Close[0];
     double Ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
     double Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
     
     // Buy signal: price is below the lower band and no open positions 
    if(price < lower && ! IsPositionOpen(_symbol))
      {
       double sl, tp;
       CalculateSLTP(sl, tp, price, true);
      if(trade.Buy(LotSize, _symbol, Ask, sl, tp, "Buy Order"))
        Print("Buy order opened at price: ", price);
      else
      { 
       Print("Error opening BUY order:", trade.ResultRetcode());
     }
      // Sell signal: price is above the upper band no open positions
      else if(price > upper && ! IsPositionOpen(_symbol))
       {
        double sl, tp;
        CalculateSLTP(sl, tp, price, false);
       if(trade.Sell(LotSize, _Symbol, Bid, sl, tp, "Sell Order"));
         Print("Sell order opened at price:", Price);
      else
         print("Error opening SELL order:", trade.ResultRetcode())
    }
  }

以下是OnTick函数的详细分解,便于理解:

定义并获取布林带值:获取布林带当前值是首要任务。为此目的,我们使用CopyBuffer函数,将指标值复制到数组中。

double upperBand[], lowerBand[], middleBand[];
   
    // Copy the Bollinger Bands values into arrays
    if(CopyBuffer(Bb_Handle, 0, 0, 1, upperBand) <= 0||
      (CopyBuffer(Bb_Handle, 1, 0, 1, middleBand) <= 0||
      (CopyBuffer(Bb_Handle, 2, 0, 1, lowerBand) <= 0||
   {
     Print("Error copying band values");
     return;

将带值分配给变量:然后将数组中的值分配给变量,以便更简单地引用。

     double upper = upperBand[0];
     double lower = lowerBand[0];
     double middle = middleBand[0];
     double price = Close[0];

获取当前的买入价和卖出价:在这里我们需要当前的买入价和卖出价来进行交易。

     double Ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
     double Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);

基于布林带的交易逻辑:买入条件是交易逻辑的基础。

  • 买入条件:如果没有开放头寸且价格低于下带,则下买入订单。 
   // Buy signal: price is below the lower band and no open positions 
    if(price < lower && ! IsPositionOpen(_symbol))
      {
       double sl, tp;
       CalculateSLTP(sl, tp, price, true);
      if(trade.Buy(LotSize, _symbol, Ask, sl, tp, "Buy Order"))
        Print("Buy order opened at price: ", price);
      else
      { 
       Print("Error opening BUY order:", trade.ResultRetcode());
     }
  • 卖出条件:如果没有开放头寸且价格高于上带,则下卖出订单。
 // Sell signal: price is above the upper band no open positions
      else if(price > upper && ! IsPositionOpen(_symbol))
       {
        double sl, tp;
        CalculateSLTP(sl, tp, price, false);
       if(trade.Sell(LotSize, _Symbol, Bid, sl, tp, "Sell Order"));
         Print("Sell order opened at price:", Price);
      else
         print("Error opening SELL order:", trade.ResultRetcode())
    }
  }

在我们的布林带交易策略中,真正的操作发生在OnTick函数中。通过仔细获取布林带值并基于此做出交易决策,我们可以开发一个可靠且自动化的交易策略。此函数的每个方面都有助于更高效的调试和改进,确保我们的EA在各种市场情况下都能以最佳效率运行。

除了主要的OnTick函数外,我们的专家顾问还依赖辅助函数来管理头寸、确定止盈和止损水平,并保证无缝交易操作。支持函数对于保持交易策略的弹性和有效性至关重要。我们将介绍在逐步布林带EA中使用的辅助函数。

第一个辅助函数是检查开放头寸。isPositionOpen函数确定所提供的交易品种此时是否有开放头寸。这是必要的,以确保EA不会同时为同一品种开设多个头寸。

//+------------------------------------------------------------------+
//| Check if there's an open position for a symbol                   |
//+------------------------------------------------------------------+
   
   bool IsPositionOpen(string symbol)
   }
    for(int i = 0;  i< PositionsTotal(); i++)
    }
     if(PositionSelectByIndex(i) && PositionGetString(POSITION_SYMBOL) == symbol)
       return true;
     {
      return false;
    }

一步步拆解开仓函数的条件:

  • 对所有头寸循环: 
for(int i = 0;  i< PositionsTotal(); i++)
    }

提供可用头寸的总数。使用索引遍历所有头寸。

  • 通过索引选择头寸:  
if(PositionSelectByIndex(i) && PositionGetString(POSITION_SYMBOL) == symbol)
       

这个函数选择了索引位置i。使用PositionGetString获取所选头寸的品种符号。

  • 检查符号,如果匹配则返回真值(true):
if(PositionSelectByIndex(i) && PositionGetString(POSITION_SYMBOL) == symbol)
       return true;
     

检查头寸的品种和输入品种符号是否一致。如果匹配则返回true。

  • 否则返回false。
return false;
    }

在遍历所有头寸后,如果没有找到一致的品种则返回false。

我们EA的第二个辅助函数是关闭某个品种的所有头寸。对于给定的品种,CloseAllPositions函数会关闭所有未平仓的头寸。这在风险管理或策略修改时可能会有所帮助。

//+------------------------------------------------------------------+
//|Close all positions for a symbol                                  |
//+------------------------------------------------------------------+
   void CloseAllPositions(string symbol)
  {
   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
    if(PositionSelectByIndex(i) && PositionGetString(POSITION_SYMBOL) == symbol)
     {
      ulong ticket = PositionGetInteger(POSITION_TICKET);
    if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
         trade.sell(LotSize, symbol, symbolInfoDouble(symbol, SYMBOL_BID), Slippage, 0, "Close Buy");
     {
     if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
          trade.Buy(LotSize, symbol, SymbolInfoDouble(symbol, SYMBOL_ASK), Slippage, 0, "Close Sell");
          // Wait for order to be processed before continuing
            Sleep(1000);
           }
          }
         }
        

逐步分解平仓某个品种的所有头寸函数的步骤:

  • 反向遍历所有头寸。
for(int i = 0;  i< PositionsTotal(); i++)    

在完成循环后返回起始点。确保关闭头寸不会改变索引顺序。

  • 通过索引选择头寸并检查其品种:

   if(PositionSelectByIndex(i) && PositionGetString(POSITION_SYMBOL) == symbol

选择头寸并确定输入的品种和当前头寸的品种是否匹配。

  • 获取头寸编号和类型:

      ulong ticket = PositionGetInteger(POSITION_TICKET);

检索头寸的编号。

  • 平仓:

if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
        trade.Sell(LotSize, symbol, SymbolInfoDouble(symbol, SYMBOL_BID), Slippage, 0, "Close Buy");
  else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
        trade.Buy(LotSize, symbol, SymbolInfoDouble(symbol, SYMBOL_ASK), Slippage, 0, "Close Sell");

通过卖出关闭买入头寸,并通过买入关闭卖出头寸。利用当前的买入价和卖出价进行操作。

  • 暂停以允许订单处理:
      // Wait for order to be processed before continuing
            Sleep(1000);
           }
          }
         }

在继续下一个环节之前暂停片刻,以确保订单已被处理。

接下来是我们的最后一个辅助函数,即计算止损和止盈水平。止损(SL)和止盈(TP)水平由CalculateSLTP函数根据当前价格和交易的买入/卖出状态确定。

//+------------------------------------------------------------------+
//| Calculate Stop Loss and Take Profit levels                       |
//+------------------------------------------------------------------+
   void CalculateSLTP(double &sl, double &tp, double price, bool isBuy)
   {
    if(isBuy)
     {
      sl = price - StopLoss *_Point;
      tp = price + TakeProfit *_Point;
     }
     else 
      {
       sl = price + StopLoss *_Point;
       tp = price - TakeProfit *_Point;
      }
     }

计算止损和止盈水平的函数的逐步分解:

  • 定义函数的参数:

void CalculateSLTP(double &sl, double &tp, double price, bool isBuy)
  • sl:止损水平。
  • tp:止盈水平。
  • price:价格。
  • sBuy:布尔值,指示交易是购买(true)还是出售(false)是购买。

确定在开启买入时的止损(SL)和止盈(TP):

if(isBuy)
  {
    sl = price - StopLoss * _Point;
    tp = price + TakeProfit * _Point;
  }

止损:从当前的止盈价格中减去设定的止损点数(以点为单位)。

止盈:在当前价格上加上设定的止盈点数(以点为单位)。为卖出交易计算止损和止盈。

else
  {
    sl = price + StopLoss * _Point;
    tp = price - TakeProfit * _Point;
  }
}

止损:将当前价格增加止损点数(以点为单位)。

止盈:从当前价格中减去指定的止盈点数(以点为单位)。

以下是辅助函数的完整代码:

//+------------------------------------------------------------------+
//| Check if there's an open position for a symbol                   |
//+------------------------------------------------------------------+
   
   bool IsPositionOpen(string symbol)
   }
    for(int i = 0;  i< PositionsTotal(); i++)
    }
     if(PositionSelectByIndex(i) && PositionGetString(POSITION_SYMBOL) == symbol)
       return true;
     {
      return false;
    }
//+------------------------------------------------------------------+
//|Close all positions for a symbol                                  |
//+------------------------------------------------------------------+
   void CloseAllPositions(string symbol)
  {
   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
    if(PositionSelectByIndex(i) && PositionGetString(POSITION_SYMBOL) == symbol)
     {
      ulong ticket = PositionGetInteger(POSITION_TICKET);
    if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
         trade.sell(LotSize, symbol, symbolInfoDouble(symbol, SYMBOL_BID), Slippage, 0, "Close Buy");
     {
     if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
          trade.Buy(LotSize, symbol, SymbolInfoDouble(symbol, SYMBOL_ASK), Slippage, 0, "Close Sell");
          // Wait for order to be processed before continuing
            Sleep(1000);
           }
          }
         }
        
//+------------------------------------------------------------------+
//| Calculate Stop Loss and Take Profit levels                       |
//+------------------------------------------------------------------+
   void CalculateSLTP(double &sl, double &tp, double price, bool isBuy)
   {
    if(isBuy)
     {
      sl = price - StopLoss *_Point;
      tp = price + TakeProfit *_Point;
     }
     else 
      {
       sl = price + StopLoss *_Point;
       tp = price - TakeProfit *_Point;
      }
     }

我们正在使用辅助函数管理和组织我们的EA的基本逻辑。这确保了EA运行顺畅,准确管理头寸,并计算我们的布林带交易策略中的风险管理水平。通过理解和应用这些辅助函数,您可以提高您的MQL5交易算法的可靠性和效率。

我们文章的完整代码如下:

//+------------------------------------------------------------------+
//|                                               BollingerBands.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

 #include<Trade\Trade.mqh> // Include the trade library
 CTrade trade; // Create an instance of the CTrade class  

 // Input parameters for the Bollinger Bands strategy
 input int BandPeriod = 30;
 input double BandDeviation = 2.0;
 input double LotSize = 0.2;
 input int Slippage = 3;
 const double StopLoss = 70;
 const double TakeProfit = 140;
 
 int Bb_Handle; // Handle for the Bollinger Bands indicator 

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   // Create the Bollinger Bands indicator handle
   Bb_Handle = iBands(_Symbol, _Period, BandPeriod, BandDeviation, 0, PRICE_CLOSE); 
    { 
    if(Bb_Handle == INVALID_HANDLE)
     {
      Print("Error creating Bollinger Bands indicator"); 
      return(INIT_FAILED);
     }
   return(INIT_SUCCEEDED);
  }
 
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   // Release the Bollinger Bands indicator hande
   IndicatorRelease(Bb_Handle);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
    double upperBand[], lowerBand[], middleBand[];
   
    // Copy the Bollinger Bands values into arrays
    if(CopyBuffer(Bb_Handle, 0, 0, 1, upperBand) <= 0||
      (CopyBuffer(Bb_Handle, 1, 0, 1, middleBand) <= 0||
      (CopyBuffer(Bb_Handle, 2, 0, 1, lowerBand) <= 0||
   {
     Print("Error copying band values");
     return;
    
     double upper = upperBand[0];
     double lower = lowerBand[0];
     double middle = middleBand[0];
     double price = Close[0];
     double Ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
     double Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
     
     // Buy signal: price is below the lower band and no open positions 
    if(price < lower && !IsPositionOpen(_symbol))
      {
       double sl, tp;
       CalculateSLTP(sl, tp, price, true);
      if(trade.Buy(LotSize, _symbol, Ask, sl, tp, "Buy Order"))
        Print("Buy order opened at price: ", price);
      else
      { 
       Print("Error opening BUY order:", trade.ResultRetcode());
     }
      // Sell signal: price is above the upper band no open positions
      else if(price > upper && !IsPositionOpen(_symbol))
       {
        double sl, tp;
        CalculateSLTP(sl, tp, price, false);
       if(trade.Sell(LotSize, _Symbol, Bid, sl, tp, "Sell Order"));
         Print("Sell order opened at price:", Price);
      else
         print("Error opening SELL order:", trade.ResultRetcode())
    }
  }

//+------------------------------------------------------------------+
//| Check if there's an open position for a symbol                   |
//+------------------------------------------------------------------+
   
   bool IsPositionOpen(string symbol)
   }
    for(int i = 0;  i< PositionsTotal(); i++)
    }
     if(PositionSelectByIndex(i) && PositionGetString(POSITION_SYMBOL) == symbol)
       return true;
     {
      return false;
    }
//+------------------------------------------------------------------+
//|Close all positions for a symbol                                  |
//+------------------------------------------------------------------+
   void CloseAllPositions(string symbol)
  {
   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
    if(PositionSelectByIndex(i) && PositionGetString(POSITION_SYMBOL) == symbol)
     {
      ulong ticket = PositionGetInteger(POSITION_TICKET);
    if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
         trade.sell(LotSize, symbol, symbolInfoDouble(symbol, SYMBOL_BID), Slippage, 0, "Close Buy");
     {
     if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
          trade.Buy(LotSize, symbol, SymbolInfoDouble(symbol, SYMBOL_ASK), Slippage, 0, "Close Sell");
          // Wait for order to be processed before continuing
            Sleep(1000);
           }
          }
         }
        
//+------------------------------------------------------------------+
//| Calculate Stop Loss and Take Profit levels                       |
//+------------------------------------------------------------------+
   void CalculateSLTP(double &sl, double &tp, double price, bool isBuy)
   {
    if(isBuy)
     {
      sl = price - StopLoss *_Point;
      tp = price + TakeProfit *_Point;
     }
     else 
      {
       sl = price + StopLoss *_Point;
       tp = price - TakeProfit *_Point;
      }
     }

恭喜我们!现在我们已经创建了一个基于布林带交易策略的智能资金交易概念系统,用以生成交易信号。


回测结果

在策略测试器中回测后的结果如下:

图形:

结果:


从2016年到2019年,该策略执行了1425笔交易,其中857笔交易获利,比亏损交易多出20.28%。          

所使用的参数是默认值,因此交易者可以调整它们以适应自己的交易系统。以下是所使用的参数:

这是我们用于测试的设置:


结论

在本文中,我们探讨了实现布林带交易策略自动化的基本步骤,这些步骤需要在MQL5中实施。我们介绍了该策略的基本定义和描述,并展示了如何在MQL5中实现它。交易者现在可以使用所展示的知识来开发更复杂的布林带策略,该策略可以被优化以最终产生更好的结果。

免责声明:本文中的代码纯粹用于教育目的,不应被视为专业的投资建议。因此,请谨慎实施这些知识,以创建和优化您的系统,使其适合您的交易风格。

我们希望您发现这些内容有用,并且是朝着创建更优化的布林带策略迈出的垫脚石。我们已经附上了必要的文件,以提供我们用来演示这些示例的例子。研究代码并将其应用于您的具体策略中,以获得最佳结果。

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

附加的文件 |
BollingerBands.mq5 (5.15 KB)
神经网络变得简单(第 93 部分):频域和时域中的自适应预测(终篇) 神经网络变得简单(第 93 部分):频域和时域中的自适应预测(终篇)
在本文中,我们继续实现 ATFNet 模型的方式,其在时间序列预测内可自适应地结合 2 个模块(频域和时域)的结果。
从新手到专家:MQL5交易的必备之旅 从新手到专家:MQL5交易的必备之旅
释放您的潜力!您会被无数机会包围。发现开启您的MQL5之旅或将其提升到更高水平的三大顶级秘诀。让我们深入探讨适合初学者和专业人士的技巧和窍门。
您应当知道的 MQL5 向导技术(第 22 部分):条件化生成式对抗网络(cGAN) 您应当知道的 MQL5 向导技术(第 22 部分):条件化生成式对抗网络(cGAN)
生成式对抗网络是一对神经网络,它们彼此相互训练,以便结果更精准。我们采用这些网络的条件化类型,作为我们正在寻找的可选项,应用于智能信号类之内预测金融时间序列。
将您自己的 LLM 集成到 EA 中(第 3 部分):使用 CPU 训练自己的 LLM 将您自己的 LLM 集成到 EA 中(第 3 部分):使用 CPU 训练自己的 LLM
在人工智能飞速发展的今天,大语言模型(LLM)是人工智能的重要组成部分,所以我们应该思考如何将强大的 LLM 融入到我们的算法交易中。对于大多数人来说,很难根据他们的需求微调这些强大的模型,在本地部署它们,然后将它们应用于算法交易。本系列文章将采取循序渐进的方法来实现这一目标。