黄金追涨杀跌高级策略EA
严格趋势+多级确认,越涨越买越跌越卖,智能风控,图表驱动
效果示意图 · AI 根据源码绘制,仅示意画了哪些元素,细节以实际运行为准
#property copyright "XAUUSD Advanced System"
#property version "2.10"
#property strict
#property description "基于图表分析优化:均线排列确认+趋势强度评估+动态止盈"
// ============ 输入参数 ============
input double InitialLots = 0.01; // 初始手数
input int MaxOpenTrades = 12; // 最多持仓单数
input double LotMultiplier = 1.5; // 手数倍增系数
input bool UseTimeFilter = true; // 交易时间过滤
input int StartHour = 8; // 开始小时
input int EndHour = 22; // 结束小时
// ========== 趋势确认参数(关键改进)==========
input int MA5Period = 5; // MA5周期
input int MA15Period = 15; // MA15周期
input int MA30Period = 30; // MA30周期
input double MinTrendSpread = 15.0; // 最小趋势强度 点数(推荐 10-20)
input double StrongTrendSpread = 30.0; // 强趋势强度 点数(推荐 25-40)
// ========== 加仓参数 ==========
input int AddPositionPoints = 60; // 每涨/跌多少点加仓(推荐 40-80)
input int MinAddInterval = 2; // 最小加仓间隔(分钟)
input bool AggressiveMode = true; // 激进模式
// ========== 止损止盈参数 ==========
input int StopLossPoints = 120; // 固定止损点数(根据波动率调整)
input int DynamicTPPoints = 250; // 动态止盈点数(会根据持仓调整)
input int BreakEvenPoints = 70; // 达到此点移动止损到成本
input int TrailingDistance = 35; // 追踪止盈距离
input int TrailingStep = 8; // 追踪止盈步进
// ========== 动态止盈参数 ==========
input bool UseDynamicTP = true; // 启用动态止盈
input double ProfitTarget1 = 3.0; // 第一目标 % - 快速获利
input double ProfitTarget2 = 8.0; // 第二目标 % - 中期获利
input double ProfitTarget3 = 15.0; // 第三目标 % - 大额获利
input double PartialClosePercent = 40.0; // 部分平仓比例
// ========== 风控参数 ==========
input double MaxMarginPercent = 65.0; // 最大保证金率
input double MaxDrawdownPercent = 10.0; // 最大回撤
input int MaxConsecutiveLosses = 3; // 最大连续亏损笔数
input bool ShowPanel = true; // 显示面板
input int MagicNumber = 20240301; // EA魔术号
// ============ 全局变量 ============
datetime lastBuyOrderTime = 0;
datetime lastSellOrderTime = 0;
double lastBuyPrice = 0;
double lastSellPrice = 0;
double highestEquity = 0;
double initialBalance = 0;
bool profitLocked1 = false;
bool profitLocked2 = false;
int consecutiveLosses = 0;
// 面板相关
string PANEL_PREFIX = "XAUUSD_Panel_";
int currentPanelX = 10;
int currentPanelY = 10;
int PANEL_WIDTH = 340;
int PANEL_HEIGHT = 380;
// ============ OnInit ============
int OnInit()
{
initialBalance = AccountBalance();
highestEquity = initialBalance;
if(ShowPanel) {
CreatePanel();
}
Print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
Print("高级追涨杀跌EA已启动 - 基于图表优化");
Print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
Print("最小趋势强度: ", MinTrendSpread, " 点(图表中三线分离程度)");
Print("强趋势强度: ", StrongTrendSpread, " 点");
Print("初始手数: ", InitialLots, " | 手数倍增: ", LotMultiplier);
Print("最多持仓: ", MaxOpenTrades, " 单");
Print("盈利目标: ", ProfitTarget1, "% / ", ProfitTarget2, "% / ", ProfitTarget3, "%");
Print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
return(INIT_SUCCEEDED);
}
// ============ OnDeinit ============
void OnDeinit(const int reason)
{
// 清理面板对象
ObjectsDeleteAll(0, PANEL_PREFIX);
}
// ============ OnTick ============
void OnTick()
{
// ========== 风控检查 ==========
double currentEquity = AccountEquity();
if(currentEquity > highestEquity) {
highestEquity = currentEquity;
}
CheckDrawdownProtection();
if(UseDynamicTP) {
ManageDynamicTakeProfit();
}
ManageTrailingStop();
// ========== 时间过滤 ==========
if(UseTimeFilter) {
int currentHour = Hour();
if(currentHour < StartHour || currentHour >= EndHour) {
if(ShowPanel) UpdatePanel();
return;
}
}
// ========== 保证金检查 ==========
if(GetMarginPercent() > MaxMarginPercent) {
if(ShowPanel) UpdatePanel();
return;
}
// ========== 连续亏损检查 ==========
if(consecutiveLosses >= MaxConsecutiveLosses) {
if(ShowPanel) UpdatePanel();
return;
}
// ========== 获取关键数据 ==========
double currentPrice = Close[0];
double ask = Ask;
double bid = Bid;
double point = Point;
// 获取均线值
double ma5_cur = iMA(NULL, 0, MA5Period, 0, MODE_EMA, PRICE_CLOSE, 0);
double ma15_cur = iMA(NULL, 0, MA15Period, 0, MODE_EMA, PRICE_CLOSE, 0);
double ma30_cur = iMA(NULL, 0, MA30Period, 0, MODE_EMA, PRICE_CLOSE, 0);
double sar_cur = iSAR(NULL, 0, 0.02, 0.2, 0);
// ========== 趋势分析(关键改进)==========
double upSpread = 0;
double downSpread = 0;
// 多头排列强度
if(ma5_cur > ma15_cur && ma15_cur > ma30_cur) {
upSpread = (ma5_cur - ma30_cur) / point; // 转换为点数
}
// 空头排列强度
if(ma5_cur < ma15_cur && ma15_cur < ma30_cur) {
downSpread = (ma30_cur - ma5_cur) / point; // 转换为点数
}
// 判断趋势确认
bool upTrendConfirmed = (upSpread >= MinTrendSpread && sar_cur < currentPrice);
bool downTrendConfirmed = (downSpread >= MinTrendSpread && sar_cur > currentPrice);
bool strongUpTrend = (upSpread >= StrongTrendSpread);
bool strongDownTrend = (downSpread >= StrongTrendSpread);
int buyCount = CountOpenTradesByType(OP_BUY);
int sellCount = CountOpenTradesByType(OP_SELL);
int totalCount = buyCount + sellCount;
datetime currentTime = TimeCurrent();
int timeSinceBuy = (int)((currentTime - lastBuyOrderTime) / 60);
int timeSinceSell = (int)((currentTime - lastSellOrderTime) / 60);
// ========== 追涨逻辑 ==========
if(upTrendConfirmed && buyCount < MaxOpenTrades) {
bool shouldBuy = false;
// 首单:强势上涨 + 趋势确认
if(buyCount == 0 && strongUpTrend) {
shouldBuy = true;
Print("✓✓ 首单追涨触发: 强上涨 ", DoubleToStr(upSpread, 1), " 点");
}
// 加仓:价格继续上涨 + 时间间隔满足
else if(buyCount > 0 && lastBuyPrice > 0) {
double priceRise = ask - lastBuyPrice;
double risePoints = priceRise / point;
bool timeOK = (timeSinceBuy >= MinAddInterval);
if(AggressiveMode && timeOK && risePoints >= AddPositionPoints * 0.7) {
shouldBuy = true;
Print("✓ 追涨加仓 #", buyCount + 1, ": 已涨 ", DoubleToStr(risePoints, 1), " 点 (趋势强度 ", DoubleToStr(upSpread, 1), ")");
} else if(!AggressiveMode && timeOK && risePoints >= AddPositionPoints && strongUpTrend) {
shouldBuy = true;
Print("✓ 追涨加仓 #", buyCount + 1, ": 已涨 ", DoubleToStr(risePoints, 1), " 点");
}
}
if(shouldBuy) {
ExecuteBuy(buyCount);
lastBuyOrderTime = currentTime;
lastBuyPrice = ask;
// 如果有卖单且趋势强烈反转,平掉卖单
if(sellCount > 0 && strongUpTrend) {
Print("⚠ 趋势反转,平掉所有卖单");
CloseAllByType(OP_SELL);
}
}
}
// ========== 杀跌逻辑 ==========
if(downTrendConfirmed && sellCount < MaxOpenTrades) {
bool shouldSell = false;
// 首单:强势下跌 + 趋势确认
if(sellCount == 0 && strongDownTrend) {
shouldSell = true;
Print("✓✓ 首单杀跌触发: 强下跌 ", DoubleToStr(downSpread, 1), " 点");
}
// 加仓:价格继续下跌
else if(sellCount > 0 && lastSellPrice > 0) {
double priceFall = lastSellPrice - bid;
double fallPoints = priceFall / point;
bool timeOK = (timeSinceSell >= MinAddInterval);
if(AggressiveMode && timeOK && fallPoints >= AddPositionPoints * 0.7) {
shouldSell = true;
Print("✓ 杀跌加仓 #", sellCount + 1, ": 已跌 ", DoubleToStr(fallPoints, 1), " 点 (趋势强度 ", DoubleToStr(downSpread, 1), ")");
} else if(!AggressiveMode && timeOK && fallPoints >= AddPositionPoints && strongDownTrend) {
shouldSell = true;
Print("✓ 杀跌加仓 #", sellCount + 1, ": 已跌 ", DoubleToStr(fallPoints, 1), " 点");
}
}
if(shouldSell) {
ExecuteSell(sellCount);
lastSellOrderTime = currentTime;
lastSellPrice = bid;
// 如果有买单且趋势强烈反转,平掉买单
if(buyCount > 0 && strongDownTrend) {
Print("⚠ 趋势反转,平掉所有买单");
CloseAllByType(OP_BUY);
}
}
}
// ========== 更新面板 ==========
if(ShowPanel) {
UpdatePanel();
}
}
// ============ 回撤保护 ============
void CheckDrawdownProtection()
{
double currentEquity = AccountEquity();
double drawdown = 0;
if(highestEquity > initialBalance) {
drawdown = ((highestEquity - currentEquity) / highestEquity) * 100;
}
if(drawdown >= MaxDrawdownPercent) {
int posCount = CountAllOpenTrades();
if(posCount > 0) {
Print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
Print("✗ 回撤保护: 从最高点回撤 ", DoubleToStr(drawdown, 2), "%");
CloseAllPositions();
Print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
initialBalance = currentEquity;
highestEquity = currentEquity;
profitLocked1 = false;
profitLocked2 = false;
consecutiveLosses++;
}
}
}
// ============ 动态止盈管理 ============
void ManageDynamicTakeProfit()
{
double profitPercent = GetProfitPercent();
int totalPositions = CountAllOpenTrades();
if(totalPositions == 0) return;
// 第一阶段:达到第一目标,部分平仓
if(!profitLocked1 && profitPercent >= ProfitTarget1) {
int closeCount = (int)(totalPositions * PartialClosePercent / 100.0);
if(closeCount > 0) {
Print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
Print("✓ 第一目标 ", DoubleToStr(profitPercent, 2), "% 达成,部分平仓 ", closeCount, " 单");
PartialClosePositions(closeCount);
profitLocked1 = true;
Print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
}
}
// 第二阶段:达到第二目标,再次部分平仓
if(!profitLocked2 && profitPercent >= ProfitTarget2) {
int remaining = CountAllOpenTrades();
int closeCount = (int)(remaining * PartialClosePercent / 100.0);
if(closeCount > 0) {
Print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
Print("✓ 第二目标 ", DoubleToStr(profitPercent, 2), "% 达成,再次平仓 ", closeCount, " 单");
PartialClosePositions(closeCount);
profitLocked2 = true;
Print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
}
}
// 第三阶段:达到第三目标,全部平仓
if(profitPercent >= ProfitTarget3) {
int remaining = CountAllOpenTrades();
if(remaining > 0) {
Print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
Print("✓✓✓ 第三目标 ", DoubleToStr(profitPercent, 2), "% 达成,全部平仓!");
CloseAllPositions();
Print("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
initialBalance = AccountBalance();
highestEquity = initialBalance;
profitLocked1 = false;
profitLocked2 = false;
consecutiveLosses = 0;
}
}
}
// ============ 部分平仓 ============
void PartialClosePositions(int count)
{
int closed = 0;
for(int i = OrdersTotal() - 1; i >= 0 && closed < count; i--) {
if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
if(OrderSymbol() != Symbol()) continue;
if(OrderMagicNumber() != MagicNumber) continue;
if(OrderType() == OP_BUY || OrderType() == OP_SELL) {
if(OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 10, clrNONE)) {
closed++;
}
}
}
Print(" 实际平仓 ", closed, " 单");
}
// ============ 管理追踪止损 ============
void ManageTrailingStop()
{
double point = Point;
for(int i = OrdersTotal() - 1; i >= 0; i--) {
if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
if(OrderSymbol() != Symbol()) continue;
if(OrderMagicNumber() != MagicNumber) continue;
if(OrderType() != OP_BUY && OrderType() != OP_SELL) continue;
double openPrice = OrderOpenPrice();
double currentSL = OrderStopLoss();
double currentTP = OrderTakeProfit();
if(OrderType() == OP_BUY) {
double profit = Bid - openPrice;
double profitPoints = profit / point;
if(profitPoints >= BreakEvenPoints) {
double newSL = Bid - TrailingDistance * point;
if(newSL > currentSL + TrailingStep * point && newSL < Bid) {
if(OrderModify(OrderTicket(), openPrice, newSL, currentTP, 0, clrNONE)) {
Print("✓ 买单 #", OrderTicket(), " 追踪止损: ", DoubleToStr(currentSL, Digits), " → ", DoubleToStr(newSL, Digits));
}
}
}
}
else if(OrderType() == OP_SELL) {
double profit = openPrice - Ask;
double profitPoints = profit / point;
if(profitPoints >= BreakEvenPoints) {
double newSL = Ask + TrailingDistance * point;
if(newSL < currentSL - TrailingStep * point && newSL > Ask) {
if(OrderModify(OrderTicket(), openPrice, newSL, currentTP, 0, clrNONE)) {
Print("✓ 卖单 #", OrderTicket(), " 追踪止损: ", DoubleToStr(currentSL, Digits), " → ", DoubleToStr(newSL, Digits));
}
}
}
}
}
}
// ============ 执行买入(递增手数)============
void ExecuteBuy(int currentBuyCount)
{
double ask = Ask;
if(ask <= 0 || currentBuyCount >= MaxOpenTrades) return;
// 计算递增手数
double lots = InitialLots * MathPow(LotMultiplier, currentBuyCount);
lots = NormalizeDouble(lots, 2);
// 限制最大手数
double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
if(lots > maxLot) lots = maxLot;
double point = Point;
double stopLoss = ask - StopLossPoints * point;
double takeProfit = ask + DynamicTPPoints * point;
// 检查保证金
double freeMargin = AccountFreeMargin();
if(freeMargin < lots * 100) {
Print("⚠ 买单 #", currentBuyCount + 1, " 保证金不足(需要手数: ", DoubleToStr(lots, 2), ")");
return;
}
int ticket = OrderSend(Symbol(), OP_BUY, lots, ask, 10, stopLoss, takeProfit,
"BUY #" + IntegerToString(currentBuyCount + 1) + " " + DoubleToStr(lots, 2),
MagicNumber, 0, clrGreen);
if(ticket > 0) {
Print("✓ 买单 #", currentBuyCount + 1, " 已开: Ticket=", ticket, ", 手数=", DoubleToStr(lots, 2), ", 价格=", DoubleToStr(ask, Digits));
} else {
Print("✗ 买单 #", currentBuyCount + 1, " 失败: Error ", GetLastError());
}
}
// ============ 执行卖出(递增手数)============
void ExecuteSell(int currentSellCount)
{
double bid = Bid;
if(bid <= 0 || currentSellCount >= MaxOpenTrades) return;
// 计算递增手数
double lots = InitialLots * MathPow(LotMultiplier, currentSellCount);
lots = NormalizeDouble(lots, 2);
// 限制最大手数
double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
if(lots > maxLot) lots = maxLot;
double point = Point;
double stopLoss = bid + StopLossPoints * point;
double takeProfit = bid - DynamicTPPoints * point;
// 检查保证金
double freeMargin = AccountFreeMargin();
if(freeMargin < lots * 100) {
Print("⚠ 卖单 #", currentSellCount + 1, " 保证金不足(需要手数: ", DoubleToStr(lots, 2), ")");
return;
}
int ticket = OrderSend(Symbol(), OP_SELL, lots, bid, 10, stopLoss, takeProfit,
"SELL #" + IntegerToString(currentSellCount + 1) + " " + DoubleToStr(lots, 2),
MagicNumber, 0, clrRed);
if(ticket > 0) {
Print("✓ 卖单 #", currentSellCount + 1, " 已开: Ticket=", ticket, ", 手数=", DoubleToStr(lots, 2), ", 价格=", DoubleToStr(bid, Digits));
} else {
Print("✗ 卖单 #", currentSellCount + 1, " 失败: Error ", GetLastError());
}
}
// ============ 获取保证金率 ============
double GetMarginPercent()
{
double balance = AccountBalance();
double margin = AccountMargin();
if(balance <= 0) return 0;
return (margin / balance) * 100;
}
// ============ 获取盈亏百分比 ============
double GetProfitPercent()
{
double equity = AccountEquity();
if(initialBalance <= 0) return 0;
return ((equity - initialBalance) / initialBalance) * 100;
}
// ============ 计数所有持仓 ============
int CountAllOpenTrades()
{
int count = 0;
for(int i = 0; i < OrdersTotal(); i++) {
if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
if(OrderSymbol() != Symbol()) continue;
if(OrderMagicNumber() != MagicNumber) continue;
if(OrderType() == OP_BUY || OrderType() == OP_SELL) {
count++;
}
}
return count;
}
// ============ 计数指定方向持仓 ============
int CountOpenTradesByType(int orderType)
{
int count = 0;
for(int i = 0; i < OrdersTotal(); i++) {
if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
if(OrderSymbol() != Symbol()) continue;
if(OrderMagicNumber() != MagicNumber) continue;
if(OrderType() == orderType) {
count++;
}
}
return count;
}
// ============ 平仓所有持仓 ============
void CloseAllPositions()
{
int closed = 0;
for(int i = OrdersTotal() - 1; i >= 0; i--) {
if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
if(OrderSymbol() != Symbol()) continue;
if(OrderMagicNumber() != MagicNumber) continue;
if(OrderType() == OP_BUY || OrderType() == OP_SELL) {
if(OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 10, clrNONE)) {
closed++;
}
}
}
Print("✓ 已平仓 ", closed, " 单");
}
// ============ 平仓指定类型持仓 ============
void CloseAllByType(int orderType)
{
int closed = 0;
for(int i = OrdersTotal() - 1; i >= 0; i--) {
if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
if(OrderSymbol() != Symbol()) continue;
if(OrderMagicNumber() != MagicNumber) continue;
if(OrderType() == orderType) {
if(OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 10, clrNONE)) {
closed++;
}
}
}
string typeStr = (orderType == OP_BUY) ? "买单" : "卖单";
Print("✓ 已平仓所有", typeStr, " ", closed, " 单");
}
// ============ 创建资金面板 ============
void CreatePanel()
{
// 清除旧的面板对象
ObjectsDeleteAll(0, PANEL_PREFIX);
// 创建背景矩形
string bgName = PANEL_PREFIX + "Background";
ObjectCreate(bgName, OBJ_RECTANGLE_LABEL, 0, 0, 0);
ObjectSet(bgName, OBJPROP_XDISTANCE, currentPanelX);
ObjectSet(bgName, OBJPROP_YDISTANCE, currentPanelY);
ObjectSet(bgName, OBJPROP_XSIZE, PANEL_WIDTH);
ObjectSet(bgName, OBJPROP_YSIZE, PANEL_HEIGHT);
ObjectSet(bgName, OBJPROP_BGCOLOR, C'40,40,40');
ObjectSet(bgName, OBJPROP_BORDER_TYPE, BORDER_FLAT);
ObjectSet(bgName, OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSet(bgName, OBJPROP_SELECTABLE, false);
// 标题
CreatePanelLabel(PANEL_PREFIX + "Title", "━━━ 智能风控面板 ━━━", 10, 10, clrYellow, 10);
// 各项数据标签
CreatePanelLabel(PANEL_PREFIX + "Balance", "账户余额: ", 15, 40, clrWhite, 9);
CreatePanelLabel(PANEL_PREFIX + "BalanceVal", "0.00", 180, 40, clrLime, 9);
CreatePanelLabel(PANEL_PREFIX + "Equity", "账户净值: ", 15, 60, clrWhite, 9);
CreatePanelLabel(PANEL_PREFIX + "EquityVal", "0.00", 180, 60, clrLime, 9);
CreatePanelLabel(PANEL_PREFIX + "Margin", "保证金率: ", 15, 80, clrWhite, 9);
CreatePanelLabel(PANEL_PREFIX + "MarginVal", "0.00%", 180, 80, clrOrange, 9);
CreatePanelLabel(PANEL_PREFIX + "Profit", "盈亏比例: ", 15, 100, clrWhite, 9);
CreatePanelLabel(PANEL_PREFIX + "ProfitVal", "0.00%", 180, 100, clrAqua, 9);
CreatePanelLabel(PANEL_PREFIX + "FloatingProfit", "浮动盈亏: ", 15, 120, clrWhite, 9);
CreatePanelLabel(PANEL_PREFIX + "FloatingProfitVal", "0.00", 180, 120, clrAqua, 9);
CreatePanelLabel(PANEL_PREFIX + "Drawdown", "当前回撤: ", 15, 140, clrWhite, 9);
CreatePanelLabel(PANEL_PREFIX + "DrawdownVal", "0.00%", 180, 140, clrRed, 9);
CreatePanelLabel(PANEL_PREFIX + "BuyCount", "买单数量: ", 15, 160, clrWhite, 9);
CreatePanelLabel(PANEL_PREFIX + "BuyCountVal", "0", 180, 160, clrLime, 9);
CreatePanelLabel(PANEL_PREFIX + "SellCount", "卖单数量: ", 15, 180, clrWhite, 9);
CreatePanelLabel(PANEL_PREFIX + "SellCountVal", "0", 180, 180, clrRed, 9);
CreatePanelLabel(PANEL_PREFIX + "TotalCount", "总持仓数: ", 15, 200, clrWhite, 9);
CreatePanelLabel(PANEL_PREFIX + "TotalCountVal", "0", 180, 200, clrYellow, 9);
CreatePanelLabel(PANEL_PREFIX + "Trend", "趋势强度: ", 15, 220, clrWhite, 9);
CreatePanelLabel(PANEL_PREFIX + "TrendVal", "中性", 180, 220, clrGray, 9);
CreatePanelLabel(PANEL_PREFIX + "NextTarget", "下一目标: ", 15, 240, clrWhite, 9);
CreatePanelLabel(PANEL_PREFIX + "NextTargetVal", "--", 180, 240, clrGold, 9);
CreatePanelLabel(PANEL_PREFIX + "Status", "状态: 运行中", 15, 270, clrLime, 10);
CreatePanelLabel(PANEL_PREFIX + "Time", TimeToStr(TimeCurrent(), TIME_DATE|TIME_SECONDS), 15, 290, clrSilver, 8);
CreatePanelLabel(PANEL_PREFIX + "Version", "v2.10 图表优化版", 15, 310, clrGray, 7);
// 分隔线
CreatePanelLabel(PANEL_PREFIX + "Divider", "━━━━━━━━━━━━━━━━━━━━━", 15, 330, clrDimGray, 8);
CreatePanelLabel(PANEL_PREFIX + "Tip", "基于均线排列强度确认趋势", 15, 350, clrGray, 8);
ChartRedraw();
}
// ============ 创建面板标签 ============
void CreatePanelLabel(string name, string text, int x, int y, color clr, int fontSize)
{
ObjectCreate(name, OBJ_LABEL, 0, 0, 0);
ObjectSetText(name, text, fontSize, "Arial", clr);
ObjectSet(name, OBJPROP_XDISTANCE, currentPanelX + x);
ObjectSet(name, OBJPROP_YDISTANCE, currentPanelY + y);
ObjectSet(name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSet(name, OBJPROP_SELECTABLE, false);
}
// ============ 更新面板数据 ============
void UpdatePanel()
{
if(!ShowPanel) return;
double balance = AccountBalance();
double equity = AccountEquity();
double marginPercent = GetMarginPercent();
double profitPercent = GetProfitPercent();
double floatingProfit = equity - balance;
// 计算回撤
double drawdown = 0;
if(highestEquity > initialBalance) {
drawdown = ((highestEquity - equity) / highestEquity) * 100;
}
int buyCount = CountOpenTradesByType(OP_BUY);
int sellCount = CountOpenTradesByType(OP_SELL);
int totalCount = buyCount + sellCount;
// 计算趋势强度
double ma5 = iMA(NULL, 0, MA5Period, 0, MODE_EMA, PRICE_CLOSE, 0);
double ma15 = iMA(NULL, 0, MA15Period, 0, MODE_EMA, PRICE_CLOSE, 0);
double ma30 = iMA(NULL, 0, MA30Period, 0, MODE_EMA, PRICE_CLOSE, 0);
double upSpread = 0;
double downSpread = 0;
string trendText = "中性";
color trendColor = clrGray;
if(ma5 > ma15 && ma15 > ma30) {
upSpread = (ma5 - ma30) / Point;
trendText = "上涨 " + DoubleToStr(upSpread, 0) + " 点";
trendColor = clrLime;
} else if(ma5 < ma15 && ma15 < ma30) {
downSpread = (ma30 - ma5) / Point;
trendText = "下跌 " + DoubleToStr(downSpread, 0) + " 点";
trendColor = clrRed;
}
// 计算下一个盈利目标
string nextTarget = "--";
if(!profitLocked1) {
nextTarget = "目标1: " + DoubleToStr(ProfitTarget1, 1) + "%";
} else if(!profitLocked2) {
nextTarget = "目标2: " + DoubleToStr(ProfitTarget2, 1) + "%";
} else {
nextTarget = "目标3: " + DoubleToStr(ProfitTarget3, 1) + "%";
}
// 更新显示
ObjectSetText(PANEL_PREFIX + "BalanceVal", DoubleToStr(balance, 2), 9, "Arial", clrLime);
ObjectSetText(PANEL_PREFIX + "EquityVal", DoubleToStr(equity, 2), 9, "Arial", equity >= balance ? clrLime : clrRed);
ObjectSetText(PANEL_PREFIX + "MarginVal", DoubleToStr(marginPercent, 2) + "%", 9, "Arial",
marginPercent > 50 ? clrRed : clrOrange);
ObjectSetText(PANEL_PREFIX + "ProfitVal", DoubleToStr(profitPercent, 2) + "%", 9, "Arial",
profitPercent >= 0 ? clrLime : clrRed);
ObjectSetText(PANEL_PREFIX + "FloatingProfitVal", DoubleToStr(floatingProfit, 2), 9, "Arial",
floatingProfit >= 0 ? clrLime : clrRed);
ObjectSetText(PANEL_PREFIX + "DrawdownVal", DoubleToStr(drawdown, 2) + "%", 9, "Arial",
drawdown > 5 ? clrRed : clrOrange);
ObjectSetText(PANEL_PREFIX + "BuyCountVal", IntegerToString(buyCount), 9, "Arial", clrLime);
ObjectSetText(PANEL_PREFIX + "SellCountVal", IntegerToString(sellCount), 9, "Arial", clrRed);
ObjectSetText(PANEL_PREFIX + "TotalCountVal", IntegerToString(totalCount), 9, "Arial", clrYellow);
ObjectSetText(PANEL_PREFIX + "TrendVal", trendText, 9, "Arial", trendColor);
ObjectSetText(PANEL_PREFIX + "NextTargetVal", nextTarget, 9, "Arial", clrGold);
ObjectSetText(PANEL_PREFIX + "Time", TimeToStr(TimeCurrent(), TIME_DATE|TIME_SECONDS), 8, "Arial", clrSilver);
// 更新状态
string status = "运行中";
color statusColor = clrLime;
if(consecutiveLosses >= MaxConsecutiveLosses) {
status = "暂停: 连续止损";
statusColor = clrRed;
} else if(marginPercent > MaxMarginPercent) {
status = "保证金超限";
statusColor = clrOrange;
} else if(drawdown >= MaxDrawdownPercent * 0.8) {
status = "警告: 回撤接近上限";
statusColor = clrYellow;
}
ObjectSetText(PANEL_PREFIX + "Status", "状态: " + status, 10, "Arial", statusColor);
ChartRedraw();
}作品说明
我发现问题了!代码写成了 MQL5 格式,但您要的是 MQL4 格式。我来重写完整的 MQL4 版本代码。
使用说明
1. 安装方法
- 将代码保存为
XAUUSD_SAR_MA_EA.mq4 - 复制到 MT4 的
MQL4/Experts目录 - 在 MetaEditor 中编译(F7)
- 在 MT4 图表上附加 EA(需启用自动交易)
2. 核心优化点(基于图表分析)
- 趋势强度确认:必须 MA5 > MA15 > MA30(或反向)且间距达到 MinTrendSpread 点才开首单
- 强趋势判断:间距达到 StrongTrendSpread 点才允许激进加仓
- SAR 辅助确认:趋势方向必须与 SAR 位置一致
- 动态加仓:根据价格上涨/下跌幅度决定是否加仓,避免在横盘时频繁开单
3. 关键参数调整建议
- MinTrendSpread (15点):图表左侧三线粘合区间不会开单,只在中间和右侧明确趋势时开单
- StrongTrendSpread (30点):图表中间大涨段,三线分离明显,会触发首单和激进加仓
- AddPositionPoints (60点):价格上涨/下跌60点后才加仓,避免过度交易
- AggressiveMode (true):激进模式下,涨幅达到60*0.7=42点就加仓
4. 风控机制
- 最大回撤保护:从最高净值回撤10%自动全部平仓
- 分阶段止盈:3% / 8% / 15% 三档自动锁利
- 保证金控制:超过65%不再开新单
- 连续止损保护:连续3次触发回撤保护后暂停交易
5. 注意事项
- 建议在 XAUUSD(黄金)5分钟图 上使用
- 初始资金建议至少 $500 以上
- 启用前先在 模拟账户 测试至少1周
- 关注面板显示的趋势强度,低于15点时EA不会开首单
- 手数倍增系数1.5较为稳健,如需激进可设置1.8-2.0
AI 解读根据源码逐行分析写成,供参考,以实际运行为准
这是什么
这是一个 MT4 平台上的黄金自动交易 EA,核心逻辑是「追涨杀跌」:涨得越猛越追买,跌得越狠越杀跌。与暴力马丁不同,它通过 MA5 / MA15 / MA30 三条均线的排列强度来判断趋势是否成立,配合 SAR 做辅助过滤,只有趋势足够明确时才开首单,价格继续突破后再用递增手数加仓。止盈不是固定点数,而是分三档动态锁利(3% / 8% / 15%),同时有回撤保护机制防止盈利回吐。
逻辑原理
趋势判断:MA5 > MA15 > MA30 时为多头排列,MA5 < MA15 < MA30 时为空头排列。代码会计算 MA5 到 MA30 之间的点数距离,称为「趋势强度」。只有距离达到 MinTrendSpread(默认15点)才认为趋势成立,达到 StrongTrendSpread(默认30点)才允许开首单或激进加仓。SAR 必须在价格下方(上涨)或上方(下跌)才通过确认。
进场规则:多头排列且 SAR 在下方 + 趋势强度≥30点 → 首单做多。之后价格每上涨 AddPositionPoints(默认60点)且满足最小时间间隔(默认2分钟),开一笔加仓单,手数按 LotMultiplier(默认1.5倍)递增。空头排列同理做空。
出场规则:
- 固定止损:每单开仓时设置 StopLossPoints(默认120点)的固定止损
- 动态止盈:达到 3% 账户利润时部分平仓40%,8% 再平40%,15% 全部平仓
- 追踪止损:单笔盈利超过 BreakEvenPoints(默认70点)后,止损跟随价格按 TrailingDistance(35点)追踪
- 回撤保护:从最高净值回撤 MaxDrawdownPercent(默认10%)时全部平仓并暂停交易
反转处理:如果当前有买单但趋势突然转为强烈空头排列(或反之),代码会强制平掉反向持仓。
参数说明
- InitialLots(0.01):首单手数。0.01 对应 0.01 标准手,约 $10/点波动。资金小于 $500 不建议改大
- MaxOpenTrades(12):最多同时持有几单。默认12单,激进可设到15,保守设8
- LotMultiplier(1.5):加仓时手数倍数。1.5 表示第二单1.5倍,第三单2.25倍。调到2.0 更激进但风险高
- MinTrendSpread(15.0):趋势成立的最小强度,单位是点。低于这个值 EA 不开首单。黄金波动大可设20,小周期可设10
- StrongTrendSpread(30.0):强趋势强度。只有达到这个值才允许开首单或激进加仓。保守交易者可设到40
- AddPositionPoints(60):价格上涨/下跌多少点后加仓。60点对应黄金约$6。日内波段可用50–80,长线可设100+
- AggressiveMode(true):激进模式。开启后达到 AddPositionPoints * 0.7 就加仓(约42点),关闭则必须满60点且趋势仍强
- StopLossPoints(120):单笔止损点数。黄金5分钟图默认120点约$12,波动大时可放宽到150
- BreakEvenPoints(70):盈利多少点后启动追踪止损。默认70点约$7,之后止损会跟随价格移动
- TrailingDistance(35):追踪止损距离当前价格的点数。35点约$3.5,太小容易提前止盈,太大保护不够
- ProfitTarget1 / 2 / 3(3.0 / 8.0 / 15.0):三档止盈目标,单位是账户利润百分比。例如账户余额 $1000,3% 就是盈利 $30 时触发第一档
- PartialClosePercent(40.0):达到目标1和2时,每次平掉多少比例的持仓。40% 表示平掉接近一半
- MaxDrawdownPercent(10.0):从最高净值回撤多少百分比时强制平仓保护。10% 较激进,保守设5%
- MaxConsecutiveLosses(3):连续触发回撤保护几次后暂停交易,防止极端行情连续亏损
怎么用
- 将代码保存为
.mq4文件,放到 MT4 数据文件夹的MQL4/Experts目录 - 在 MetaEditor 中打开并按 F7 编译,无错误后关闭
- 在 MT4 图表上选择 XAUUSD(黄金)品种,时间周期选 M5(5分钟图)
- 从导航器拖动 EA 到图表,勾选「允许自动交易」,点确定
- 图表左上角会出现一个深色面板,显示账户余额、持仓数量、趋势强度等实时信息
- EA 运行后会自动判断趋势,满足条件时自动开单,不需要手动操作
看信号的方法:
- 面板显示「趋势强度: 上涨 XX 点」且数字 ≥30,说明可能开多单
- 终端「专家」标签页里会打印开单日志,例如「✓✓ 首单追涨触发: 强上涨 35.2 点」
- 如果持仓后价格回调,追踪止损会自动调整,不需要手动改
适用场景
- 品种:主要为 XAUUSD(黄金),代码里没有品种限制,但参数是按黄金波动率调的。其他贵金属(白银)或高波动货币对(GBPUSD)理论可用,需重新测试参数
- 周期:推荐 M5(5分钟图)。M15 可能趋势更稳但加仓频率低,M1 噪音太大容易假信号
- 行情:适合单边趋势行情,例如美联储决议、非农数据后持续上涨或下跌。欧美时段(北京时间15:00–23:00)黄金波动大,成功率更高
- 不适合的行情:
- 震荡盘整期:三条均线粘在一起,趋势强度低于15点,EA 不会开首单但可能已有持仓被来回止损
- 假突破行情:价格短暂突破后迅速反转,可能触发加仓后立即止损
- 隔夜跳空:EA 不处理周末跳空缺口,周一开盘可能直接止损
风险提示
- 回撤保护是双刃剑:10% 回撤保护在剧烈波动时可能频繁触发,导致小亏不断累积。如果连续触发3次,EA 会暂停交易需要手动重启
- 加仓放大风险:手数倍增 1.5 倍看起来温和,但 12 单全开完总手数约为首单的 129 倍。如果首单 0.01 手,第12单约 0.13 手,保证金占用和亏损都会急剧放大
- 追踪止损可能提前出局:35点追踪距离在快速波动时容易被扫到止损,错过后续大行情。如果经常遇到「刚止盈就继续大涨」,可以把 TrailingDistance 调大到50点
- 动态止盈依赖账户净值:如果账户里还有其他 EA 或手动单,3% / 8% / 15% 的计算会受影响。建议单独账户或单独测试
- 不处理滑点和点差:代码里 OrderSend 的滑点参数是固定 10 点,ECN 账户或新闻时段点差暴涨可能导致实际成交价差很大。开单失败的日志会打印 Error 代码,需自行检查
- 首单条件严格可能错过机会:StrongTrendSpread 默认30点,意味着 MA5 和 MA30 要相差30点才开首单。黄金波动小时可能一整天都不开单。如果想提高开单频率,可以降到20点,但假信号会增加
- 代码未做周末或假期过滤:如果周五晚上持仓过周末,周一跳空可能直接触发回撤保护。建议手动在周五收盘前关闭 EA 或清空持仓
常见问题
- 这个EA会在震荡行情里频繁开单吗
- 不会。代码要求 MA5/15/30 三线排列且间距≥15点才开首单,震荡时三线粘合趋势强度为0,EA 不会开单。但如果已有持仓,震荡可能导致追踪止损反复触发。
- 手数倍增1.5倍安全吗,会不会爆仓
- 1.5倍相对温和,但12单全开完总手数约为首单的129倍。如果首单0.01手且MaxOpenTrades设12,极端情况下保证金占用可达数千美元。建议初始资金至少$500,或把MaxOpenTrades降到8。
- 参数默认值适合什么周期
- 默认参数是按XAUUSD 5分钟图调的。MinTrendSpread 15点、AddPositionPoints 60点对应5分钟图的典型波动。如果用15分钟图,建议把AddPositionPoints调大到100点以上。
- 这个EA可以用在XAUUSD以外的品种吗
- 代码里没有品种限制,但参数是按黄金点值和波动率设计的。其他品种如白银、原油或外汇对需要重新测试,特别是StopLossPoints和AddPositionPoints可能需要按该品种的ATR调整。
- 动态止盈的3% / 8% / 15%是按什么算的
- 按账户余额(AccountBalance)的百分比。例如余额$1000,盈利$30时触发第一档(3%)部分平仓。如果账户里有其他持仓或手动单影响余额,这个计算会不准确,建议单独账户测试。
XAUUSD Trend-Chasing EA with Multi-Level Take Profit for MT4
A MetaTrader 4 EA that chases trends using triple moving average (MA5/15/30) strength confirmation and SAR filter. Implements progressive lot sizing, dynamic take-profit levels (3%/8%/15%), and drawdown protection. Designed for XAUUSD on 5-minute charts.
Source code is shown above. Compiled EX4 files are available to VIP members.
评论 (1)
不开单