Summary: 黄金结构边缘EA是一款专为XAUUSD设计的MQL4智能交易系统,识别H1枢轴区突破并由多EMA趋势过滤确认。包含硬性回撤限制、每日亏损上限和纯结构逻辑。
黄金结构边缘EA基于一个核心理念设计:成功的黄金交易需要结构清晰而非信号噪音。EA识别H1枢轴区——定义市场结构的波段高点和低点——并等待价格突破这些水平,同时接受多EMA趋势过滤器(维加斯隧道:144、288、576 EMA)的确认。不使用马丁格尔、网格或对冲。每笔交易都带有设在枢轴区之外的硬止损,以及基于ATR风险回报比的止盈。EA包含真正生效的硬编码风控限制:每日亏损上限停止交易、总回撤保护阻止新开仓、紧急制动在波动率超过2.5倍ATR时平仓所有头寸。这些限制并非装饰——它们是策略在整个市场周期中保持可控回撤的原因。
推荐加载周期: H1
策略核心逻辑:
1. 枢轴区检测:识别最近20根H1 K线的最高高点和最低低点作为结构枢轴水平。
2. 趋势过滤:维加斯隧道(EMA 144、288、576)在H1上必须全部同向排列。
3. 突破确认:价格收盘高于枢轴高点(做多)或低于枢轴低点(做空),且为动量K线(实体 > 0.7倍区间)。
4. 入场:确认后下一根K线开盘价入场。
5. 风险管理:硬止损为枢轴区外1.5倍ATR;止盈为2.2倍ATR;盈利达到0.8倍ATR后启动追踪止损。
```mql4
//+------------------------------------------------------------------+
//| GoldStructuralEdgeEA.mq4 |
//+------------------------------------------------------------------+
#property copyright ""
#property link ""
#property version "1.00"
#property strict
//--- 输入参数及注释
input double LotSize = 0.01; // 固定交易手数(黄金0.01手)
input int PivotLookback = 20; // 枢轴区检测回溯K线数
input int VegasFastEMA = 144; // 维加斯隧道快EMA
input int VegasMidEMA = 288; // 维加斯隧道中EMA
input int VegasSlowEMA = 576; // 维加斯隧道慢EMA
input double MinBodyRangeRatio = 0.7; // 最小实体/区间比例(动量确认)
input int ATRPeriod = 14; // ATR周期(止损/止盈计算)
input double ATRStopMultiplier = 1.5; // 止损倍数(ATR倍数)
input double ATRTakeMultiplier = 2.2; // 止盈倍数(ATR倍数)
input double TrailingStartATR = 0.8; // 追踪止损启动(盈利达到x倍ATR)
input double TrailingStepATR = 0.4; // 追踪步长(ATR倍数)
input double MaxDailyLossPercent = 3.0; // 硬性每日亏损上限(停止交易)
input double MaxDrawdownPercent = 8.0; // 硬性总回撤上限
input int MaxConsecutiveLosses = 5; // 最大连续亏损次数(超限后暂停)
input double EmergencyATRMultiplier = 2.5; // 紧急制动:ATR超过avgATR倍数时平仓
input int MagicNumber = 202502; // EA魔术号
input int MaxSpread = 35; // 最大允许点差(黄金单位:点)
//--- 全局变量
double dailyStartBalance = 0;
double peakEquity = 0;
datetime lastBarTime = 0;
int consecutiveLosses = 0;
datetime lastLossTime = 0;
double avgATR = 0;
bool drawdownStop = false;
bool dailyStop = false;
double pivotHigh = 0;
double pivotLow = 0;
//+------------------------------------------------------------------+
//| EA初始化函数 |
//+------------------------------------------------------------------+
int OnInit()
{
dailyStartBalance = AccountBalance();
peakEquity = AccountEquity();
lastBarTime = 0;
consecutiveLosses = 0;
drawdownStop = false;
dailyStop = false;
avgATR = iATR(Symbol(), PERIOD_H1, ATRPeriod, 1);
if(avgATR <= 0) avgATR = 250 * Point;
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| EA退出函数 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
Comment("");
}
//+------------------------------------------------------------------+
//| 获取维加斯隧道趋势方向(所有EMA同向排列) |
//+------------------------------------------------------------------+
int GetVegasTrend()
{
double emaFast = iMA(Symbol(), PERIOD_H1, VegasFastEMA, 0, MODE_EMA, PRICE_CLOSE, 1);
double emaMid = iMA(Symbol(), PERIOD_H1, VegasMidEMA, 0, MODE_EMA, PRICE_CLOSE, 1);
double emaSlow = iMA(Symbol(), PERIOD_H1, VegasSlowEMA, 0, MODE_EMA, PRICE_CLOSE, 1);
double emaFastPrev = iMA(Symbol(), PERIOD_H1, VegasFastEMA, 0, MODE_EMA, PRICE_CLOSE, 2);
double emaMidPrev = iMA(Symbol(), PERIOD_H1, VegasMidEMA, 0, MODE_EMA, PRICE_CLOSE, 2);
double emaSlowPrev = iMA(Symbol(), PERIOD_H1, VegasSlowEMA, 0, MODE_EMA, PRICE_CLOSE, 2);
bool bullishAlign = (emaFast > emaMid && emaMid > emaSlow);
bool bearishAlign = (emaFast < emaMid && emaMid < emaSlow);
bool bullishSlope = (emaFast > emaFastPrev && emaMid > emaMidPrev && emaSlow > emaSlowPrev);
bool bearishSlope = (emaFast < emaFastPrev && emaMid < emaMidPrev && emaSlow < emaSlowPrev);
if(bullishAlign && bullishSlope) return 1;
if(bearishAlign && bearishSlope) return -1;
return 0;
}
//+------------------------------------------------------------------+
//| 检测枢轴区水平(波段高低点) |
//+------------------------------------------------------------------+
void DetectPivotZone()
{
int highestIdx = iHighest(Symbol(), PERIOD_H1, MODE_HIGH, PivotLookback, 1);
int lowestIdx = iLowest(Symbol(), PERIOD_H1, MODE_LOW, PivotLookback, 1);
if(highestIdx > 0)
pivotHigh = iHigh(Symbol(), PERIOD_H1, highestIdx);
if(lowestIdx > 0)
pivotLow = iLow(Symbol(), PERIOD_H1, lowestIdx);
}
//+------------------------------------------------------------------+
//| 检查动量K线质量 |
//+------------------------------------------------------------------+
bool IsMomentumCandle(int direction)
{
double open = iOpen(Symbol(), PERIOD_H1, 1);
double close = iClose(Symbol(), PERIOD_H1, 1);
double high = iHigh(Symbol(), PERIOD_H1, 1);
double low = iLow(Symbol(), PERIOD_H1, 1);
double range = high - low;
double body = MathAbs(close - open);
if(range <= 0) return false;
if(body / range < MinBodyRangeRatio) return false;
if(direction == 1) // 看涨动量
return (close > open && close > pivotHigh);
else if(direction == -1) // 看跌动量
return (close < open && close < pivotLow);
return false;
}
//+------------------------------------------------------------------+
//| 检查突破入场条件 |
//+------------------------------------------------------------------+
bool CheckBreakoutEntry(int trendDir, double &entryPrice, double &sl, double &tp, double atr)
{
if(trendDir == 0) return false;
if(pivotHigh <= 0 || pivotLow <= 0) return false;
double close1 = iClose(Symbol(), PERIOD_H1, 1);
if(trendDir == 1 && close1 > pivotHigh && IsMomentumCandle(1))
{
entryPrice = Ask;
sl = entryPrice - (atr * ATRStopMultiplier);
tp = entryPrice + (atr * ATRTakeMultiplier);
return true;
}
else if(trendDir == -1 && close1 < pivotLow && IsMomentumCandle(-1))
{
entryPrice = Bid;
sl = entryPrice + (atr * ATRStopMultiplier);
tp = entryPrice - (atr * ATRTakeMultiplier);
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| 更新连续亏损计数器(市场记忆) |
//+------------------------------------------------------------------+
void UpdateLossCounter()
{
static int prevOrders = 0;
static double prevEquity = 0;
int currentOrders = CountPositions();
double currentEquity = AccountEquity();
if(prevOrders > 0 && currentOrders == 0)
{
double equityChange = currentEquity - prevEquity;
if(equityChange < 0)
{
consecutiveLosses++;
lastLossTime = TimeCurrent();
}
else if(equityChange > 0)
{
consecutiveLosses = 0;
}
}
if(currentOrders > 0)
prevEquity = currentEquity;
prevOrders = currentOrders;
}
//+------------------------------------------------------------------+
//| 检查并执行硬性风控限制 |
//+------------------------------------------------------------------+
bool CheckHardRiskLimits()
{
double currentEquity = AccountEquity();
double dailyLossPercent = (dailyStartBalance - currentEquity) / dailyStartBalance * 100;
double totalDrawdownPercent = (peakEquity - currentEquity) / peakEquity * 100;
// 更新峰值权益
if(currentEquity > peakEquity)
peakEquity = currentEquity;
// 每日亏损限制
if(dailyLossPercent >= MaxDailyLossPercent)
{
if(!dailyStop)
{
CloseAllOrders();
dailyStop = true;
Comment("每日亏损上限触发,今日停止交易");
}
return false;
}
// 总回撤限制
if(totalDrawdownPercent >= MaxDrawdownPercent)
{
if(!drawdownStop)
{
CloseAllOrders();
drawdownStop = true;
Comment("最大回撤上限触发,EA暂停");
}
return false;
}
// 连续亏损冷却
if(consecutiveLosses >= MaxConsecutiveLosses)
{
if(TimeCurrent() - lastLossTime < 3600) // 冷却1小时
{
Comment("连续亏损冷却中,已亏损", consecutiveLosses, "次");
return false;
}
else
{
consecutiveLosses = 0;
}
}
return true;
}
//+------------------------------------------------------------------+
//| 紧急制动:波动率爆炸时平仓 |
//+------------------------------------------------------------------+
void CheckEmergencyBrake()
{
double atr = iATR(Symbol(), PERIOD_H1, ATRPeriod, 1);
if(atr > avgATR * EmergencyATRMultiplier && avgATR > 0)
{
CloseAllOrders();
Comment("紧急制动触发:波动率过高 ATR ", atr);
}
if(atr > 0) avgATR = (avgATR * 0.95) + (atr * 0.05);
}
//+------------------------------------------------------------------+
//| 管理持仓的追踪止损 |
//+------------------------------------------------------------------+
void ManageTrailingStop(double atr)
{
for(int i = OrdersTotal()-1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
{
double activate = atr * TrailingStartATR;
double step = atr * TrailingStepATR;
double newSL = 0;
if(OrderType() == OP_BUY)
{
double profit = Bid - OrderOpenPrice();
if(profit >= activate)
{
newSL = Bid - step;
if(newSL > OrderStopLoss())
OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrNONE);
}
}
else if(OrderType() == OP_SELL)
{
double profit = OrderOpenPrice() - Ask;
if(profit >= activate)
{
newSL = Ask + step;
if(newSL < OrderStopLoss() || OrderStopLoss() == 0)
OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrNONE);
}
}
break;
}
}
}
}
//+------------------------------------------------------------------+
//| EA主循环函数(每Tick执行) |
//+------------------------------------------------------------------+
void OnTick()
{
// 更新亏损计数器(市场记忆)
UpdateLossCounter();
// 优先检查紧急制动
CheckEmergencyBrake();
// 检查硬性风控限制
if(!CheckHardRiskLimits())
return;
// 每日重置
datetime currentTime = TimeCurrent();
static datetime lastDay = 0;
if(TimeDayOfYear(currentTime) != TimeDayOfYear(lastDay))
{
dailyStartBalance = AccountBalance();
dailyStop = false;
lastDay = currentTime;
}
// 周五收盘保护
if(TimeDayOfWeek(currentTime) == 5 && TimeHour(currentTime) >= 21)
{
if(CountPositions() > 0)
CloseAllOrders();
return;
}
// 点差过滤
if(MarketInfo(Symbol(), MODE_SPREAD) > MaxSpread)
{
Comment("当前点差过大:", MarketInfo(Symbol(), MODE_SPREAD));
return;
}
// 仅在新K线开始时检测入场(H1)
if(Time[0] == lastBarTime)
return;
lastBarTime = Time[0];
// 管理现有持仓
int posCount = CountPositions();
if(posCount > 0)
{
double atr = iATR(Symbol(), PERIOD_H1, ATRPeriod, 1);
if(atr > 0) ManageTrailingStop(atr);
return;
}
// 获取ATR
double atr = iATR(Symbol(), PERIOD_H1, ATRPeriod, 1);
if(atr <= 0) atr = avgATR;
// 检测枢轴区水平
DetectPivotZone();
// 获取维加斯隧道趋势方向
int trendDir = GetVegasTrend();
if(trendDir == 0)
{
Comment("维加斯隧道无明确同向排列");
return;
}
// 检查突破入场
double entryPrice = 0, sl = 0, tp = 0;
if(CheckBreakoutEntry(trendDir, entryPrice, sl, tp, atr))
{
int cmd = (trendDir == 1) ? OP_BUY : OP_SELL;
int ticket = OrderSend(Symbol(), cmd, LotSize, entryPrice, 5, sl, tp, "Structural Edge", MagicNumber, 0, clrNONE);
if(ticket < 0)
Print("开仓失败,错误码:", GetLastError());
else
Print("枢轴突破开仓成功,方向:", cmd==OP_BUY?"买入":"卖出");
}
}
//+------------------------------------------------------------------+
//| 统计当前魔术号的持仓数量 |
//+------------------------------------------------------------------+
int CountPositions()
{
int count = 0;
for(int i = OrdersTotal()-1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
count++;
}
}
return count;
}
//+------------------------------------------------------------------+
//| 平仓当前品种下所有属于该EA的订单 |
//+------------------------------------------------------------------+
void CloseAllOrders()
{
for(int i = OrdersTotal()-1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
{
if(OrderType() == OP_BUY)
OrderClose(OrderTicket(), OrderLots(), Bid, 5, clrNONE);
else if(OrderType() == OP_SELL)
OrderClose(OrderTicket(), OrderLots(), Ask, 5, clrNONE);
}
}
}
}
//+------------------------------------------------------------------+
```
参考来源: 原创MQL4代码,策略架构参考了2025-2026年MQL5市场上黄金EA的结构化交易原理,包括Gold BullBear Structure Trader的枢轴区检测方法和