希望祠.同舟.量化.侦云取势势能研究中心

 找回密码
 立即注册

《周易.系辞》

君子藏器于身,待时而动!

《吕氏.春秋》

君子谋时而动,顺势而为!

《晏子·霸业因时而生》

识时务者为俊杰,通机变者为英豪!

《周易.系辞》

天之所助,吉无不利,天之所助者.顺天者也!

《史记.太史公自序》
天之势,浩浩汤汤,顺之者昌,逆之者亡!

《寒窑赋》

天不得时,日月无光.地 不得时,草木不长.

《周易.系辞》

刚柔者,立本者也!变通者,识时者也!

圣人云:

君子务本,本立而道生!

 《势胜学》

不知势,无以为人也.势易而未觉,必败焉!

《周易·系辞上传》:

富有之谓大业,日新之谓盛德!

《礼记.大学》:
格物致知,正心诚意,修身齐家!

《礼记.中庸》:

凡事预则立,不预则废!

查看: 6395|回复: 0

【量化源码策略】布林带突破 + SAR趋势确认策略

[复制链接]

757

主题

812

帖子

2869

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2869

最佳新人活跃会员热心会员推广达人荣誉管理副站长之印官方管理员常务

admin 发表于 2025-11-16 00:27:23 | 显示全部楼层 |阅读模式
布林带突破 + SAR趋势确认策略
这个策略的核心是等待价格突破布林带,并用SAR来确认趋势的有效性,避免假突破。

策略逻辑:
当价格突破布林带上轨,且SAR指标已经位于K线下方(确认上升趋势),则做多。
当价格突破布林带下轨,且SAR指标已经位于K线上方(确认下降趋势),则做空。

多单交易规则:

入场条件:

当前K线收盘价(或实体)上穿布林带上轨。

此时,SAR指标的点位必须已经位于当前K线(或前一根K线)的下方。

两个条件同时满足时,在下一根K线开盘时入场做多。

止损设置:

初始止损设置在最近的一个SAR点位的下方。

或者设置在入场K线最低点的下方。

止盈设置:

追踪止损: 随着行情发展,SAR点位会不断上移,当SAR点位移动到K线上方时,平仓离场。

固定目标: 当价格触及布林带中轨(20期均线)时,可平仓一半,剩余仓位继续用SAR追踪。

空单交易规则:

入场条件:

当前K线收盘价(或实体)下穿布林带下轨。

此时,SAR指标的点位必须已经位于当前K线(或前一根K线)的上方。

两个条件同时满足时,在下一根K线开盘时入场做空。

止损设置:

初始止损设置在最近的一个SAR点位的上方。

或者设置在入场K线最高点的上方。

止盈设置:

追踪止损: 随着行情发展,SAR点位会不断下移,当SAR点位移动到K线下方时,平仓离场。

固定目标: 当价格触及布林带中轨时,可平仓一半,剩余仓位继续用SAR追踪。

源码:
//+------------------------------------------------------------------+
//|                                     BB_SAR_Breakout_EA_Fixed.mq5 |
//|                                  Copyright 2023, Your Name       |
//|                                             https://www.example.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, Your Name"
#property link      "https://www.example.com"
#property version   "1.1 Corrected"
#property description "布林带突破结合SAR确认的交易策略 (已修正编译错误)"

#include <Trade\Trade.mqh> // 引入官方交易库,简化交易操作

//--- 定义离场策略的枚举类型
enum ENUM_EXIT_STRATEGY
{
    EXIT_ON_SAR_FLIP,    // 当SAR反转时离场
    EXIT_ON_MIDDLE_BAND  // 当价格触及布林带中轨时离场
};

//--- EA 输入参数 (可以在EA属性面板中修改)
input group             "交易参数"
input double            InpLots          = 0.01;     // 交易手数
input ulong             InpMagicNumber   = 12345;    // EA魔术号,用于区分不同EA的订单
input int               InpSlippage      = 10;       // 允许的滑点 (points)

input group             "布林带指标参数"
input int               InpBB_Period     = 20;       // 布林带周期
input double            InpBB_Deviation  = 2.0;      // 布林带标准差

input group             "SAR指标参数"
input double            InpSAR_Step      = 0.02;     // SAR 步长 (Step)
input double            InpSAR_Maximum   = 0.2;      // SAR 最大值 (Maximum)

input group             "策略设置"
input ENUM_EXIT_STRATEGY InpExitStrategy = EXIT_ON_SAR_FLIP; // 选择离场策略


//--- 全局变量
CTrade trade;                     // 交易类对象
int    bb_handle;                 // 布林带指标句柄
int    sar_handle;                // SAR指标句柄

//+------------------------------------------------------------------+
//| EA初始化函数                                                     |
//+------------------------------------------------------------------+
int OnInit()
{
    //--- 初始化交易对象
    trade.SetExpertMagicNumber(InpMagicNumber);
    // 修正: CTrade类中设置滑点的方法是 SetDeviationInPoints, 而不是 SetSlippage
    trade.SetDeviationInPoints(InpSlippage);
    trade.SetTypeFillingBySymbol(_Symbol); // 根据交易品种设置成交模式

    //--- 创建指标句柄
    // 创建布林带指标句柄
    bb_handle = iBands(_Symbol, _Period, InpBB_Period, 0, InpBB_Deviation, PRICE_CLOSE);
    if(bb_handle == INVALID_HANDLE)
    {
        Print("创建布林带指标失败,错误代码: ", GetLastError());
        return(INIT_FAILED);
    }

    // 创建SAR指标句柄
    sar_handle = iSAR(_Symbol, _Period, InpSAR_Step, InpSAR_Maximum);
    if(sar_handle == INVALID_HANDLE)
    {
        Print("创建SAR指标失败,错误代码: ", GetLastError());
        return(INIT_FAILED);
    }

    //--- 初始化成功
    return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| EA去初始化函数 (当EA从图表移除时调用)                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    //--- 释放指标句柄资源
    IndicatorRelease(bb_handle);
    IndicatorRelease(sar_handle);
}

//+------------------------------------------------------------------+
//| EA核心逻辑函数 (每个报价到来时执行)                           |
//+------------------------------------------------------------------+
void OnTick()
{
    //--- 定义用于存储指标和价格数据的数组
    // 索引[0] = 当前未收盘K线, 索引[1] = 上一根已收盘K线, 索引[2] = 上上根K线
    double bb_upper[3], bb_lower[3], bb_middle[3];
    double sar_values[3];
    double close_prices[3], high_prices[3], low_prices[3];

    //--- 从指标句柄复制数据到数组中
    // 复制布林带数据 (0: 上轨, 1: 中轨, 2: 下轨)
    if(CopyBuffer(bb_handle, 1, 0, 3, bb_upper) < 3 ||
       CopyBuffer(bb_handle, 0, 0, 3, bb_middle) < 3 || // 注意:iBands的主缓冲区(0)是中轨
       CopyBuffer(bb_handle, 2, 0, 3, bb_lower) < 3)
    {
        Print("获取布林带数据失败");
        return;
    }

    // 复制SAR数据
    if(CopyBuffer(sar_handle, 0, 0, 3, sar_values) < 3)
    {
        Print("获取SAR数据失败");
        return;
    }

    //--- 获取K线价格数据
    if(CopyClose(_Symbol, _Period, 0, 3, close_prices) < 3 ||
       CopyHigh(_Symbol, _Period, 0, 3, high_prices) < 3 ||
       CopyLow(_Symbol, _Period, 0, 3, low_prices) < 3)
    {
        Print("获取价格数据失败");
        return;
    }

    // 修正: CopyBuffer获取的数据默认就是时序的,无需使用ArraySetAsSeries,该函数会导致编译器警告

    //--- 检查是否有新K线诞生,避免在同一根K线上重复开仓
    static datetime lastBarTime = 0;
    datetime currentBarTime = (datetime)SeriesInfoInteger(_Symbol, _Period, SERIES_LASTBAR_DATE);

    bool isNewBar = false;
    if(lastBarTime != currentBarTime)
    {
        lastBarTime = currentBarTime;
        isNewBar = true;
    }

    //--- 持仓管理逻辑 (每个tick都检查)
    ManagePositions(bb_middle, sar_values, high_prices, low_prices);

    //--- 入场逻辑 (只在新K线诞生时检查一次)
    if(isNewBar)
    {
        // 如果当前没有持仓,则检查开仓信号
        if(PositionsTotal() == 0)
        {
            CheckEntrySignal(close_prices, bb_upper, bb_lower, sar_values, high_prices, low_prices);
        }
    }
}

//+------------------------------------------------------------------+
//| 检查入场信号函数                                                 |
//+------------------------------------------------------------------+
void CheckEntrySignal(const double &close[], const double &upper[], const double &lower[],
                      const double &sar[], const double &high[], const double &low[])
{
    //--- 多单入场条件检查 (在上一根K线[索引1]上检查)
    // 1. 上一根K线收盘价上穿布林带上轨
    // 2. 上一根K线的SAR点位在K线下方
    if(close[1] > upper[1] && sar[1] < low[1])
    {
        // 计算止损位:设置为上一根K线对应的SAR点位
        double stop_loss = sar[1];

        // 执行开多单操作
        trade.Buy(InpLots, _Symbol, SymbolInfoDouble(_Symbol, SYMBOL_ASK), stop_loss, 0, "BB SAR Buy");
        return; // 开仓后直接返回,避免检查空单
    }

    //--- 空单入场条件检查 (在上一根K线[索引1]上检查)
    // 1. 上一根K线收盘价下穿布林带下轨
    // 2. 上一根K线的SAR点位在K线上方
    if(close[1] < lower[1] && sar[1] > high[1])
    {
        // 计算止损位:设置为上一根K线对应的SAR点位
        double stop_loss = sar[1];

        // 执行开空单操作
        trade.Sell(InpLots, _Symbol, SymbolInfoDouble(_Symbol, SYMBOL_BID), stop_loss, 0, "BB SAR Sell");
        return;
    }
}

//+------------------------------------------------------------------+
//| 持仓管理函数 (止盈/平仓逻辑)                                     |
//+------------------------------------------------------------------+
void ManagePositions(const double &middle[], const double &sar[], const double &high[], const double &low[])
{
    // 如果没有持仓,直接返回
    if(PositionsTotal() == 0)
    {
        return;
    }

    // 遍历所有持仓
    for(int i = PositionsTotal() - 1; i >= 0; i--)
    {
        // 获取持仓票号
        ulong ticket = PositionGetTicket(i);
        if(ticket > 0)
        {
            // 筛选由本EA、在本图表交易的订单
            if(PositionGetInteger(POSITION_MAGIC) == InpMagicNumber && PositionGetString(POSITION_SYMBOL) == _Symbol)
            {
                long position_type = PositionGetInteger(POSITION_TYPE);

                //--- 多单平仓逻辑
                if(position_type == POSITION_TYPE_BUY)
                {
                    bool close_signal = false;
                    // 检查SAR反转平仓信号 (上一根K线[索引1]的SAR点已经移动到K线上方)
                    if(InpExitStrategy == EXIT_ON_SAR_FLIP && sar[1] > high[1])
                    {
                        close_signal = true;
                    }
                    // 检查触及中轨平仓信号 (当前价格的低点[索引0]触及或低于中轨)
                    if(InpExitStrategy == EXIT_ON_MIDDLE_BAND && low[0] <= middle[0])
                    {
                        close_signal = true;
                    }

                    if(close_signal)
                    {
                        // 修正: PositionClose的第二个参数是滑点, 不是注释。此处省略以使用默认滑点。
                        trade.PositionClose(ticket);
                    }
                }

                //--- 空单平仓逻辑
                else if(position_type == POSITION_TYPE_SELL)
                {
                    bool close_signal = false;
                    // 检查SAR反转平仓信号 (上一根K线[索引1]的SAR点已经移动到K线下方)
                    if(InpExitStrategy == EXIT_ON_SAR_FLIP && sar[1] < low[1])
                    {
                        close_signal = true;
                    }
                    // 检查触及中轨平仓信号 (当前价格的高点[索引0]触及或高于中轨)
                    if(InpExitStrategy == EXIT_ON_MIDDLE_BAND && high[0] >= middle[0])
                    {
                        close_signal = true;
                    }

                    if(close_signal)
                    {
                        // 修正: PositionClose的第二个参数是滑点, 不是注释。此处省略以使用默认滑点。
                        trade.PositionClose(ticket);
                    }
                }
            }
        }
    }
}
//+------------------------------------------------------------------+


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐上一条 /5 下一条

人生者,生存也。
生存所需,财(钱)官(权)也。
财自食伤(子孙福德爻)生,
印星生身荫护,官财印全,适合人间生存也。
若命缺财,缺官,则失去生存权。
一旦脱离父母养育,将天天面临,
从绝望中醒来,又从绝望中睡去。来去如烟!

Archiver|小黑屋|希望祠.同舟.量化

GMT+8, 2026-1-1 21:08 , Processed in 0.020224 second(s), 20 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表