设为首页 收藏本站 切换语言
| 发表于 7 天前 | 显示全部楼层 |复制链接
© 本贴为 henrylin9999 首发,严禁抄袭!
#property description "布林带均值回归策略 - Bollinger Bands Mean Reversion Strategy"

参数设置

参数设置
image.png

//--- 包含标准交易库
#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("
举报

评论 使用道具

精彩评论2

xzy881230
DD
| 发表于 4 天前 | 显示全部楼层
举报

点赞 评论 使用道具

Y67748537
D
| 发表于 4 天前 | 显示全部楼层
这个好,总算不用让我买了
举报

点赞 评论 使用道具

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

简体中文
繁體中文
English(英语)
日本語(日语)
Deutsch(德语)
Русский язык(俄语)
بالعربية(阿拉伯语)
Türkçe(土耳其语)
Português(葡萄牙语)
ภาษาไทย(泰国语)
한어(朝鲜语/韩语)
Français(法语)