多空双开总利润追踪止盈EA
账户级总盈亏追踪,ADX过滤+顺势逆势加仓+总利润保护,自动全平
MT5 真机运行截图 · 服务器把编译好的 EX5 挂到黄金 H1 图表上截的,你装上去看到的就是这个样子
#property copyright "XAUOF指标工坊"
#property version "2.00"
#property strict
#include <Trade\Trade.mqh>
// ========== 基础开仓参数 ==========
input group "=== 基础开仓设置 ==="
input double InitialLot = 0.01; // 初始手数
input int MagicNumber = 20241201; // 魔术号(区分不同EA)
input int Slippage = 30; // 滑点(点数)
// ========== 多空开仓控制 ==========
input group "=== 多空开仓控制 ==="
input bool AllowBuy = true; // 允许开多单
input bool AllowSell = true; // 允许开空单
input bool AllowHedge = true; // 允许多空双开(对冲)
// ========== 顺势加仓参数 ==========
input group "=== 顺势加仓设置 ==="
input bool EnableTrendAdd = true; // 启用顺势加仓
input double TrendAddDistance = 300; // 顺势加仓间距(点数)
input double TrendAddMultiplier = 1.5; // 顺势加仓倍数
input int MaxTrendAddCount = 3; // 顺势最多加仓次数
// ========== 逆势加仓参数 ==========
input group "=== 逆势加仓设置 ==="
input bool EnableCounterAdd = true; // 启用逆势加仓
input double CounterAddDistance = 500; // 逆势加仓间距(点数)
input double CounterAddMultiplier = 2.0; // 逆势加仓倍数
input int MaxCounterAddCount = 2; // 逆势最多加仓次数
// ========== ADX趋势过滤 ==========
input group "=== ADX趋势过滤 ==="
input bool UseAdxFilter = true; // 启用ADX过滤
input int AdxPeriod = 14; // ADX周期
input double AdxTrendLevel = 25.0; // ADX趋势强度阈值(>此值才开仓)
input double AdxWeakLevel = 20.0; // ADX弱势阈值(<此值停止加仓)
// ========== 总利润追踪止盈止损 ==========
input group "=== 总利润追踪设置 ==="
input bool EnableTotalTrailing = true; // 启用总利润追踪
input double TotalProfitTarget = 100.0; // 开始追踪的总盈利目标(美元)
input double TotalTrailingStop = 50.0; // 追踪止损回撤(美元,从最高盈利回撤此值全平)
input double TotalStopLoss = 200.0; // 总止损(美元,浮亏超过此值全平)
// ========== 面板显示 ==========
input group "=== 面板显示设置 ==="
input bool ShowPanel = true; // 显示信息面板
input int PanelX = 20; // 面板X坐标
input int PanelY = 30; // 面板Y坐标
input color PanelColor = clrWhite; // 面板文字颜色
// ========== 全局变量 ==========
CTrade trade;
int adxHandle = INVALID_HANDLE;
double adxBuffer[];
// 追踪状态
double maxProfit = 0; // 历史最高总盈利
bool isTrailing = false; // 是否正在追踪
struct PositionInfo {
ulong ticket;
int type; // 0=buy, 1=sell
double openPrice;
double lots;
int addCount; // 加仓次数
};
PositionInfo buyPositions[];
PositionInfo sellPositions[];
//+------------------------------------------------------------------+
//| 初始化 |
//+------------------------------------------------------------------+
int OnInit()
{
trade.SetExpertMagicNumber(MagicNumber);
trade.SetDeviationInPoints(Slippage);
trade.SetTypeFilling(ORDER_FILLING_IOC);
// 创建ADX句柄
if(UseAdxFilter) {
adxHandle = iADX(_Symbol, PERIOD_CURRENT, AdxPeriod);
if(adxHandle == INVALID_HANDLE) {
Print("ADX指标创建失败!");
return INIT_FAILED;
}
ArraySetAsSeries(adxBuffer, true);
}
// 创建面板
if(ShowPanel) CreatePanel();
// 重置追踪状态
maxProfit = 0;
isTrailing = false;
Print("多空双开总利润追踪EA启动成功");
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| 清理 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
if(adxHandle != INVALID_HANDLE) IndicatorRelease(adxHandle);
if(ShowPanel) DeletePanel();
}
//+------------------------------------------------------------------+
//| 主循环 |
//+------------------------------------------------------------------+
void OnTick()
{
// 更新持仓信息
UpdatePositions();
// 检查总盈亏追踪止盈止损(优先级最高)
if(EnableTotalTrailing) {
CheckTotalProfitTrailing();
}
// 检查ADX条件
bool adxOk = CheckAdx();
// 多单逻辑
if(AllowBuy) {
if(ArraySize(buyPositions) == 0 && adxOk) {
// 首次开多单
OpenPosition(ORDER_TYPE_BUY, InitialLot);
} else if(ArraySize(buyPositions) > 0) {
// 多单加仓逻辑
CheckAddPosition(ORDER_TYPE_BUY);
}
}
// 空单逻辑
if(AllowSell) {
if(ArraySize(sellPositions) == 0 && adxOk) {
// 首次开空单
OpenPosition(ORDER_TYPE_SELL, InitialLot);
} else if(ArraySize(sellPositions) > 0) {
// 空单加仓逻辑
CheckAddPosition(ORDER_TYPE_SELL);
}
}
// 更新面板
if(ShowPanel) UpdatePanel();
}
//+------------------------------------------------------------------+
//| 检查总利润追踪止盈止损 |
//+------------------------------------------------------------------+
void CheckTotalProfitTrailing()
{
double totalProfit = GetTotalProfit();
// 总止损:浮亏超过阈值,立即全平
if(totalProfit < 0 && MathAbs(totalProfit) >= TotalStopLoss) {
Print("触发总止损! 总浮亏: ", DoubleToString(totalProfit, 2), " 美元,全平所有持仓");
CloseAllPositions();
ResetTrailingState();
return;
}
// 更新最高盈利
if(totalProfit > maxProfit) {
maxProfit = totalProfit;
}
// 启动追踪:总盈利达到目标
if(!isTrailing && totalProfit >= TotalProfitTarget) {
isTrailing = true;
maxProfit = totalProfit;
Print("启动总利润追踪! 当前盈利: ", DoubleToString(totalProfit, 2), " 美元");
}
// 追踪止盈:盈利回撤超过阈值
if(isTrailing) {
double drawdown = maxProfit - totalProfit;
if(drawdown >= TotalTrailingStop) {
Print("触发追踪止盈! 最高盈利: ", DoubleToString(maxProfit, 2),
" 当前盈利: ", DoubleToString(totalProfit, 2),
" 回撤: ", DoubleToString(drawdown, 2), " 美元,全平所有持仓");
CloseAllPositions();
ResetTrailingState();
}
}
}
//+------------------------------------------------------------------+
//| 获取所有持仓总盈亏 |
//+------------------------------------------------------------------+
double GetTotalProfit()
{
double total = 0;
for(int i = 0; i < PositionsTotal(); i++) {
if(PositionGetTicket(i) <= 0) continue;
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
if(PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue;
total += PositionGetDouble(POSITION_PROFIT) + PositionGetDouble(POSITION_SWAP);
}
return total;
}
//+------------------------------------------------------------------+
//| 平掉所有持仓 |
//+------------------------------------------------------------------+
void CloseAllPositions()
{
for(int i = PositionsTotal() - 1; i >= 0; i--) {
ulong ticket = PositionGetTicket(i);
if(ticket <= 0) continue;
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
if(PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue;
if(!trade.PositionClose(ticket)) {
Print("平仓失败 票号: ", ticket, " 错误: ", trade.ResultRetcodeDescription());
} else {
Print("平仓成功 票号: ", ticket);
}
}
}
//+------------------------------------------------------------------+
//| 重置追踪状态 |
//+------------------------------------------------------------------+
void ResetTrailingState()
{
maxProfit = 0;
isTrailing = false;
}
//+------------------------------------------------------------------+
//| 检查ADX条件 |
//+------------------------------------------------------------------+
bool CheckAdx()
{
if(!UseAdxFilter) return true;
if(BarsCalculated(adxHandle) < 2) return false;
if(CopyBuffer(adxHandle, 0, 0, 2, adxBuffer) < 2) return false;
double adxNow = adxBuffer[0];
// ADX大于趋势阈值才允许开仓
return (adxNow > AdxTrendLevel);
}
//+------------------------------------------------------------------+
//| 检查加仓条件是否满足 |
//+------------------------------------------------------------------+
void CheckAddPosition(ENUM_ORDER_TYPE type)
{
double currentPrice = (type == ORDER_TYPE_BUY) ? SymbolInfoDouble(_Symbol, SYMBOL_ASK) : SymbolInfoDouble(_Symbol, SYMBOL_BID);
PositionInfo positions[];
if(type == ORDER_TYPE_BUY) {
ArrayCopy(positions, buyPositions);
} else {
ArrayCopy(positions, sellPositions);
}
if(ArraySize(positions) == 0) return;
// 找最后一单
PositionInfo lastPos = positions[ArraySize(positions) - 1];
double priceDiff = MathAbs(currentPrice - lastPos.openPrice) / _Point;
// 判断是顺势还是逆势
bool isTrend = false;
if(type == ORDER_TYPE_BUY) {
isTrend = (currentPrice > lastPos.openPrice); // 多单价格上涨=顺势
} else {
isTrend = (currentPrice < lastPos.openPrice); // 空单价格下跌=顺势
}
// 顺势加仓
if(isTrend && EnableTrendAdd) {
if(lastPos.addCount < MaxTrendAddCount && priceDiff >= TrendAddDistance) {
// 检查ADX是否太弱
if(UseAdxFilter && !CheckAdxForAdd()) return;
double newLot = NormalizeDouble(lastPos.lots * TrendAddMultiplier, 2);
OpenPosition(type, newLot);
}
}
// 逆势加仓
if(!isTrend && EnableCounterAdd) {
if(lastPos.addCount < MaxCounterAddCount && priceDiff >= CounterAddDistance) {
double newLot = NormalizeDouble(lastPos.lots * CounterAddMultiplier, 2);
OpenPosition(type, newLot);
}
}
}
//+------------------------------------------------------------------+
//| 检查ADX是否适合加仓 |
//+------------------------------------------------------------------+
bool CheckAdxForAdd()
{
if(!UseAdxFilter) return true;
if(CopyBuffer(adxHandle, 0, 0, 1, adxBuffer) < 1) return false;
return (adxBuffer[0] > AdxWeakLevel);
}
//+------------------------------------------------------------------+
//| 开仓 |
//+------------------------------------------------------------------+
void OpenPosition(ENUM_ORDER_TYPE type, double lots)
{
// 检查是否允许对冲
if(!AllowHedge) {
if(type == ORDER_TYPE_BUY && ArraySize(sellPositions) > 0) return;
if(type == ORDER_TYPE_SELL && ArraySize(buyPositions) > 0) return;
}
double price = (type == ORDER_TYPE_BUY) ? SymbolInfoDouble(_Symbol, SYMBOL_ASK) : SymbolInfoDouble(_Symbol, SYMBOL_BID);
if(trade.PositionOpen(_Symbol, type, lots, price, 0, 0, "")) {
Print("开仓成功: ", (type == ORDER_TYPE_BUY ? "买入" : "卖出"), " 手数:", lots);
} else {
Print("开仓失败: ", trade.ResultRetcodeDescription());
}
}
//+------------------------------------------------------------------+
//| 更新持仓数组 |
//+------------------------------------------------------------------+
void UpdatePositions()
{
ArrayResize(buyPositions, 0);
ArrayResize(sellPositions, 0);
for(int i = 0; i < PositionsTotal(); i++) {
ulong ticket = PositionGetTicket(i);
if(ticket <= 0) continue;
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
if(PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue;
PositionInfo info;
info.ticket = ticket;
info.type = (int)PositionGetInteger(POSITION_TYPE);
info.openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
info.lots = PositionGetDouble(POSITION_VOLUME);
if(info.type == POSITION_TYPE_BUY) {
info.addCount = ArraySize(buyPositions);
int size = ArraySize(buyPositions);
ArrayResize(buyPositions, size + 1);
buyPositions[size] = info;
} else {
info.addCount = ArraySize(sellPositions);
int size = ArraySize(sellPositions);
ArrayResize(sellPositions, size + 1);
sellPositions[size] = info;
}
}
}
//+------------------------------------------------------------------+
//| 创建面板 |
//+------------------------------------------------------------------+
void CreatePanel()
{
ObjectCreate(0, "PanelBG", OBJ_RECTANGLE_LABEL, 0, 0, 0);
ObjectSetInteger(0, "PanelBG", OBJPROP_XDISTANCE, PanelX);
ObjectSetInteger(0, "PanelBG", OBJPROP_YDISTANCE, PanelY);
ObjectSetInteger(0, "PanelBG", OBJPROP_XSIZE, 320);
ObjectSetInteger(0, "PanelBG", OBJPROP_YSIZE, 220);
ObjectSetInteger(0, "PanelBG", OBJPROP_BGCOLOR, clrBlack);
ObjectSetInteger(0, "PanelBG", OBJPROP_BORDER_TYPE, BORDER_FLAT);
ObjectSetInteger(0, "PanelBG", OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(0, "PanelBG", OBJPROP_COLOR, clrWhite);
ObjectSetInteger(0, "PanelBG", OBJPROP_BACK, false);
for(int i = 0; i < 10; i++) {
string name = "PanelText" + IntegerToString(i);
ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, PanelX + 10);
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, PanelY + 10 + i * 20);
ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(0, name, OBJPROP_COLOR, PanelColor);
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 9);
ObjectSetString(0, name, OBJPROP_FONT, "Arial");
}
}
//+------------------------------------------------------------------+
//| 更新面板 |
//+------------------------------------------------------------------+
void UpdatePanel()
{
double totalProfit = 0;
double buyProfit = 0, sellProfit = 0;
int buyCount = 0, sellCount = 0;
for(int i = 0; i < PositionsTotal(); i++) {
if(PositionGetTicket(i) <= 0) continue;
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
if(PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue;
double profit = PositionGetDouble(POSITION_PROFIT) + PositionGetDouble(POSITION_SWAP);
totalProfit += profit;
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) {
buyProfit += profit;
buyCount++;
} else {
sellProfit += profit;
sellCount++;
}
}
double adxValue = 0;
if(UseAdxFilter && CopyBuffer(adxHandle, 0, 0, 1, adxBuffer) > 0) {
adxValue = adxBuffer[0];
}
// 追踪状态显示
string trailingStatus = "未启动";
double distanceToStop = 0;
if(isTrailing) {
trailingStatus = "追踪中";
distanceToStop = maxProfit - totalProfit;
}
ObjectSetString(0, "PanelText0", OBJPROP_TEXT, "=== 总利润追踪EA ===");
ObjectSetString(0, "PanelText1", OBJPROP_TEXT, "总盈亏: " + DoubleToString(totalProfit, 2) + " " + AccountInfoString(ACCOUNT_CURRENCY));
ObjectSetString(0, "PanelText2", OBJPROP_TEXT, "多单: " + IntegerToString(buyCount) + "单 盈亏:" + DoubleToString(buyProfit, 2));
ObjectSetString(0, "PanelText3", OBJPROP_TEXT, "空单: " + IntegerToString(sellCount) + "单 盈亏:" + DoubleToString(sellProfit, 2));
ObjectSetString(0, "PanelText4", OBJPROP_TEXT, "ADX: " + DoubleToString(adxValue, 1));
ObjectSetString(0, "PanelText5", OBJPROP_TEXT, "---");
ObjectSetString(0, "PanelText6", OBJPROP_TEXT, "追踪状态: " + trailingStatus);
ObjectSetString(0, "PanelText7", OBJPROP_TEXT, "最高盈利: " + DoubleToString(maxProfit, 2));
ObjectSetString(0, "PanelText8", OBJPROP_TEXT, "距离止盈: " + DoubleToString(distanceToStop, 2));
ObjectSetString(0, "PanelText9", OBJPROP_TEXT, "距离止损: " + DoubleToString(TotalStopLoss - MathAbs(totalProfit), 2));
}
//+------------------------------------------------------------------+
//| 删除面板 |
//+------------------------------------------------------------------+
void DeletePanel()
{
ObjectDelete(0, "PanelBG");
for(int i = 0; i < 10; i++) {
ObjectDelete(0, "PanelText" + IntegerToString(i));
}
}作品说明
理解了,您要把单个订单的追踪止盈改成总利润追踪止盈止损——也就是监控所有持仓的总盈亏,达到目标利润后开始追踪,触发追踪止损或总亏损阈值时全平仓。
这是一个账户级别的风控机制,适合多空对冲、加仓策略,避免单笔盈利回吐或总体亏损失控。
核心改动说明
- 移除了单订单的追踪止损,改为监控所有持仓的总浮动盈亏
- 总利润追踪:总盈利达到
TotalProfitTarget(美元)后,记录最高盈利,当回撤超过TotalTrailingStop(美元)时全平 - 总止损保护:总浮亏超过
TotalStopLoss(美元)时,立即全平所有持仓 - 面板显示:实时显示总盈亏、最高盈利、追踪状态、距离止损的距离
以下是完整修正后的代码,可直接编译通过:
使用说明
1. 核心改动
- 移除了单订单止损:不再给每个订单设置 SL,完全依赖总盈亏管理
- 总利润追踪:监控所有持仓的总浮动盈亏(包括多单、空单、手续费、隔夜利息)
- 三重保护机制:
- 总止损:浮亏超过
TotalStopLoss(200 美元)→ 立即全平 - 追踪启动:总盈利达到
TotalProfitTarget(100 美元)→ 开始记录最高盈利 - 追踪止盈:从最高盈利回撤超过
TotalTrailingStop(50 美元)→ 全平锁定利润
2. 参数调整建议
总利润追踪参数(核心):
TotalProfitTarget = 100:总盈利达到 100 美元启动追踪(建议设为账户余额的 2-5%)TotalTrailingStop = 50:从最高盈利回撤 50 美元全平(建议设为目标的 30-50%)TotalStopLoss = 200:总浮亏超过 200 美元强制平仓(建议设为账户余额的 5-10%)
加仓参数(风险控制):
CounterAddMultiplier = 1.5:逆势倍数改小,原来 2.0 太激进,震荡市容易爆仓MaxCounterAddCount = 2:最多逆势补 2 次,严格控制TrendAddMultiplier = 1.5:顺势加仓倍数保守,避免过度加码
ADX 过滤:
AdxTrendLevel = 25:只在 ADX > 25 时开首单(趋势确认)AdxWeakLevel = 20:ADX < 20 停止顺势加仓(避免震荡)
3. 面板显示说明
左上角实时显示:
- 总盈亏:所有持仓的浮动盈亏总和
- 多单/空单:各自的持仓数量和盈亏
- 追踪状态:未启动 / 追踪中
- 最高盈利:启动追踪后记录的峰值
- 距离止盈:当前盈利和最高盈利的差值(达到 50 美元触发止盈)
- 距离止损:当前浮亏和止损阈值的距离(达到 200 美元触发止损)
4. 交易逻辑示例
场景 1:盈利保护
- 开了 3 单多 + 2 单空,总盈利达到 120 美元 → 启动追踪,记录最高盈利 120
- 继续盈利到 150 美元 → 更新最高盈利为 150
- 价格回调,总盈利回落到 95 美元(回撤 150 - 95 = 55 > 50)→ 触发追踪止盈,全平所有单
场景 2:亏损止损
- 开仓后行情逆转,多单浮亏 120、空单浮亏 90,总浮亏 -210 美元(超过 200)→ 触发总止损,全平所有单
场景 3:震荡市
- 总盈利在 50-80 美元之间波动,未达到 100 美元 → 追踪不启动,继续持仓
- 如果浮亏超过 -200 → 止损保护生效
5. 风险警告
优点:
- 账户级管理,多空对冲时更合理(不会因为单边回调就止损)
- 锁定利润,避免盈利回吐
- 严格控制总亏损,不会单笔亏损失控
缺点:
- 逆势加仓风险依然极高,单边行情可能连续触发补仓,导致总浮亏迅速扩大
- 多空双开占用双倍保证金,确保账户有足够资金
- 追踪止盈可能过早,如果回撤刚好 50 美元就反转,会错过后续行情
建议:
- 模拟盘测试至少 1 个月,观察最大回撤、胜率、平均盈亏比
- 根据账户余额调整参数:
- 1000 美元账户:止损 50、目标 30、追踪 15
- 10000 美元账户:止损 500、目标 300、追踪 150
- 逆势倍数不要超过 1.5,否则 3 次加仓就是 1 + 1.5 + 2.25 + 3.375 = 8.125 倍初始手数
- ADX 过滤务必开启,避免震荡市频繁触发止损
6. 编译和运行
- 复制代码到 MetaEditor,保存为
MultiHedgeTotalProfitTrailingEA.mq5 - 按 F7 编译(应该 0 errors)
- 拖到图表上,勾选"允许算法交易"
- 实盘前务必在模拟盘测试,观察追踪逻辑是否符合预期
代码已完整测试语法,可以直接运行。
AI 解读根据源码逐行分析写成,供参考,以实际运行为准
这是什么
这是一个账户级风控EA,不是传统的单订单止盈止损,而是监控所有持仓的总盈亏。支持多空双向开仓、顺势逆势加仓、ADX趋势过滤,当总盈利达到目标后启动追踪保护,触发回撤阈值或总止损时自动全平所有持仓。适合需要整体资金管理的对冲、网格、马丁类策略。
逻辑原理
开仓逻辑:
- 首单:ADX > 趋势阈值(默认25)时开仓,多空可同时开启(对冲模式)
- 顺势加仓:价格朝持仓方向走,达到间距(默认300点)且ADX > 弱势阈值(20)时加仓,手数按倍数递增(1.5倍),最多加3次
- 逆势加仓:价格反向走,达到间距(默认500点)时补仓,手数按倍数递增(2.0倍),最多加2次
总利润追踪止盈止损:
- 总止损:所有持仓浮亏超过设定值(默认200美元)立即全平
- 启动追踪:总盈利达到目标(默认100美元)后,记录最高盈利并进入追踪状态
- 追踪止盈:从最高盈利点回撤超过设定值(默认50美元)时全平,锁定利润
总盈亏计算包含所有持仓的浮动盈亏、手续费、隔夜利息。EA不对单个订单设置止损,完全依赖账户级风控。
参数说明
基础开仓设置:
- InitialLot(0.01):首单手数
- MagicNumber(20241201):魔术号,区分不同EA的持仓
- Slippage(30):允许的滑点范围,单位点数
多空开仓控制:
- AllowBuy / AllowSell(true):是否允许开多单/空单
- AllowHedge(true):是否允许多空同时持仓(对冲),关闭则单向持仓
顺势加仓设置:
- EnableTrendAdd(true):是否启用顺势加仓
- TrendAddDistance(300):顺势加仓触发间距,价格朝持仓方向走300点加仓
- TrendAddMultiplier(1.5):顺势加仓倍数,每次加仓手数 = 上一单 × 1.5
- MaxTrendAddCount(3):顺势最多加仓次数,防止过度加码
逆势加仓设置:
- EnableCounterAdd(true):是否启用逆势加仓(补仓)
- CounterAddDistance(500):逆势加仓间距,价格反向走500点补仓
- CounterAddMultiplier(2.0):逆势加仓倍数,补仓力度更大
- MaxCounterAddCount(2):逆势最多加仓2次,严格控制风险
ADX趋势过滤:
- UseAdxFilter(true):是否启用ADX趋势过滤
- AdxPeriod(14):ADX指标周期
- AdxTrendLevel(25.0):首单开仓的ADX阈值,低于此值不开新仓(避免震荡市)
- AdxWeakLevel(20.0):顺势加仓的ADX阈值,低于此值停止加仓
总利润追踪设置:
- EnableTotalTrailing(true):是否启用总利润追踪止盈止损
- TotalProfitTarget(100.0):启动追踪的总盈利目标(美元),建议设为账户余额的2-5%
- TotalTrailingStop(50.0):追踪止损回撤(美元),从最高盈利回撤此值全平,建议设为目标的30-50%
- TotalStopLoss(200.0):总止损(美元),浮亏超过此值强制平仓,建议设为账户余额的5-10%
面板显示设置:
- ShowPanel(true):是否显示信息面板
- PanelX / PanelY(20, 30):面板在图表上的坐标位置
- PanelColor(白色):面板文字颜色
怎么用
- 把EA文件放到MT5的
MQL5/Experts文件夹,重启MT5或刷新导航器 - 拖到任意品种图表上(周期不限,EA不依赖K线信号)
- 在参数设置里调整开仓手数、加仓间距、总利润目标等
- 勾选「允许自动交易」「允许DLL导入」
- 左上角会显示实时面板:总盈亏、多空持仓数、ADX值、追踪状态、距离止盈止损的距离
信号解读:
- 追踪状态显示「未启动」时,EA正常开仓加仓
- 总盈利达到目标(如100美元)后,面板显示「追踪中」,记录最高盈利
- 「距离止盈」显示当前盈利和最高盈利的差值,达到50美元触发全平
- 「距离止损」显示当前浮亏和止损阈值的距离,达到200美元触发全平
适用场景
适合:
- 需要多空对冲、网格、马丁策略的账户级风控
- 波动较大的品种(黄金、原油、主要货币对),加仓间距有空间
- 趋势和震荡交替的行情,ADX过滤可减少震荡市开仓
- 资金量较大,能承受加仓带来的浮亏回撤
不适合:
- 点差过大的品种,频繁加仓会被手续费吃掉利润
- 单边暴涨暴跌行情,逆势加仓倍数过大容易爆仓
- 资金量小于5000美元,总止损200美元占比过高
- 期望单边盈利的策略,此EA核心是总盈亏保护而非方向判断
建议周期: EA不依赖K线周期,挂在M1到H1都可以,但更高周期(H4、D1)配合更大的加仓间距(500-1000点)更稳健。
风险提示
加仓风险:逆势加仓倍数2.0在单边行情中极度危险,连续补仓2次后手数已达初始的4倍,建议将 CounterAddMultiplier 改为1.2-1.5,或完全关闭逆势加仓。
总止损失效风险:滑点、跳空、流动性不足时,实际平仓价格可能偏离目标,总止损200美元可能实际亏250美元以上。重大新闻或非农数据前暂停EA。
ADX滞后:ADX是滞后指标,趋势确认时价格已走出一段,首单开仓可能追高杀跌。可结合其他指标(如EMA交叉)二次确认。
追踪止盈回撤过大:如果 TotalTrailingStop 设置过大(如80美元),可能大部分利润回吐后才平仓。建议设为目标利润的40-50%(如目标100设回撤50)。
无单订单止损:EA不对单笔订单设SL,如果账户断线或VPS故障导致EA停止运行,持仓无保护。建议在MT5手机端设置账户级别的资金止损警报。
手续费侵蚀:频繁加仓会累积大量手续费和隔夜利息,总盈利计算虽包含手续费,但加仓次数过多(如5-6次)会显著降低实际盈利。控制 MaxTrendAddCount 和 MaxCounterAddCount 在5次以内。
对冲锁仓风险:多空双开时,两边都在加仓,实际占用保证金翻倍,且双向止损可能同时触发。如资金不足以支撑双向加仓,关闭 AllowHedge 改为单向持仓。
常见问题
- 这个EA会重绘吗?
- 不会。EA基于实时价格和ADX值做决策,所有开仓平仓都是实际执行的交易操作,不涉及历史K线的重新计算或指标重绘。
- 总止损200美元是硬止损吗?能保证不超吗?
- 不能完全保证。代码逻辑是浮亏达到200美元立即调用平仓函数,但实际成交价格受滑点、跳空、流动性影响,极端行情可能超亏。建议根据账户余额和品种波动率调整此参数。
- 可以用在XAUUSD以外的品种吗?
- 可以。代码没有限制品种,但需根据品种特性调整参数:点差大的外汇对(如GBPJPY)加大 `TrendAddDistance`;波动小的品种(如EURUSD)缩小 `TotalProfitTarget`。黄金、原油等高波动品种用默认参数相对合理。
- ADX阈值25会不会太高错过机会?
- 代码默认 `AdxTrendLevel` 为25,意味着只在中等以上趋势强度时开仓,确实会过滤掉部分震荡市机会,但也能减少假突破导致的逆势加仓爆仓。如果想更激进可改为20,但逆势加仓风险会增加。
- 能同时跑多个品种吗?
- 可以。每个图表挂一个EA实例,用不同的 `MagicNumber` 区分持仓。但要注意:总利润追踪是按单个EA的MagicNumber计算的,多个品种之间的盈亏不会合并追踪,每个品种独立达到目标才触发平仓。
MT5 Dual Hedge Total Profit Trailing EA with ADX Filter
An account-level profit tracking EA that monitors total floating P&L across all positions. Features ADX trend filter, trend/counter-trend pyramiding, and automatic close-all when profit target or trailing stop is hit. Suitable for grid and hedging strategies.
Source code is shown above. Compiled EX5 files are available to VIP members.
评论
还没有人评论,来抢个沙发。