在MQL5中构建自优化智能交易系统(EA)(第五部分):自适应交易规则·进阶篇
(2/3)· 固定RSI周期碰上三月无信号?本篇用平均走势倍数改写突破确认逻辑
「高低周期联动的突破触发逻辑」
在 MT5 多周期策略里,大周期(TF_1)负责画支撑阻力,小周期(TF_2)负责盯盘下单。代码用 static datetime time_stamp 做时间戳比对,只有当前 K 线时间变了才刷新数据,避免每 tick 重复计算。 大周期侧每次刷新会重取 RSI 与 ATR 缓冲,并用 iLow(Symbol(),TF_1,5) / iHigh(Symbol(),TF_1,5) 把前 5 根 K 的高低点当支撑阻力,先删旧横线再建新线。注意原文 ObjectCreate 里支撑线名字拼成了 "Suppoprt",渲染层会显示两条线名不一致,复制时得手改。 小周期侧在无持仓时判断:若 TF_2 当前最低价大于 resistance,且 rsi[0]>70,则倾向以卖价开空,止损放在 ask + ATR_SIZE*atr[0]、止盈在 ask - ATR_SIZE*atr[0];若 TF_2 最高价小于 support 则走反向买逻辑。外汇与贵金属杠杆高,这类突破反转信号失败概率不低,实盘前务必在策略测试器用历史数据验一遍 ATR_SIZE 取值。
class="type">class="kw">datetime current_time = iTime(Symbol(),TF_1,class="num">0); class=class="str">"cmt">//Update the time if(time_stamp != current_time) { time_stamp = current_time; class=class="str">"cmt">//Update indicator readings CopyBuffer(rsi_handler,class="num">0,class="num">0,class="num">1,rsi); CopyBuffer(atr_handler,class="num">0,class="num">0,class="num">1,atr); class=class="str">"cmt">//Update our support and resistance levels support = iLow(Symbol(),TF_1,class="num">5); resistance = iHigh(Symbol(),TF_1,class="num">5); ObjectDelete(class="num">0,"Support"); ObjectDelete(class="num">0,"Resistance"); ObjectCreate(class="num">0,"Suppoprt",OBJ_HLINE,class="num">0,class="num">0,support); ObjectCreate(class="num">0,"Resistance",OBJ_HLINE,class="num">0,class="num">0,resistance); } } class=class="str">"cmt">//While other duties need more attention, and must be handled on lower time frames. { class="kw">static class="type">class="kw">datetime time_stamp; class="type">class="kw">datetime current_time = iTime(Symbol(),TF_2,class="num">0); class="type">class="kw">double bid,ask; class=class="str">"cmt">//Update the time if(time_stamp != current_time) { time_stamp = current_time; bid=SymbolInfoDouble(Symbol(),SYMBOL_BID); ask=SymbolInfoDouble(Symbol(),SYMBOL_ASK); class=class="str">"cmt">//Check if we have broken either extreme if(PositionsTotal() == class="num">0) { class=class="str">"cmt">//We are looking for opportunities to sell if(iLow(Symbol(),TF_2,class="num">0) > resistance) { if(rsi[class="num">0] > class="num">70) Trade.Sell(VOL,Symbol(),bid,(ask + (ATR_SIZE * atr[class="num">0])),(ask - (ATR_SIZE * atr[class="num">0]))); } class=class="str">"cmt">//We are looking for opportunities to buy if(iHigh(Symbol(),TF_2,class="num">0) < support) {
RSI 超卖后的下单与宏定义收尾
当 RSI 最新值跌破 30 阈值,脚本以当前卖价 ask 买入 0.1 手,止损设在 bid 减去 1.5 倍 ATR,止盈设在 bid 加上 1.5 倍 ATR,这套边界用 ATR 动态宽度替代固定点数。 交易块跑完之后,程序用 #undef 把 RSI_PERIOD、RSI_PRICE、ATR_PERIOD、ATR_SIZE、TF_1、TF_2、VOL 全部取消定义,避免宏名泄漏到后续编译单元。 紧接着是第二段源码的头部:重新 #define RSI_PERIOD 10、RSI_PRICE 为收盘价、ATR_SIZE 1.5、ATR_PERIOD 14、TF_1 为日线、TF_2 为 M15、VOL 0.1,并引入 CTrade Trade 做下单对象。外汇与贵金属杠杆高,这类固定 0.1 手参数在极端波动下可能触发超预期浮亏,上 MT5 改 VOL 前先算账户净值承受度。
if(rsi[class="num">0] < class="num">30) Trade.Buy(VOL,Symbol(),ask,(bid - (ATR_SIZE * atr[class="num">0])),(bid + (ATR_SIZE * atr[class="num">0]))); class="macro">#undef RSI_PERIOD class="macro">#undef RSI_PRICE class="macro">#undef ATR_PERIOD class="macro">#undef ATR_SIZE class="macro">#undef TF_1 class="macro">#undef TF_2 class="macro">#undef VOL class="macro">#define RSI_PERIOD class="num">10 class="macro">#define RSI_PRICE PRICE_CLOSE class="macro">#define ATR_SIZE class="num">1.5 class="macro">#define ATR_PERIOD class="num">14 class="macro">#define TF_1 PERIOD_D1 class="macro">#define TF_2 PERIOD_M15 class="macro">#define VOL class="num">0.1 class="macro">#include <Trade/Trade.mqh> CTrade Trade;
◍ 把指标句柄和支撑阻力塞进全局
EA 跑起来最怕两件事:指标句柄重复创建拖慢终端,以及支撑阻力用了过期报价。下面这段初始化骨架把 RSI、ATR 句柄和前 5 根 K 的高低点一次性挂到全局,后续 OnTick 只做更新不重建。
注意 iHigh(Symbol(),TF_1,5) 取的是 TF_1 周期上 shift=5 的那根 K 线高点,不是实时最新价。若 TF_1 选 H1、品种跳空,这个 support/resistance 可能滞后一根,实盘前先在 MT5 用 Comment(support,resistance) 打印核对。
setup() 里 ATR_PERIOD、RSI_PERIOD 都是外部宏,没填具体数字就编译不过;复制代码时先把这些常量在文件头定义好,例如 #define ATR_PERIOD 14、#define RSI_PERIOD 14。外汇与贵金属杠杆高,句柄泄漏会让策略在长跑中变卡甚至掉单,释放逻辑不能省。
class=class="str">"cmt">//| Global variables | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int rsi_handler,atr_handler; class="type">class="kw">double rsi[],atr[]; class="type">class="kw">double support,resistance; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Expert initialization function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- setup(); class=class="str">"cmt">//--- class="kw">return(INIT_SUCCEEDED); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Expert deinitialization function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnDeinit(const class="type">int reason) { class=class="str">"cmt">//--- release(); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Expert tick function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- update(); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| User defined methods | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Initialize our system variables | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void setup(class="type">void) { class=class="str">"cmt">//Load our technical indicators atr_handler = iATR(Symbol(),TF_1,ATR_PERIOD); rsi_handler = iRSI(Symbol(),TF_2,RSI_PERIOD,RSI_PRICE); resistance = iHigh(Symbol(),TF_1,class="num">5); support = iLow(Symbol(),TF_1,class="num">5); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Let go of resources we are no longer consuming | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void release(class="type">void) { class=class="str">"cmt">//Free up resources we are not class="kw">using IndicatorRelease(atr_handler); IndicatorRelease(rsi_handler); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Update our system variables and look for trading setups | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void update(class="type">void) { class=class="str">"cmt">//Update our system variables class=class="str">"cmt">//Some duties must be performed periodically on the higher time frame { class="kw">static class="type">class="kw">datetime time_stamp;
「小周期上用突破极值抓反转单」
大周期负责画支撑阻力,真正下单的触发逻辑放在更低周期 TF_2 里跑。每次 TF_2 的 0 号 K 线换新(用静态 time_stamp 比对 iTime 判断),才刷新一次 bid / ask 并扫条件,避免每 tick 重复计算。 无持仓时,若 TF_2 当前最低价高于 resistance,且 rsi[0] 大于 70,倾向视为向上假突破后的反转卖点;若 TF_2 当前最高价低于 support,且 rsi[0] 小于 30,则倾向抓向下假突破后的回买。止损止盈都用 ATR_SIZE 倍的 atr[0] 对称展开。 注意原文 ObjectCreate 里把支撑线名字拼成了 "Suppoprt",而删除时叫 "Support",这条线实际删不掉,会在图表上留垃圾。外汇与贵金属杠杆高,假突破失败概率不低,参数未经实盘验证前先用策略测试器跑一遍。 下面这段是 TF_2 触发块的核心,去掉了外层大周期部分,方便直接对照:
{
class="kw">static class="type">class="kw">datetime time_stamp;
class="type">class="kw">datetime current_time = iTime(Symbol(),TF_2,class="num">0);
class="type">class="kw">double bid,ask;
class=class="str">"cmt">//Update the time
if(time_stamp != current_time)
{
time_stamp = current_time;
bid=SymbolInfoDouble(Symbol(),SYMBOL_BID);
ask=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
class=class="str">"cmt">//Check if we have broken either extreme
if(PositionsTotal() == class="num">0)
{
class=class="str">"cmt">//We are looking for opportunities to sell
if(iLow(Symbol(),TF_2,class="num">0) > resistance)
{
if(rsi[class="num">0] > class="num">70)
Trade.Sell(VOL,Symbol(),bid,(ask + (ATR_SIZE * atr[class="num">0])),(ask - (ATR_SIZE * atr[class="num">0])));
}
class=class="str">"cmt">//We are looking for opportunities to buy
if(iHigh(Symbol(),TF_2,class="num">0) < support)
{
if(rsi[class="num">0] < class="num">30)
Trade.Buy(VOL,Symbol(),ask,(bid - (ATR_SIZE * atr[class="num">0])),(bid + (ATR_SIZE * atr[class="num">0])));
}
}
}
}