布林带均值回归策略,上一个发的,代码只发了一半,重新发一下

| 发表于 2025-9-21 21:50:51 | 显示全部楼层 |复制链接
#property description "布林带均值回归策略 - Bollinger Bands Mean Reversion Strategy"
//---仅供学习,实盘请用多个策略进行判断,例如,MACD KDJ RSI 布林带,动量策略等进行判断,单一策略实盘胜率不高,还有很多策略,有兴趣的可以一起交流,你们提需求,我根据实际情况来开发。
//--- 包含标准交易库
#include <Trade\Trade.mqh>

  1. //--- 输入参数
  2. input group "=== 基础参数 ==="
  3. input double   InpLotSize = 0.01;          // 手数(适配股票)
  4. input int      InpStopLoss = 500;          // 止损点数(适配股票)
  5. input int      InpTakeProfit = 1000;       // 止盈点数(适配股票)
  6. input int      InpMagicNumber = 12345;     // 魔术数字
  7. input group "=== 风险管理 ==="
  8. input int      InpMaxSpread = 200;         // 最大允许点差(适配股票)
  9. input double   InpMaxRisk = 0.01;          // 最大风险比例(保守)
  10. input int      InpMaxPositions = 1;        // 最大持仓数量
  11. input group "=== 布林带参数 ==="
  12. input int      InpBandsPeriod = 20;        // 布林带周期
  13. input double   InpBandsDeviation = 2.0;    // 标准差倍数
  14. input int      InpBandsShift = 0;          // 指标偏移
  15. input ENUM_MA_METHOD InpBandsMethod = MODE_SMA; // 移动平均方法
  16. input ENUM_APPLIED_PRICE InpBandsPrice = PRICE_CLOSE; // 应用价格
  17. input group "=== 信号参数 ==="
  18. input double   InpEntryThreshold = 0.1;    // 进入信号阈值(0-1)
  19. input double   InpExitThreshold = 0.5;     // 退出信号阈值(0-1)
  20. input bool     InpReverseSignals = false;  // 反转信号
  21. //--- 全局变量
  22. double         g_point_value;              // 点值
  23. datetime       g_last_trade_time;          // 上次交易时间
  24. //--- 交易对象
  25. CTrade         g_trade;
  26. //--- 布林带策略特定变量
  27. int            g_bands_handle;             // 布林带句柄
  28. double         g_upper_buffer[];           // 上轨缓冲区
  29. double         g_middle_buffer[];          // 中轨缓冲区  
  30. double         g_lower_buffer[];           // 下轨缓冲区
  31. //+------------------------------------------------------------------+
  32. //| Expert initialization function                                   |
  33. //+------------------------------------------------------------------+
  34. int OnInit()
  35. {
  36.     // 基础初始化
  37.     if(!BaseInitialization())
  38.         return INIT_FAILED;
  39.     // 策略特定初始化
  40.     if(!StrategyInitialization())
  41.         return INIT_FAILED;
  42.     Print("策略初始化成功: ", _Symbol);
  43.     return INIT_SUCCEEDED;
  44. }
  45. //+------------------------------------------------------------------+
  46. //| Expert deinitialization function                                 |
  47. //+------------------------------------------------------------------+
  48. void OnDeinit(const int reason)
  49. {
  50.     // 策略特定清理
  51.     StrategyDeinitialization();
  52.     // 基础清理
  53.     BaseDeinitialization();
  54.     Print("策略已停止运行");
  55. }
  56. //+------------------------------------------------------------------+
  57. //| Expert tick function                                             |
  58. //+------------------------------------------------------------------+
  59. void OnTick()
  60. {
  61.     // 基础检查
  62.     if(!BaseChecks())
  63.         return;
  64.     // 策略信号检查
  65.     int signal = GetStrategySignal();
  66.     if(signal != 0)
  67.     {
  68.         // 检查是否可以开仓
  69.         if(CanOpenPosition(signal))
  70.         {
  71.             // 执行交易
  72.             if(signal > 0)
  73.                 OpenBuyPosition();
  74.             else
  75.                 OpenSellPosition();
  76.         }
  77.     }
  78.     // 管理现有持仓
  79.     ManagePositions();
  80. }
  81. //+------------------------------------------------------------------+
  82. //| 基础初始化                                                        |
  83. //+------------------------------------------------------------------+
  84. bool BaseInitialization()
  85. {
  86.     // 设置交易对象
  87.     g_trade.SetExpertMagicNumber(InpMagicNumber);
  88.     g_trade.SetMarginMode();
  89.     g_trade.SetTypeFillingBySymbol(_Symbol);
  90.     g_trade.SetDeviationInPoints(10);
  91.     // 获取点值
  92.     g_point_value = _Point;
  93.     if(_Digits == 5 || _Digits == 3)
  94.         g_point_value = _Point * 10;
  95.     // 初始化时间
  96.     g_last_trade_time = 0;
  97.     // 验证输入参数
  98.     if(InpLotSize <= 0)
  99.     {
  100.         Print("错误: 手数必须大于0");
  101.         return false;
  102.     }
  103.     if(InpMagicNumber <= 0)
  104.     {
  105.         Print("错误: 魔术数字必须大于0");
  106.         return false;
  107.     }
  108.     // 显示品种基本信息
  109.     Print("✅ 品种信息:");
  110.     Print("  品种: ", _Symbol);
  111.     Print("  最小手数: ", SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN));
  112.     Print("  最大手数: ", SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX));
  113.     Print("  手数步长: ", SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP));
  114.     return true;
  115. }
  116. //+------------------------------------------------------------------+
  117. //| 布林带策略初始化                                                    |
  118. //+------------------------------------------------------------------+
  119. bool StrategyInitialization()
  120. {
  121.     // 创建布林带指标句柄
  122.     g_bands_handle = iBands(_Symbol, PERIOD_CURRENT,
  123.                            InpBandsPeriod, InpBandsShift,
  124.                            InpBandsDeviation, InpBandsPrice);
  125.     if(g_bands_handle == INVALID_HANDLE)
  126.     {
  127.         Print("创建布林带指标失败");
  128.         return false;
  129.     }
  130.     // 设置缓冲区为时间序列
  131.     ArraySetAsSeries(g_upper_buffer, true);
  132.     ArraySetAsSeries(g_middle_buffer, true);
  133.     ArraySetAsSeries(g_lower_buffer, true);
  134.     // 验证参数
  135.     if(InpBandsPeriod < 2 || InpBandsPeriod > 200)
  136.     {
  137.         Print("错误: 布林带周期必须在2-200之间");
  138.         return false;
  139.     }
  140.     if(InpBandsDeviation <= 0 || InpBandsDeviation > 5)
  141.     {
  142.         Print("错误: 标准差倍数必须在0-5之间");
  143.         return false;
  144.     }
  145.     if(InpEntryThreshold < 0 || InpEntryThreshold > 1)
  146.     {
  147.         Print("错误: 进入信号阈值必须在0-1之间");
  148.         return false;
  149.     }
  150.     Print("布林带策略初始化成功");
  151.     Print("布林带周期: ", InpBandsPeriod);
  152.     Print("标准差倍数: ", InpBandsDeviation);
  153.     Print("进入阈值: ", InpEntryThreshold);
  154.     Print("退出阈值: ", InpExitThreshold);
  155.     return true;
  156. }
  157. //+------------------------------------------------------------------+
  158. //| 基础清理                                                          |
  159. //+------------------------------------------------------------------+
  160. void BaseDeinitialization()
  161. {
  162.     // 基础清理工作
  163. }
  164. //+------------------------------------------------------------------+
  165. //| 布林带策略清理                                                      |
  166. //+------------------------------------------------------------------+
  167. void StrategyDeinitialization()
  168. {
  169.     // 释放布林带指标句柄
  170.     if(g_bands_handle != INVALID_HANDLE)
  171.     {
  172.         IndicatorRelease(g_bands_handle);
  173.         Print("布林带指标句柄已释放");
  174.     }
  175. }
  176. //+------------------------------------------------------------------+
  177. //| 基础检查                                                          |
  178. //+------------------------------------------------------------------+
  179. bool BaseChecks()
  180. {
  181.     // 检查市场状态
  182.     if(!IsMarketOpen())
  183.         return false;
  184.     // 检查点差
  185.     if(!IsSpreadAcceptable())
  186.         return false;
  187.     return true;
  188. }
  189. //+------------------------------------------------------------------+
  190. //| 获取布林带均值回归信号                                                |
  191. //+------------------------------------------------------------------+
  192. int GetStrategySignal()
  193. {
  194.     // 复制布林带数据
  195.     if(CopyBuffer(g_bands_handle, 0, 0, 3, g_middle_buffer) < 3 ||
  196.        CopyBuffer(g_bands_handle, 1, 0, 3, g_upper_buffer) < 3 ||
  197.        CopyBuffer(g_bands_handle, 2, 0, 3, g_lower_buffer) < 3)
  198.     {
  199.         Print("复制布林带数据失败");
  200.         return 0;
  201.     }
  202.     // 获取当前价格
  203.     double current_price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
  204.     double ask_price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
  205.     // 获取布林带值
  206.     double upper_current = g_upper_buffer[0];
  207.     double middle_current = g_middle_buffer[0];  
  208.     double lower_current = g_lower_buffer[0];
  209.     // 计算价格在布林带中的相对位置 (0=下轨, 0.5=中轨, 1=上轨)
  210.     double band_width = upper_current - lower_current;
  211.     if(band_width <= 0)
  212.         return 0;
  213.     double price_position = (current_price - lower_current) / band_width;
  214.     // 均值回归信号逻辑
  215.     int signal = 0;
  216.     if(!InpReverseSignals)
  217.     {
  218.         // 正常均值回归: 价格偏离均值时反向操作
  219.         if(price_position <= InpEntryThreshold)
  220.         {
  221.             // 价格接近下轨,预期回归,买入信号
  222.             signal = 1;
  223.         }
  224.         else if(price_position >= (1.0 - InpEntryThreshold))
  225.         {
  226.             // 价格接近上轨,预期回归,卖出信号  
  227.             signal = -1;
  228.         }
  229.     }
  230.     else
  231.     {
  232.         // 反转信号: 用于突破策略
  233.         if(price_position >= (1.0 - InpEntryThreshold))
  234.         {
  235.             // 价格突破上轨,买入信号
  236.             signal = 1;
  237.         }
  238.         else if(price_position <= InpEntryThreshold)
  239.         {
  240.             // 价格突破下轨,卖出信号
  241.             signal = -1;
  242.         }
  243.     }
  244.     // 添加趋势过滤 - 检查中轨斜率
  245.     double middle_prev = g_middle_buffer[1];
  246.     double middle_prev2 = g_middle_buffer[2];
  247.     // 计算中轨趋势
  248.     bool uptrend = (middle_current > middle_prev) && (middle_prev > middle_prev2);
  249.     bool downtrend = (middle_current < middle_prev) && (middle_prev < middle_prev2);
  250.     // 趋势过滤: 在强趋势中减少反向信号
  251.     if(!InpReverseSignals)
  252.     {
  253.         if(signal == -1 && uptrend)
  254.             signal = 0;  // 上升趋势中不做空
  255.         if(signal == 1 && downtrend)
  256.             signal = 0;  // 下降趋势中不做多
  257.     }
  258.     // 调试输出
  259.     if(signal != 0)
  260.     {
  261.         Print("布林带信号: ", signal > 0 ? "BUY" : "SELL");
  262.         Print("价格位置: ", DoubleToString(price_position, 3));
  263.         Print("上轨: ", DoubleToString(upper_current, _Digits));
  264.         Print("中轨: ", DoubleToString(middle_current, _Digits));
  265.         Print("下轨: ", DoubleToString(lower_current, _Digits));
  266.         Print("当前价: ", DoubleToString(current_price, _Digits));
  267.     }
  268.     return signal;
  269. }
  270. //+------------------------------------------------------------------+
  271. //| 检查市场是否开放                                                    |
  272. //+------------------------------------------------------------------+
  273. bool IsMarketOpen()
  274. {
  275.     MqlTick tick;
  276.     if(!SymbolInfoTick(_Symbol, tick))
  277.         return false;
  278.     return tick.time > 0;
  279. }
  280. //+------------------------------------------------------------------+
  281. //| 检查点差是否可接受                                                  |
  282. //+------------------------------------------------------------------+
  283. bool IsSpreadAcceptable()
  284. {
  285.     long spread = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
  286.     if(spread > InpMaxSpread)
  287.     {
  288.         static datetime last_warning = 0;
  289.         if(TimeCurrent() - last_warning > 300) // 每5分钟警告一次
  290.         {
  291.             Print("点差过大: ", spread, " > ", InpMaxSpread);
  292.             last_warning = TimeCurrent();
  293.         }
  294.         return false;
  295.     }
  296.     return true;
  297. }
  298. //+------------------------------------------------------------------+
  299. //| 检查是否可以开仓                                                    |
  300. //+------------------------------------------------------------------+
  301. bool CanOpenPosition(int signal)
  302. {
  303.     // 检查最大持仓数量
  304.     if(CountPositions() >= InpMaxPositions)
  305.         return false;
  306.     // 检查时间间隔(避免频繁交易)
  307.     if(TimeCurrent() - g_last_trade_time < 60) // 1分钟间隔
  308.         return false;
  309.     // 检查账户余额
  310.     double free_margin = AccountInfoDouble(ACCOUNT_MARGIN_FREE);
  311.     double required_margin = 0;
  312.     if(!OrderCalcMargin(signal > 0 ? ORDER_TYPE_BUY : ORDER_TYPE_SELL,
  313.                        _Symbol, InpLotSize,
  314.                        SymbolInfoDouble(_Symbol, signal > 0 ? SYMBOL_ASK : SYMBOL_BID),
  315.                        required_margin))
  316.         return false;
  317.     if(required_margin > free_margin * 0.5) // 不使用超过50%的自由保证金
  318.         return false;
  319.     return true;
  320. }
  321. //+------------------------------------------------------------------+
  322. //| 开多头仓位                                                         |
  323. //+------------------------------------------------------------------+
  324. bool OpenBuyPosition()
  325. {
  326.     double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
  327.     double sl = InpStopLoss > 0 ? ask - InpStopLoss * g_point_value : 0;
  328.     double tp = InpTakeProfit > 0 ? ask + InpTakeProfit * g_point_value : 0;
  329.     // 规范化交易量
  330.     double volume = InpLotSize;
  331.     double min_vol = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
  332.     double max_vol = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
  333.     double vol_step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
  334.     // 确保音量符合要求
  335.     volume = MathMax(volume, min_vol);
  336.     volume = MathMin(volume, max_vol);
  337.     volume = MathRound(volume / vol_step) * vol_step;
  338.     // 调试输出
  339.     Print("
复制代码
123.png
111.png
举报

评论 使用道具

精彩评论1

jacke22gao
D
| 发表于 2025-11-13 23:33:18 | 显示全部楼层
不错!感谢分享
举报

点赞 评论 使用道具

发新帖
EA交易
您需要登录后才可以评论 登录 | 立即注册