#property description "布林带均值回归策略 - Bollinger Bands Mean Reversion Strategy"
//---仅供学习,实盘请用多个策略进行判断,例如,MACD KDJ RSI 布林带,动量策略等进行判断,单一策略实盘胜率不高,还有很多策略,有兴趣的可以一起交流,你们提需求,我根据实际情况来开发。
//--- 包含标准交易库
#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("
复制代码
|