本专家顾问(EA)专为XAUUSD(黄金)品种量身打造,旨在应对其高波动性、对点差的敏感性以及无固定交易时段的固有特征。代码完全独立,无需外部DLL,专为稳定、低风险的自动化交易而设计。
加载周期建议
本EA的推荐加载时间框架为 M15(15分钟图) 。这一选择基于策略在信号颗粒度与噪声过滤之间寻求平衡的需求。M15时间框架能为基于ATR的动态网格和RSI极值过滤器提供足够的价格行为细节,同时又能有效过滤掉M1或M5等更低时间框架上常见的过度噪声,这些噪声容易引发虚假信号并增加交易成本。实践表明,许多专业黄金EA都选择在M15或H1图表上运行,因为这是在捕捉有意义的价格波动与过滤微小波动之间的理想平衡点。
交易逻辑
本EA采用混合逻辑运行,结合了趋势跟踪的初始入场和一种经过精心设计的、风险可控的网格恢复系统。它并非一个盲目加仓的网格系统;所有操作都受到波动性和动量条件的过滤。
1. 初始入场条件:
MaxSpread),并确保波动率(通过ATR衡量)处于合理范围内,以规避动荡的市场状况。2. 网格恢复机制:
当初始头寸朝不利方向移动时,EA会激活一个恢复网格。这是一个精心管理的过程:
GridATR_Multiplier)动态计算。这意味着网格会在高波动时自动扩展,在低波动时收缩,从而适应市场状况,而不是使用可能带来风险的固定点数步长。MaxGridOrders),以防止风险呈指数级增长。后续每单的仓位大小通过一个乘数(GridMultiplier)增加,但会设置上限以控制保证金使用。3. 出场与风险管理:
GridTargetProfit)使用动态止盈目标,使整个网格能实现整体盈利后平仓。GridTrailStartPips, GridTrailDistPips)以锁定订单组合的利润。- 最大回撤: 基于账户净值的硬性浮动亏损限制(
MaxFloatingLossPct)。- 每日止损: 每日亏损限制(
DailyStopPct),在表现不佳时暂停交易。- 冷却期: 在一系列连续亏损后激活冷却期(
UseCooldown),防止情绪化交易,给予市场喘息空间。- 时间过滤器: 可选的交易时段过滤器,将交易限制在特定时段,这对于管理低流动性时期的风险至关重要。
独家视角:黄金波动的非对称性与“时段感知ATR”
我对XAUUSD市场的独立理解,结合国际清算银行(BIS)的研究,凸显了其波动性的一个关键不对称性。虽然标准的ATR能提供平均波动性的有用度量,但它并未考虑到主要交易时段(伦敦、纽约、亚洲)之间结构性流动性差异。
BIS指出,黄金现货市场的交易量高度集中在伦敦和纽约时段的重叠期,这导致流动性更高,但矛盾的是,价格波动也更频繁,尽管通常是均值回归性质的。相比之下,亚洲时段虽然通常较为平静,但在流动性较薄的情况下可能突然出现剧烈波动,而单一的、聚合的ATR值无法很好地捕捉这种特征。
为了解决这一问题,本EA的逻辑不仅仅停留在简单的ATR缩放。它融合了一个“时段感知”ATR计算。这不仅是一个针对入场时间的过滤器,更是对
UseDynamicGridStep逻辑的修正。EA在内部会根据当前交易时段区分ATR周期(例如,14期vs.30期),或对动态网格步长应用一个乘数因子。例如,在亚洲时段,网格步长会被加宽以应对潜在的流动性不足缺口;在伦敦/纽约重叠时段的高影响新闻事件期间,步长会进一步加宽。这防止了网格在平静但易突变的市场中过于紧密,或在流动性和波动性都很高的市场中过于宽松,从而优化了恢复过程并降低了整体回撤风险。这种复杂的波动率管理方法是让EA为“黄金交易”做好准备的“秘密武器”。参考来源
源码
``
cpp
//+------------------------------------------------------------------+
//| GoldVolatilityGrid.mq4 |
//| Copyright 2026, FXEAR |
//| https://www.fxear.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, FXEAR"
#property link "https://www.fxear.com"
#property version "1.00"
#property strict
//+------------------------------------------------------------------+
//| 输入参数及其完整说明 |
//+------------------------------------------------------------------+
//--- 常规设置
input string General_Settings = "═══════ 常规设置 ═══════"; // 常规设置
input string CustomComment = "GoldGrid"; // 订单注释
input bool AutoStart = true; // 附加到图表时自动启动
input int MagicNumber = 20260621; // 魔术号(EA唯一标识)
input int Slippage = 3; // 最大滑点(以点为单位)
input int MaxSpread = 300; // 最大点差(以点为单位,对于2位小数经纪商300=30.0点)
input bool TradeFriday = false; // 允许在星期五交易
input int EntryTF = 15; // 入场时间框架(推荐M15)
input bool UseSessionFilter = true; // 启用交易时段过滤器
input int SessionStartHour = 1; // 时段开始小时(0-23,经纪商时间)
input int SessionEndHour = 22; // 时段结束小时(0-23,经纪商时间)
//--- 恢复参数
input string Recovery_Settings = "═══════ 恢复参数 ═══════"; // 恢复设置
input bool UseDynamicGridStep = true; // 使用基于ATR的动态网格步长
input int GridStepPips = 150; // 基础网格步长(以点为单位,1点=10个价格点)
input double GridMultiplier = 1.5; // 每级网格的手数乘数(1.0=固定手数)
input int MaxGridOrders = 5; // 每个方向的最大网格订单数
input int GridTargetProfit = 50; // 距盈亏平衡点的网格目标盈利(点)
input double GridDistanceMult = 1.2; // 每级网格步长扩展乘数
input double GridATR_Multiplier = 1.5; // 动态步长的ATR乘数(若UseDynamicGridStep=true)
input bool UseGridNewBar = true; // 仅在新K线时开启网格订单
input bool UseGridCandleConfirm = true; // 要求K线收盘确认网格入场
//--- 过滤器与安全参数
input string Filters_Settings = "═══════ 过滤器与安全参数 ═══════"; // 过滤器与安全设置
input bool UseTrendFilter = true; // 初始入场使用H1趋势过滤
input int TrendMAPeriod = 100; // H1趋势MA周期
input bool UseRSI_Entry = true; // 初始入场使用RSI过滤
input int RSI_Period = 14; // RSI周期
input int RSI_BuyTrigger = 30; // RSI买入触发水平(超卖)
input int RSI_SellTrigger = 70; // RSI卖出触发水平(超买)
input bool UseWPR_GridFilter = true; // 使用WPR过滤网格恢复入场
input int WPR_Period = 14; // WPR周期
input int WPR_BuyTrigger = -80; // WPR买入触发水平(超卖)
input int WPR_SellTrigger = -20; // WPR卖出触发水平(超买)
input bool UseMACD_GridFilter = true; // 使用MACD过滤网格恢复入场
input int MACD_Fast = 12; // MACD快线EMA
input int MACD_Slow = 26; // MACD慢线EMA
input int MACD_Signal = 9; // MACD信号线SMA
input bool UseGridTrailing = true; // 在网格组合上使用移动止损
input int GridTrailStartPips = 150; // 启动移动止损的盈利点数(点)
input int GridTrailDistPips = 100; // 移动止损距离(点)
input int GridTrailStepPips = 25; // 移动止损步长(点)
//--- 支撑/阻力引擎
input string SR_Settings = "═══════ 支撑/阻力引擎 ═══════"; // 支撑/阻力引擎
input int SR_TF = 60; // 计算S/R的时间框架(H1)
input int SR_ScanBars = 100; // 扫描S/R水平的K线数量
input int SR_LeftRightBars = 5; // 定义峰/谷的相邻K线数量
input int SR_ZoneHeightPips = 50; // S/R区域的高度(点)
input bool ShowSRLines = true; // 在图表上显示S/R线
input bool UseSR_GridFilter = true; // 使用S/R过滤器延迟网格订单
input int SR_GridTolerancePips = 20; // 网格入场的S/R区域容差(点)
input int SR_WaitRangePips = 50; // 在网格步长附近搜索S/R的范围
input int SR_MaxWaitBars = 5; // 等待S/R反弹的最大M15 K线数
//--- 风险保护与安全
input string Risk_Settings = "═══════ 风险保护 ═══════"; // 风险保护
input double DailyStopPct = 2.0; // 每日亏损限制(账户余额百分比,0=禁用)
input double DailyProfitPct = 5.0; // 每日利润目标(账户余额百分比,0=禁用)
input double MaxFloatingLossPct = 10.0; // 允许的最大浮动亏损(账户余额百分比)
input double MinMarginLevel = 150.0; // 开新单的最低保证金水平(百分比)
input double MaxGridDrawdownUSD = 0; // 网格最大亏损额(以美元计,0=禁用)
input bool UseCooldown = true; // 亏损后启用冷却期
input int MaxConsecLosses = 3; // 触发冷却前的最大连续亏损次数
input int CooldownBars = 5; // 冷却期持续时间(以M15 K线计)
input double RiskPercent = 0.5; // 每笔交易风险(账户余额百分比,用于初始手数)
//+------------------------------------------------------------------+
//| 全局变量 |
//+------------------------------------------------------------------+
double g_point;
int g_magic;
datetime g_lastTradeTime;
int g_tradesToday;
double g_dailyProfit;
double g_maxFloatingLoss;
datetime g_lastBarTime;
datetime g_cooldownEndTime;
bool g_isCooldown;
int g_consecutiveLosses;
double g_equityProtect;
double g_balanceProtect;
//--- S/R数组
double g_supportLevels[];
double g_resistanceLevels[];
datetime g_srTimestamps[];
//+------------------------------------------------------------------+
//| 专家初始化函数 |
//+------------------------------------------------------------------+
int OnInit()
{
//--- 初始化变量
g_magic = MagicNumber;
g_point = Point;
if (Digits == 3 || Digits == 5)
g_point = Point 10;
g_lastTradeTime = 0;
g_tradesToday = 0;
g_dailyProfit = 0;
g_maxFloatingLoss = 0;
g_lastBarTime = 0;
g_cooldownEndTime = 0;
g_isCooldown = false;
g_consecutiveLosses = 0;
g_equityProtect = 0;
g_balanceProtect = 0;
//--- 参数验证
if (RiskPercent <= 0 || RiskPercent > 10)
{
Print("错误:RiskPercent 必须在 0.1 和 10 之间。使用默认值 0.5。");
RiskPercent = 0.5;
}
//--- 初始化S/R数组
ArrayResize(g_supportLevels, 0);
ArrayResize(g_resistanceLevels, 0);
ArrayResize(g_srTimestamps, 0);
//--- 检查所需时间框架
if (Period() != EntryTF)
{
Print("警告:EA 设计用于 M", EntryTF, " 时间框架。当前:", Period());
// 允许运行但发出警告
}
Print("GoldVolatilityGrid 初始化成功。");
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| 专家反初始化函数 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- 清理图表对象
if (ShowSRLines)
{
ObjectsDeleteAll(0, "SR_");
}
Print("GoldVolatilityGrid 已反初始化。");
}
//+------------------------------------------------------------------+
//| 专家报价处理函数 |
//+------------------------------------------------------------------+
void OnTick()
{
//--- 检查新K线
if (Time[0] == g_lastBarTime) return;
g_lastBarTime = Time[0];
//--- 检查自动启动
if (!AutoStart) return;
//--- 检查交易时段
if (UseSessionFilter && !IsWithinSession()) return;
//--- 检查星期五交易
if (!TradeFriday && TimeDayOfWeek(TimeCurrent()) == 5) return;
//--- 检查冷却期
if (g_isCooldown)
{
if (TimeCurrent() >= g_cooldownEndTime)
{
g_isCooldown = false;
Print("冷却期结束。");
}
else
{
return;
}
}
//--- 更新每日统计
UpdateDailyStats();
//--- 检查风险保护
if (!CheckRiskProtection()) return;
//--- 检查保证金水平
if (!CheckMarginLevel()) return;
//--- 更新S/R水平
if (ShowSRLines || UseSR_GridFilter)
UpdateSupportResistance();
//--- 统计当前未平仓订单
int buyOrders = 0, sellOrders = 0;
double buyAvgPrice = 0, sellAvgPrice = 0;
double buyProfit = 0, sellProfit = 0;
CountOpenOrders(buyOrders, sellOrders, buyAvgPrice, sellAvgPrice, buyProfit, sellProfit);
//--- 检查网格止盈
CheckGridTakeProfit(buyOrders, sellOrders, buyAvgPrice, sellAvgPrice, buyProfit, sellProfit);
//--- 管理移动止损
if (UseGridTrailing)
ManageTrailingStops();
//--- 检查新入场信号
if (buyOrders == 0 && sellOrders == 0)
{
//--- 无持仓,检查初始入场
CheckInitialEntry();
}
else
{
//--- 有持仓,管理网格
ManageGrid(buyOrders, sellOrders, buyAvgPrice, sellAvgPrice);
}
//--- 更新浮动亏损保护
CheckFloatingLoss();
}
//+------------------------------------------------------------------+
//| 检查当前时间是否在交易时段内 |
//+------------------------------------------------------------------+
bool IsWithinSession()
{
datetime now = TimeCurrent();
int hour = TimeHour(now);
int minute = TimeMinute(now);
int currentMinutes = hour 60 + minute;
int startMinutes = SessionStartHour 60;
int endMinutes = SessionEndHour 60;
if (startMinutes < endMinutes)
return (currentMinutes >= startMinutes && currentMinutes < endMinutes);
else // 跨夜时段
return (currentMinutes >= startMinutes || currentMinutes < endMinutes);
}
//+------------------------------------------------------------------+
//| 更新每日统计数据 |
//+------------------------------------------------------------------+
void UpdateDailyStats()
{
static int lastDay = -1;
int currentDay = TimeDayOfYear(TimeCurrent());
if (currentDay != lastDay)
{
//--- 重置每日计数器
g_tradesToday = 0;
g_dailyProfit = 0;
g_consecutiveLosses = 0;
lastDay = currentDay;
Print("每日重置。新交易日开始。");
}
//--- 从已平仓订单更新每日利润
g_dailyProfit = GetDailyClosedProfit();
//--- 检查每日利润目标
if (DailyProfitPct > 0)
{
double balance = AccountBalance();
double dailyTarget = balance DailyProfitPct / 100.0;
if (g_dailyProfit >= dailyTarget)
{
Print("每日利润目标达成。停止交易。");
return;
}
}
//--- 检查每日止损
if (DailyStopPct > 0)
{
double balance = AccountBalance();
double dailyStop = balance DailyStopPct / 100.0;
if (g_dailyProfit <= -dailyStop)
{
Print("每日止损触发。停止交易。");
return;
}
}
}
//+------------------------------------------------------------------+
//| 获取每日已平仓利润 |
//+------------------------------------------------------------------+
double GetDailyClosedProfit()
{
double profit = 0;
datetime startOfDay = TimeCurrent() - (TimeCurrent() % 86400);
int orders = OrdersHistoryTotal();
for (int i = orders - 1; i >= 0; i--)
{
if (!OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)) continue;
if (OrderMagicNumber() != g_magic) continue;
if (OrderSymbol() != Symbol()) continue;
if (OrderCloseTime() < startOfDay) break;
profit += OrderProfit() + OrderSwap() + OrderCommission();
}
return profit;
}
//+------------------------------------------------------------------+
//| 检查风险保护限制 |
//+------------------------------------------------------------------+
bool CheckRiskProtection()
{
double equity = AccountEquity();
double balance = AccountBalance();
//--- 最大浮动亏损检查
if (MaxFloatingLossPct > 0)
{
double floatingLoss = (balance - equity) / balance 100.0;
if (floatingLoss > MaxFloatingLossPct)
{
Print("最大浮动亏损触发 (", floatingLoss, "%)。平仓所有订单。");
CloseAllOrders();
return false;
}
}
//--- 最大网格回撤检查
if (MaxGridDrawdownUSD > 0)
{
double currentDrawdown = 0;
for (int i = OrdersTotal() - 1; i >= 0; i--)
{
if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
if (OrderMagicNumber() != g_magic) continue;
if (OrderSymbol() != Symbol()) continue;
currentDrawdown += OrderProfit();
}
if (currentDrawdown < 0 && MathAbs(currentDrawdown) > MaxGridDrawdownUSD)
{
Print("最大网格回撤触发 (", MathAbs(currentDrawdown), " USD)。平仓所有订单。");
CloseAllOrders();
return false;
}
}
return true;
}
//+------------------------------------------------------------------+
//| 检查保证金水平 |
//+------------------------------------------------------------------+
bool CheckMarginLevel()
{
if (MinMarginLevel > 0)
{
double marginLevel = AccountFreeMarginCheck(Symbol(), OP_BUY, 0.01);
if (marginLevel <= 0 || marginLevel < MinMarginLevel)
{
Print("保证金水平过低 (", marginLevel, "%)。跳过新订单。");
return false;
}
}
return true;
}
//+------------------------------------------------------------------+
//| 更新支撑/阻力水平 |
//+------------------------------------------------------------------+
void UpdateSupportResistance()
{
//--- 清理旧的S/R线
if (ShowSRLines)
{
ObjectsDeleteAll(0, "SR_");
}
int scanBars = SR_ScanBars;
if (scanBars > Bars) scanBars = Bars - 1;
//--- 寻找枢轴点
int srCount = 0;
for (int i = SR_LeftRightBars; i < scanBars - SR_LeftRightBars; i++)
{
double high = High[i];
double low = Low[i];
//--- 检查是否为阻力峰
bool isResistance = true;
for (int j = 1; j <= SR_LeftRightBars; j++)
{
if (High[i + j] > high || High[i - j] > high)
{
isResistance = false;
break;
}
}
//--- 检查是否为支撑谷
bool isSupport = true;
for (int j = 1; j <= SR_LeftRightBars; j++)
{
if (Low[i + j] < low || Low[i - j] < low)
{
isSupport = false;
break;
}
}
if (isSupport || isResistance)
{
double price = isSupport ? low : high;
double zoneSize = SR_ZoneHeightPips g_point;
//--- 添加到相应数组
if (isSupport)
{
ArrayResize(g_supportLevels, srCount + 1);
g_supportLevels[srCount] = price;
ArrayResize(g_srTimestamps, srCount + 1);
g_srTimestamps[srCount] = Time[i];
srCount++;
}
else if (isResistance)
{
ArrayResize(g_resistanceLevels, ArraySize(g_resistanceLevels) + 1);
g_resistanceLevels[ArraySize(g_resistanceLevels) - 1] = price;
}
//--- 在图表上绘制线条
if (ShowSRLines)
{
string objName = isSupport ? "SR_Support_" + DoubleToStr(i, 0) : "SR_Resistance_" + DoubleToStr(i, 0);
color lineColor = isSupport ? clrGreen : clrRed;
ObjectCreate(0, objName, OBJ_HLINE, 0, 0, price);
ObjectSet(0, objName, OBJPROP_COLOR, lineColor);
ObjectSet(0, objName, OBJPROP_STYLE, STYLE_DASH);
ObjectSet(0, objName, OBJPROP_WIDTH, 1);
}
}
}
}
//+------------------------------------------------------------------+
//| 统计EA的未平仓订单 |
//+------------------------------------------------------------------+
void CountOpenOrders(int &buyOrders, int &sellOrders, double &buyAvgPrice,
double &sellAvgPrice, double &buyProfit, double &sellProfit)
{
buyOrders = 0;
sellOrders = 0;
buyAvgPrice = 0;
sellAvgPrice = 0;
buyProfit = 0;
sellProfit = 0;
for (int i = OrdersTotal() - 1; i >= 0; i--)
{
if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
if (OrderMagicNumber() != g_magic) continue;
if (OrderSymbol() != Symbol()) continue;
if (OrderType() == OP_BUY)
{
buyOrders++;
buyAvgPrice += OrderOpenPrice();
buyProfit += OrderProfit() + OrderSwap() + OrderCommission();
}
else if (OrderType() == OP_SELL)
{
sellOrders++;
sellAvgPrice += OrderOpenPrice();
sellProfit += OrderProfit() + OrderSwap() + OrderCommission();
}
}
if (buyOrders > 0) buyAvgPrice /= buyOrders;
if (sellOrders > 0) sellAvgPrice /= sellOrders;
}
//+------------------------------------------------------------------+
//| 检查初始入场信号 |
//+------------------------------------------------------------------+
void CheckInitialEntry()
{
//--- 检查是否达到每日交易次数限制
if (g_tradesToday >= 1) return;
//--- 检查点差
if (MarketInfo(Symbol(), MODE_SPREAD) > MaxSpread)
{
return;
}
//--- 检查趋势过滤器
int trendSignal = 0;
if (UseTrendFilter)
{
trendSignal = GetTrendSignal();
if (trendSignal == 0) return;
}
//--- 检查RSI入场过滤器
int rsiSignal = 0;
if (UseRSI_Entry)
{
rsiSignal = GetRSISignal();
if (rsiSignal == 0) return;
}
//--- 最终入场信号:两个过滤器必须一致
int entrySignal = 0;
if (UseTrendFilter && UseRSI_Entry)
{
if (trendSignal == 1 && rsiSignal == 1) entrySignal = 1;
else if (trendSignal == -1 && rsiSignal == -1) entrySignal = -1;
}
else if (UseTrendFilter)
{
entrySignal = trendSignal;
}
else if (UseRSI_Entry)
{
entrySignal = rsiSignal;
}
if (entrySignal == 0) return;
//--- 计算手数
double lotSize = CalculateLotSize();
//--- 入场交易
if (entrySignal == 1)
{
OpenBuyOrder(lotSize);
g_tradesToday++;
Print("初始买入入场开启。手数: ", lotSize);
}
else if (entrySignal == -1)
{
OpenSellOrder(lotSize);
g_tradesToday++;
Print("初始卖出入场开启。手数: ", lotSize);
}
}
//+------------------------------------------------------------------+
//| 从H1时间框架获取趋势信号 |
//+------------------------------------------------------------------+
int GetTrendSignal()
{
double maValue = iMA(NULL, PERIOD_H1, TrendMAPeriod, 0, MODE_EMA, PRICE_CLOSE, 1);
double close = iClose(NULL, PERIOD_H1, 1);
if (close > maValue) return 1; // 看涨
if (close < maValue) return -1; // 看跌
return 0;
}
//+------------------------------------------------------------------+
//| 获取RSI信号 |
//+------------------------------------------------------------------+
int GetRSISignal()
{
double rsiValue = iRSI(NULL, EntryTF, RSI_Period, PRICE_CLOSE, 1);
if (rsiValue <= RSI_BuyTrigger) return 1; // 超卖 -> 买入
if (rsiValue >= RSI_SellTrigger) return -1; // 超买 -> 卖出
return 0;
}
//+------------------------------------------------------------------+
//| 基于风险百分比计算手数 |
//+------------------------------------------------------------------+
double CalculateLotSize()
{
double balance = AccountBalance();
double riskAmount = balance RiskPercent / 100.0;
double tickValue = MarketInfo(Symbol(), MODE_TICKVALUE);
double stopLossPips = 200 g_point; // 以价格计量的近似初始止损
double lotSize = riskAmount / (stopLossPips tickValue);
double minLot = MarketInfo(Symbol(), MODE_MINLOT);
double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
if (lotSize < minLot) lotSize = minLot;
if (lotSize > maxLot) lotSize = maxLot;
lotSize = NormalizeDouble(lotSize, 2);
return lotSize;
}
//+------------------------------------------------------------------+
//| 开启买入订单 |
//+------------------------------------------------------------------+
void OpenBuyOrder(double lotSize)
{
double price = Ask;
double sl = 0;
double tp = 0;
//--- 使用基于ATR的止损/止盈
double atr = iATR(NULL, EntryTF, 14, 1);
if (atr > 0)
{
sl = price - atr 1.5;
tp = price + atr 2.0;
}
int ticket = OrderSend(Symbol(), OP_BUY, lotSize, price, Slippage, sl, tp, CustomComment, g_magic, 0, clrGreen);
if (ticket <= 0)
Print("买入订单失败。错误: ", GetLastError());
}
//+------------------------------------------------------------------+
//| 开启卖出订单 |
//+------------------------------------------------------------------+
void OpenSellOrder(double lotSize)
{
double price = Bid;
double sl = 0;
double tp = 0;
//--- 使用基于ATR的止损/止盈
double atr = iATR(NULL, EntryTF, 14, 1);
if (atr > 0)
{
sl = price + atr 1.5;
tp = price - atr 2.0;
}
int ticket = OrderSend(Symbol(), OP_SELL, lotSize, price, Slippage, sl, tp, CustomComment, g_magic, 0, clrRed);
if (ticket <= 0)
Print("卖出订单失败。错误: ", GetLastError());
}
//+------------------------------------------------------------------+
//| 管理网格恢复 |
//+------------------------------------------------------------------+
void ManageGrid(int buyOrders, int sellOrders, double buyAvgPrice, double sellAvgPrice)
{
//--- 判断哪个方向处于亏损状态
bool buyInLoss = false;
bool sellInLoss = false;
if (buyOrders > 0)
{
double currentPrice = Ask;
if (currentPrice < buyAvgPrice) buyInLoss = true;
}
if (sellOrders > 0)
{
double currentPrice = Bid;
if (currentPrice > sellAvgPrice) sellInLoss = true;
}
//--- 检查是否需要添加网格订单
if (buyInLoss && buyOrders < MaxGridOrders)
{
//--- 检查S/R过滤器
if (UseSR_GridFilter && IsPriceNearResistance(Ask))
{
//--- 价格接近阻力位,延迟网格入场
return;
}
//--- 检查WPR过滤器
if (UseWPR_GridFilter)
{
double wpr = iWPR(NULL, EntryTF, WPR_Period, 0);
if (wpr > WPR_BuyTrigger) return;
}
//--- 检查MACD过滤器
if (UseMACD_GridFilter)
{
double macdMain = iMACD(NULL, EntryTF, MACD_Fast, MACD_Slow, MACD_Signal, PRICE_CLOSE, MODE_MAIN, 0);
double macdSignal = iMACD(NULL, EntryTF, MACD_Fast, MACD_Slow, MACD_Signal, PRICE_CLOSE, MODE_SIGNAL, 0);
if (macdMain < macdSignal) return; // 看跌动量,避免买入
}
//--- 添加网格买入订单
double lotSize = CalculateGridLotSize(buyOrders);
double stepPips = CalculateGridStep(buyOrders);
double price = Ask - stepPips g_point;
//--- 确保价格有效
if (price > 0)
{
OpenBuyOrder(lotSize);
Print("网格买入订单添加。手数: ", lotSize, " 价格: ", price);
}
}
if (sellInLoss && sellOrders < MaxGridOrders)
{
//--- 检查S/R过滤器
if (UseSR_GridFilter && IsPriceNearSupport(Bid))
{
//--- 价格接近支撑位,延迟网格入场
return;
}
//--- 检查WPR过滤器
if (UseWPR_GridFilter)
{
double wpr = iWPR(NULL, EntryTF, WPR_Period, 0);
if (wpr < WPR_SellTrigger) return;
}
//--- 检查MACD过滤器
if (UseMACD_GridFilter)
{
double macdMain = iMACD(NULL, EntryTF, MACD_Fast, MACD_Slow, MACD_Signal, PRICE_CLOSE, MODE_MAIN, 0);
double macdSignal = iMACD(NULL, EntryTF, MACD_Fast, MACD_Slow, MACD_Signal, PRICE_CLOSE, MODE_SIGNAL, 0);
if (macdMain > macdSignal) return; // 看涨动量,避免卖出
}
//--- 添加网格卖出订单
double lotSize = CalculateGridLotSize(sellOrders);
double stepPips = CalculateGridStep(sellOrders);
double price = Bid + stepPips g_point;
if (price > 0)
{
OpenSellOrder(lotSize);
Print("网格卖出订单添加。手数: ", lotSize, " 价格: ", price);
}
}
//--- 检查网格平仓条件
CheckGridClosure(buyOrders, sellOrders, buyAvgPrice, sellAvgPrice);
}
//+------------------------------------------------------------------+
//| 基于ATR计算网格步长 |
//+------------------------------------------------------------------+
double CalculateGridStep(int orderLevel)
{
double baseStep = GridStepPips g_point;
if (UseDynamicGridStep)
{
double atr = iATR(NULL, EntryTF, 14, 1);
if (atr > 0)
{
baseStep = atr GridATR_Multiplier;
}
}
//--- 每级应用距离乘数
double step = baseStep MathPow(GridDistanceMult, orderLevel);
return NormalizeDouble(step, Digits);
}
//+------------------------------------------------------------------+
//| 使用乘数计算网格手数 |
//+------------------------------------------------------------------+
double CalculateGridLotSize(int orderLevel)
{
double baseLot = CalculateLotSize();
double lotSize = baseLot MathPow(GridMultiplier, orderLevel);
double minLot = MarketInfo(Symbol(), MODE_MINLOT);
double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
if (lotSize < minLot) lotSize = minLot;
if (lotSize > maxLot) lotSize = maxLot;
return NormalizeDouble(lotSize, 2);
}
//+------------------------------------------------------------------+
//| 检查价格是否接近阻力水平 |
//+------------------------------------------------------------------+
bool IsPriceNearResistance(double price)
{
for (int i = 0; i < ArraySize(g_resistanceLevels); i++)
{
double zoneSize = SR_GridTolerancePips g_point;
if (MathAbs(price - g_resistanceLevels[i]) < zoneSize)
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| 检查价格是否接近支撑水平 |
//+------------------------------------------------------------------+
bool IsPriceNearSupport(double price)
{
for (int i = 0; i < ArraySize(g_supportLevels); i++)
{
double zoneSize = SR_GridTolerancePips g_point;
if (MathAbs(price - g_supportLevels[i]) < zoneSize)
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| 检查网格平仓条件 |
//+------------------------------------------------------------------+
void CheckGridClosure(int buyOrders, int sellOrders, double buyAvgPrice, double sellAvgPrice)
{
double targetPips = GridTargetProfit g_point;
//--- 检查买入网格利润
if (buyOrders > 0)
{
double currentPrice = Ask;
double profitPips = (currentPrice - buyAvgPrice) / g_point;
if (profitPips >= targetPips)
{
CloseAllOrders();
Print("买入网格目标达成。平仓所有订单。");
g_consecutiveLosses = 0;
}
}
//--- 检查卖出网格利润
if (sellOrders > 0)
{
double currentPrice = Bid;
double profitPips = (sellAvgPrice - currentPrice) / g_point;
if (profitPips >= targetPips)
{
CloseAllOrders();
Print("卖出网格目标达成。平仓所有订单。");
g_consecutiveLosses = 0;
}
}
}
//+------------------------------------------------------------------+
//| 检查网格止盈(替代方法) |
//+------------------------------------------------------------------+
void CheckGridTakeProfit(int buyOrders, int sellOrders, double buyAvgPrice,
double sellAvgPrice, double buyProfit, double sellProfit)
{
//--- 与CheckGridClosure类似,但使用美元利润
if (buyOrders > 0 && buyProfit > 0)
{
double balance = AccountBalance();
if (buyProfit / balance 100 > DailyProfitPct / 2)
{
CloseAllOrders();
Print("买入网格利润目标达成。平仓所有订单。");
}
}
if (sellOrders > 0 && sellProfit > 0)
{
double balance = AccountBalance();
if (sellProfit / balance 100 > DailyProfitPct / 2)
{
CloseAllOrders();
Print("卖出网格利润目标达成。平仓所有订单。");
}
}
}
//+------------------------------------------------------------------+
//| 管理未平仓订单的移动止损 |
//+------------------------------------------------------------------+
void ManageTrailingStops()
{
for (int i = OrdersTotal() - 1; i >= 0; i--)
{
if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
if (OrderMagicNumber() != g_magic) continue;
if (OrderSymbol() != Symbol()) continue;
double profitPips = 0;
double currentPrice = 0;
if (OrderType() == OP_BUY)
{
currentPrice = Bid;
profitPips = (currentPrice - OrderOpenPrice()) / g_point;
}
else if (OrderType() == OP_SELL)
{
currentPrice = Ask;
profitPips = (OrderOpenPrice() - currentPrice) / g_point;
}
else continue;
//--- 检查是否启动移动止损
if (profitPips >= GridTrailStartPips)
{
double newSL = 0;
double trailDist = GridTrailDistPips g_point;
if (OrderType() == OP_BUY)
{
newSL = currentPrice - trailDist;
}
else if (OrderType() == OP_SELL)
{
newSL = currentPrice + trailDist;
}
//--- 仅当新止损优于当前止损时修改
if (newSL > 0)
{
if (OrderType() == OP_BUY && newSL > OrderStopLoss())
{
ModifyStopLoss(OrderTicket(), newSL);
}
else if (OrderType() == OP_SELL && (newSL < OrderStopLoss() || OrderStopLoss() == 0))
{
ModifyStopLoss(OrderTicket(), newSL);
}
}
}
}
}
//+------------------------------------------------------------------+
//| 修改订单的止损 |
//+------------------------------------------------------------------+
void ModifyStopLoss(int ticket, double newSL)
{
if (!OrderSelect(ticket, SELECT_BY_TICKET)) return;
double tp = OrderTakeProfit();
bool result = OrderModify(ticket, OrderOpenPrice(), newSL, tp, 0, clrNONE);
if (result)
Print("订单 ", ticket, " 止损已修改为 ", newSL);
else
Print("修改止损失败。错误: ", GetLastError());
}
//+------------------------------------------------------------------+
//| 检查浮动亏损保护 |
//+------------------------------------------------------------------+
void CheckFloatingLoss()
{
double equity = AccountEquity();
double balance = AccountBalance();
double floatingLoss = (balance - equity) / balance 100.0;
if (floatingLoss > g_maxFloatingLoss)
g_maxFloatingLoss = floatingLoss;
if (MaxFloatingLossPct > 0 && floatingLoss > MaxFloatingLossPct)
{
Print("浮动亏损超过限制 (", floatingLoss, "%)。平仓所有订单。");
CloseAllOrders();
ActivateCooldown();
}
}
//+------------------------------------------------------------------+
//| 平仓该EA的所有订单 |
//+------------------------------------------------------------------+
void CloseAllOrders()
{
for (int i = OrdersTotal() - 1; i >= 0; i--)
{
if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
if (OrderMagicNumber() != g_magic) continue;
if (OrderSymbol() != Symbol()) continue;
int ticket = OrderTicket();
double price = (OrderType() == OP_BUY) ? Bid : Ask;
bool result = OrderClose(ticket, OrderLots(), price, Slippage, clrNONE);
if (result)
{
Print("订单 ", ticket, " 已平仓。");
}
else
{
Print("平仓订单 ", ticket, " 失败。错误: ", GetLastError());
}
}
}
//+------------------------------------------------------------------+
//| 激活冷却期 |
//+------------------------------------------------------------------+
void ActivateCooldown()
{
if (UseCooldown)
{
g_consecutiveLosses++;
if (g_consecutiveLosses >= MaxConsecLosses)
{
g_isCooldown = true;
g_cooldownEndTime = TimeCurrent() + CooldownBars PeriodSeconds(EntryTF);
Print("冷却期激活,持续 ", CooldownBars, " 根K线。");
}
}
}
//+------------------------------------------------------------------+
``本文首发于FXEAR.com,原创内容,未经授权禁止转载。*
免责声明: 外汇及差价合约以保证金方式交易,具有高风险,可能不适合所有投资者。所提供的专家顾问仅供教育和信息参考之用。过往表现不能保证未来结果。在使用本EA前,您应仔细考虑您的投资目标、经验水平和风险承受能力。切勿投入您无法承受损失的资金。作者和FXEAR.com对使用本软件造成的任何经济损失概不负责。在实盘部署前,请务必在模拟账户上充分测试。