|
多头入场
布林带收窄:当前带宽(上轨-下轨) < 过去20日平均带宽 × 0.8到1.1期间都开单
价格突破:收盘价 > 布林带上轨
波动放大:当前ATR值 > 前5根K线平均ATR × 1.2到1.5期间
空头入场
布林带收窄:当前带宽 < 过去20日平均带宽 × 0.8到1.1期间都开单
价格突破:收盘价 < 布林带下轨
波动放大:当前ATR值 > 前5根K线平均ATR × 1.2 1.2到1.5期间
三、出场规则
止损规则
多头止损:布林带中轨 - 2 × 当前ATR
空头止损:布林带中轨 + 2 × 当前ATR
止盈规则(二选一)
选项1:固定盈亏比1:2
止盈价 = 入场价 ± (止损距离 × 2)
(例:多头止损距离=入场价-止损价,止盈价=入场价+2×止损距离)
//+------------------------------------------------------------------+
//| BB_ATR_EA.mq5 |
//| Copyright 2023, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "1.00"
input double BandRatio1 = 0.8; // 布林带收窄下限系数
input double BandRatio2 = 1.1; // 布林带收窄上限系数
input int BandPeriod = 20; // 布林带周期
input double BandDeviation = 2.0; // 布林带标准差
input int ATRPeriod = 14; // ATR周期
input double ATRMultiMin = 1.2; // ATR最小倍数
input double ATRMultiMax = 1.5; // ATR最大倍数
input int ATRLookback = 5; // ATR比较周期
input double RiskPercent = 2.0; // 风险百分比
input double SLMultiplier = 2.0; // 止损ATR倍数
input double RRRatio = 2.0; // 盈亏比
int bandsHandle, atrHandle;
double upperBand[], middleBand[], lowerBand[], atrBuffer[], closePrice[];
datetime lastBarTime;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
bandsHandle = iBands(_Symbol, _Period, BandPeriod, 0, BandDeviation, PRICE_CLOSE);
atrHandle = iATR(_Symbol, _Period, ATRPeriod);
if(bandsHandle == INVALID_HANDLE || atrHandle == INVALID_HANDLE){
Print("指标初始化失败");
return(INIT_FAILED);
}
ArraySetAsSeries(upperBand, true);
ArraySetAsSeries(middleBand, true);
ArraySetAsSeries(lowerBand, true);
ArraySetAsSeries(atrBuffer, true);
ArraySetAsSeries(closePrice, true);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
IndicatorRelease(bandsHandle);
IndicatorRelease(atrHandle);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
if(!isNewBar()) return;
// 获取最新数据
CopyBuffer(bandsHandle, 1, 0, BandPeriod+2, upperBand);
CopyBuffer(bandsHandle, 0, 0, BandPeriod+2, middleBand);
CopyBuffer(bandsHandle, 2, 0, BandPeriod+2, lowerBand);
CopyBuffer(atrHandle, 0, 0, ATRLookback+2, atrBuffer);
CopyClose(_Symbol, _Period, 0, 2, closePrice);
// 计算布林带带宽参数
double currentBand = upperBand[0] - lowerBand[0];
double avgBand = 0;
for(int i=1; i<=BandPeriod; i++) avgBand += (upperBand - lowerBand);
avgBand /= BandPeriod;
// 计算ATR参数
double currentATR = atrBuffer[0];
double avgATR = 0;
for(int i=1; i<=ATRLookback; i++) avgATR += atrBuffer;
avgATR /= ATRLookback;
// 获取当前价格
double askPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double bidPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
// 检查多头条件
if(currentBand > avgBand*BandRatio1 &&
currentBand < avgBand*BandRatio2 &&
closePrice[1] > upperBand[1] &&
currentATR > avgATR*ATRMultiMin &&
currentATR < avgATR*ATRMultiMax)
{
double sl = middleBand[0] - SLMultiplier*currentATR;
double tp = askPrice + (askPrice - sl)*RRRatio;
OpenTrade(ORDER_TYPE_BUY, sl, tp);
}
// 检查空头条件
if(currentBand > avgBand*BandRatio1 &&
currentBand < avgBand*BandRatio2 &&
closePrice[1] < lowerBand[1] &&
currentATR > avgATR*ATRMultiMin &&
currentATR < avgATR*ATRMultiMax)
{
double sl = middleBand[0] + SLMultiplier*currentATR;
double tp = bidPrice - (sl - bidPrice)*RRRatio;
OpenTrade(ORDER_TYPE_SELL, sl, tp);
}
}
//+------------------------------------------------------------------+
//| 开仓函数 |
//+------------------------------------------------------------------+
bool OpenTrade(ENUM_ORDER_TYPE type, double sl, double tp)
{
if(PositionSelect(_Symbol)) return false;
MqlTradeRequest request = {};
MqlTradeResult result = {};
ZeroMemory(request);
ZeroMemory(result);
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = LotSize();
request.type = type;
request.price = (type == ORDER_TYPE_BUY) ? SymbolInfoDouble(_Symbol, SYMBOL_ASK)
: SymbolInfoDouble(_Symbol, SYMBOL_BID);
request.sl = sl;
request.tp = tp;
request.deviation = 5;
request.type_filling = ORDER_FILLING_FOK;
if(!OrderSend(request, result)){
Print("开仓失败 错误码:", GetLastError());
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| 计算手数大小 |
//+------------------------------------------------------------------+
double LotSize()
{
double balance = AccountInfoDouble(ACCOUNT_BALANCE);
double lot = (balance * RiskPercent/100) / 1000.0;
return NormalizeDouble(lot, 2);
}
//+------------------------------------------------------------------+
//| 判断新K线 |
//+------------------------------------------------------------------+
bool isNewBar()
{
datetime currentBarTime = iTime(_Symbol, _Period, 0);
if(currentBarTime != lastBarTime){
lastBarTime = currentBarTime;
return true;
}
return false;
}
//+------------------------------------------------------------------+
|
|