|
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#property description "Bollinger Bands Squeeze with MA Filter Strategy"
#include <Trade/Trade.mqh>
//--- 输入参数
input int BandsPeriod = 20; // 布林带周期
input double BandsDeviations = 2.0; // 标准差倍数
input double WidthMultiplier = 1.1; // 宽度乘数
input int LookbackPeriod = 20; // 回溯周期
input double LotSize = 0.1; // 交易手数
input ulong MagicNumber = 123456; // 魔术码
input int Slippage = 3; // 滑点
input int TakeProfitPoints = 6000; // 止盈点数
input int StopLossPoints = 5000; // 止损点数
input int MA1_Period = 5; // 均线1周期
input int MA2_Period = 10; // 均线2周期
input int MA3_Period = 15; // 均线3周期
input int MA4_Period = 20; // 均线4周期
input int MA5_Period = 60; // 均线5周期
//--- 全局变量
int handleBands;
int handleMA1, handleMA2, handleMA3, handleMA4, handleMA5;
CTrade trade;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// 初始化指标句柄
handleBands = iBands(_Symbol, _Period, BandsPeriod, 0, BandsDeviations, PRICE_CLOSE);
handleMA1 = iMA(_Symbol, _Period, MA1_Period, 0, MODE_SMA, PRICE_CLOSE);
handleMA2 = iMA(_Symbol, _Period, MA2_Period, 0, MODE_SMA, PRICE_CLOSE);
handleMA3 = iMA(_Symbol, _Period, MA3_Period, 0, MODE_SMA, PRICE_CLOSE);
handleMA4 = iMA(_Symbol, _Period, MA4_Period, 0, MODE_SMA, PRICE_CLOSE);
handleMA5 = iMA(_Symbol, _Period, MA5_Period, 0, MODE_SMA, PRICE_CLOSE);
// 检查指标是否创建成功
if(handleBands == INVALID_HANDLE ||
handleMA1 == INVALID_HANDLE ||
handleMA2 == INVALID_HANDLE ||
handleMA3 == INVALID_HANDLE ||
handleMA4 == INVALID_HANDLE ||
handleMA5 == INVALID_HANDLE)
{
Print("Failed to initialize indicators!");
return(INIT_FAILED);
}
trade.SetExpertMagicNumber(MagicNumber);
trade.SetDeviationInPoints(Slippage);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| 持仓检查函数 |
//+------------------------------------------------------------------+
bool HasPosition()
{
for(int i=PositionsTotal()-1; i>=0; i--)
if(PositionGetSymbol(i) == _Symbol && PositionGetInteger(POSITION_MAGIC) == MagicNumber)
return true;
return false;
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
static datetime prevBarTime = 0;
datetime currentTime = iTime(_Symbol, _Period, 0);
if(currentTime == prevBarTime) return;
prevBarTime = currentTime;
// 获取布林带数据
double upper[], middle[], lower[];
ArraySetAsSeries(upper, true);
ArraySetAsSeries(middle, true);
ArraySetAsSeries(lower, true);
if(CopyBuffer(handleBands, 1, 0, LookbackPeriod+1, upper) <= 0 ||
CopyBuffer(handleBands, 0, 0, LookbackPeriod+1, middle) <= 0 ||
CopyBuffer(handleBands, 2, 0, LookbackPeriod+1, lower) <= 0)
{
Print("Error copying Bollinger Bands data!");
return;
}
// 计算当前布林带宽度
double currentWidth = upper[0] - lower[0];
// 寻找过去N个宽度中的最小值
double minWidth = DBL_MAX;
for(int i=1; i<=LookbackPeriod; i++) {
double w = upper[i] - lower[i];
if(w < minWidth) minWidth = w;
}
// 获取均线数据(前一根K线的值)
double ma1[2], ma2[2], ma3[2], ma4[2], ma5[2];
if(CopyBuffer(handleMA1, 0, 0, 2, ma1) < 2 ||
CopyBuffer(handleMA2, 0, 0, 2, ma2) < 2 ||
CopyBuffer(handleMA3, 0, 0, 2, ma3) < 2 ||
CopyBuffer(handleMA4, 0, 0, 2, ma4) < 2 ||
CopyBuffer(handleMA5, 0, 0, 2, ma5) < 2)
{
Print("Failed to copy MA buffers!");
return;
}
// 判断均线排列条件
bool isLongMA = ma1[1] > ma2[1] && ma2[1] > ma3[1] && ma3[1] > ma4[1] && ma4[1] > ma5[1];
bool isShortMA = ma1[1] < ma2[1] && ma2[1] < ma3[1] && ma3[1] < ma4[1] && ma4[1] < ma5[1];
// 获取价格数据
double lastClose = iClose(_Symbol, _Period, 1);
// 交易信号检测
if(!HasPosition() && currentWidth < minWidth * WidthMultiplier)
{
// 多单入场条件
if(isLongMA && lastClose > upper[1])
{
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double sl = NormalizeDouble(ask - StopLossPoints * _Point, _Digits);
double tp = NormalizeDouble(ask + TakeProfitPoints * _Point, _Digits);
trade.Buy(LotSize, _Symbol, ask, sl, tp, "BB Buy Entry");
}
// 空单入场条件
else if(isShortMA && lastClose < lower[1])
{
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double sl = NormalizeDouble(bid + StopLossPoints * _Point, _Digits);
double tp = NormalizeDouble(bid - TakeProfitPoints * _Point, _Digits);
trade.Sell(LotSize, _Symbol, bid, sl, tp, "BB Sell Entry");
}
}
}
|
|