© 本贴为 henrylin9999 首发,严禁抄袭!
#property description "布林带均值回归策略 - Bollinger Bands Mean Reversion Strategy"
参数设置
//--- 包含标准交易库
#include <Trade\Trade.mqh>
//--- 输入参数
input group "=== 基础参数 ==="
input double InpLotSize = 0.01; // 手数(适配股票)
input int InpStopLoss = 500; // 止损点数(适配股票)
input int InpTakeProfit = 1000; // 止盈点数(适配股票)
input int InpMagicNumber = 12345; // 魔术数字
input group "=== 风险管理 ==="
input int InpMaxSpread = 200; // 最大允许点差(适配股票)
input double InpMaxRisk = 0.01; // 最大风险比例(保守)
input int InpMaxPositions = 1; // 最大持仓数量
input group "=== 布林带参数 ==="
input int InpBandsPeriod = 20; // 布林带周期
input double InpBandsDeviation = 2.0; // 标准差倍数
input int InpBandsShift = 0; // 指标偏移
input ENUM_MA_METHOD InpBandsMethod = MODE_SMA; // 移动平均方法
input ENUM_APPLIED_PRICE InpBandsPrice = PRICE_CLOSE; // 应用价格
input group "=== 信号参数 ==="
input double InpEntryThreshold = 0.1; // 进入信号阈值(0-1)
input double InpExitThreshold = 0.5; // 退出信号阈值(0-1)
input bool InpReverseSignals = false; // 反转信号
//--- 全局变量
double g_point_value; // 点值
datetime g_last_trade_time; // 上次交易时间
//--- 交易对象
CTrade g_trade;
//--- 布林带策略特定变量
int g_bands_handle; // 布林带句柄
double g_upper_buffer[]; // 上轨缓冲区
double g_middle_buffer[]; // 中轨缓冲区
double g_lower_buffer[]; // 下轨缓冲区
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// 基础初始化
if(!BaseInitialization())
return INIT_FAILED;
// 策略特定初始化
if(!StrategyInitialization())
return INIT_FAILED;
Print("策略初始化成功: ", _Symbol);
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// 策略特定清理
StrategyDeinitialization();
// 基础清理
BaseDeinitialization();
Print("策略已停止运行");
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// 基础检查
if(!BaseChecks())
return;
// 策略信号检查
int signal = GetStrategySignal();
if(signal != 0)
{
// 检查是否可以开仓
if(CanOpenPosition(signal))
{
// 执行交易
if(signal > 0)
OpenBuyPosition();
else
OpenSellPosition();
}
}
// 管理现有持仓
ManagePositions();
}
//+------------------------------------------------------------------+
//| 基础初始化 |
//+------------------------------------------------------------------+
bool BaseInitialization()
{
// 设置交易对象
g_trade.SetExpertMagicNumber(InpMagicNumber);
g_trade.SetMarginMode();
g_trade.SetTypeFillingBySymbol(_Symbol);
g_trade.SetDeviationInPoints(10);
// 获取点值
g_point_value = _Point;
if(_Digits == 5 || _Digits == 3)
g_point_value = _Point * 10;
// 初始化时间
g_last_trade_time = 0;
// 验证输入参数
if(InpLotSize <= 0)
{
Print("错误: 手数必须大于0");
return false;
}
if(InpMagicNumber <= 0)
{
Print("错误: 魔术数字必须大于0");
return false;
}
// 显示品种基本信息
Print("✅ 品种信息:");
Print(" 品种: ", _Symbol);
Print(" 最小手数: ", SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN));
Print(" 最大手数: ", SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX));
Print(" 手数步长: ", SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP));
return true;
}
//+------------------------------------------------------------------+
//| 布林带策略初始化 |
//+------------------------------------------------------------------+
bool StrategyInitialization()
{
// 创建布林带指标句柄
g_bands_handle = iBands(_Symbol, PERIOD_CURRENT,
InpBandsPeriod, InpBandsShift,
InpBandsDeviation, InpBandsPrice);
if(g_bands_handle == INVALID_HANDLE)
{
Print("创建布林带指标失败");
return false;
}
// 设置缓冲区为时间序列
ArraySetAsSeries(g_upper_buffer, true);
ArraySetAsSeries(g_middle_buffer, true);
ArraySetAsSeries(g_lower_buffer, true);
// 验证参数
if(InpBandsPeriod < 2 || InpBandsPeriod > 200)
{
Print("错误: 布林带周期必须在2-200之间");
return false;
}
if(InpBandsDeviation <= 0 || InpBandsDeviation > 5)
{
Print("错误: 标准差倍数必须在0-5之间");
return false;
}
if(InpEntryThreshold < 0 || InpEntryThreshold > 1)
{
Print("错误: 进入信号阈值必须在0-1之间");
return false;
}
Print("布林带策略初始化成功");
Print("布林带周期: ", InpBandsPeriod);
Print("标准差倍数: ", InpBandsDeviation);
Print("进入阈值: ", InpEntryThreshold);
Print("退出阈值: ", InpExitThreshold);
return true;
}
//+------------------------------------------------------------------+
//| 基础清理 |
//+------------------------------------------------------------------+
void BaseDeinitialization()
{
// 基础清理工作
}
//+------------------------------------------------------------------+
//| 布林带策略清理 |
//+------------------------------------------------------------------+
void StrategyDeinitialization()
{
// 释放布林带指标句柄
if(g_bands_handle != INVALID_HANDLE)
{
IndicatorRelease(g_bands_handle);
Print("布林带指标句柄已释放");
}
}
//+------------------------------------------------------------------+
//| 基础检查 |
//+------------------------------------------------------------------+
bool BaseChecks()
{
// 检查市场状态
if(!IsMarketOpen())
return false;
// 检查点差
if(!IsSpreadAcceptable())
return false;
return true;
}
//+------------------------------------------------------------------+
//| 获取布林带均值回归信号 |
//+------------------------------------------------------------------+
int GetStrategySignal()
{
// 复制布林带数据
if(CopyBuffer(g_bands_handle, 0, 0, 3, g_middle_buffer) < 3 ||
CopyBuffer(g_bands_handle, 1, 0, 3, g_upper_buffer) < 3 ||
CopyBuffer(g_bands_handle, 2, 0, 3, g_lower_buffer) < 3)
{
Print("复制布林带数据失败");
return 0;
}
// 获取当前价格
double current_price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double ask_price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
// 获取布林带值
double upper_current = g_upper_buffer[0];
double middle_current = g_middle_buffer[0];
double lower_current = g_lower_buffer[0];
// 计算价格在布林带中的相对位置 (0=下轨, 0.5=中轨, 1=上轨)
double band_width = upper_current - lower_current;
if(band_width <= 0)
return 0;
double price_position = (current_price - lower_current) / band_width;
// 均值回归信号逻辑
int signal = 0;
if(!InpReverseSignals)
{
// 正常均值回归: 价格偏离均值时反向操作
if(price_position <= InpEntryThreshold)
{
// 价格接近下轨,预期回归,买入信号
signal = 1;
}
else if(price_position >= (1.0 - InpEntryThreshold))
{
// 价格接近上轨,预期回归,卖出信号
signal = -1;
}
}
else
{
// 反转信号: 用于突破策略
if(price_position >= (1.0 - InpEntryThreshold))
{
// 价格突破上轨,买入信号
signal = 1;
}
else if(price_position <= InpEntryThreshold)
{
// 价格突破下轨,卖出信号
signal = -1;
}
}
// 添加趋势过滤 - 检查中轨斜率
double middle_prev = g_middle_buffer[1];
double middle_prev2 = g_middle_buffer[2];
// 计算中轨趋势
bool uptrend = (middle_current > middle_prev) && (middle_prev > middle_prev2);
bool downtrend = (middle_current < middle_prev) && (middle_prev < middle_prev2);
// 趋势过滤: 在强趋势中减少反向信号
if(!InpReverseSignals)
{
if(signal == -1 && uptrend)
signal = 0; // 上升趋势中不做空
if(signal == 1 && downtrend)
signal = 0; // 下降趋势中不做多
}
// 调试输出
if(signal != 0)
{
Print("布林带信号: ", signal > 0 ? "BUY" : "SELL");
Print("价格位置: ", DoubleToString(price_position, 3));
Print("上轨: ", DoubleToString(upper_current, _Digits));
Print("中轨: ", DoubleToString(middle_current, _Digits));
Print("下轨: ", DoubleToString(lower_current, _Digits));
Print("当前价: ", DoubleToString(current_price, _Digits));
}
return signal;
}
//+------------------------------------------------------------------+
//| 检查市场是否开放 |
//+------------------------------------------------------------------+
bool IsMarketOpen()
{
MqlTick tick;
if(!SymbolInfoTick(_Symbol, tick))
return false;
return tick.time > 0;
}
//+------------------------------------------------------------------+
//| 检查点差是否可接受 |
//+------------------------------------------------------------------+
bool IsSpreadAcceptable()
{
long spread = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
if(spread > InpMaxSpread)
{
static datetime last_warning = 0;
if(TimeCurrent() - last_warning > 300) // 每5分钟警告一次
{
Print("点差过大: ", spread, " > ", InpMaxSpread);
last_warning = TimeCurrent();
}
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| 检查是否可以开仓 |
//+------------------------------------------------------------------+
bool CanOpenPosition(int signal)
{
// 检查最大持仓数量
if(CountPositions() >= InpMaxPositions)
return false;
// 检查时间间隔(避免频繁交易)
if(TimeCurrent() - g_last_trade_time < 60) // 1分钟间隔
return false;
// 检查账户余额
double free_margin = AccountInfoDouble(ACCOUNT_MARGIN_FREE);
double required_margin = 0;
if(!OrderCalcMargin(signal > 0 ? ORDER_TYPE_BUY : ORDER_TYPE_SELL,
_Symbol, InpLotSize,
SymbolInfoDouble(_Symbol, signal > 0 ? SYMBOL_ASK : SYMBOL_BID),
required_margin))
return false;
if(required_margin > free_margin * 0.5) // 不使用超过50%的自由保证金
return false;
return true;
}
//+------------------------------------------------------------------+
//| 开多头仓位 |
//+------------------------------------------------------------------+
bool OpenBuyPosition()
{
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double sl = InpStopLoss > 0 ? ask - InpStopLoss * g_point_value : 0;
double tp = InpTakeProfit > 0 ? ask + InpTakeProfit * g_point_value : 0;
// 规范化交易量
double volume = InpLotSize;
double min_vol = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double max_vol = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
double vol_step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
// 确保音量符合要求
volume = MathMax(volume, min_vol);
volume = MathMin(volume, max_vol);
volume = MathRound(volume / vol_step) * vol_step;
// 调试输出
Print(" |