【量化源码策略】布林带突破 + SAR趋势确认策略
布林带突破 + 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()
{
//--- 定义用于存储指标和价格数据的数组
// 索引 = 当前未收盘K线, 索引 = 上一根已收盘K线, 索引 = 上上根K线
double bb_upper, bb_lower, bb_middle;
double sar_values;
double close_prices, high_prices, low_prices;
//--- 从指标句柄复制数据到数组中
// 复制布林带数据 (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 > upper && sar < low)
{
// 计算止损位:设置为上一根K线对应的SAR点位
double stop_loss = sar;
// 执行开多单操作
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 < lower && sar > high)
{
// 计算止损位:设置为上一根K线对应的SAR点位
double stop_loss = sar;
// 执行开空单操作
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 > high)
{
close_signal = true;
}
// 检查触及中轨平仓信号 (当前价格的低点[索引0]触及或低于中轨)
if(InpExitStrategy == EXIT_ON_MIDDLE_BAND && low <= middle)
{
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 < low)
{
close_signal = true;
}
// 检查触及中轨平仓信号 (当前价格的高点[索引0]触及或高于中轨)
if(InpExitStrategy == EXIT_ON_MIDDLE_BAND && high >= middle)
{
close_signal = true;
}
if(close_signal)
{
// 修正: PositionClose的第二个参数是滑点, 不是注释。此处省略以使用默认滑点。
trade.PositionClose(ticket);
}
}
}
}
}
}
//+------------------------------------------------------------------+
页:
[1]