//+------------------------------------------------------------------+ //| XAUUSD_Dual_Martin_EA.mq5 | //| Copyright 2025 | //| | //+------------------------------------------------------------------+ #property copyright "Copyright 2024" #property link "" #property version "1.00" #property description "XAUUSD双向马丁EA - 多空双向马丁策略,空方和多方仓位分开管理" #include CTrade trade; //+------------------------------------------------------------------+ //| 输入参数 | //+------------------------------------------------------------------+ input group "=== 基本设置 ===" input ulong Magic_Number = 999002; // EA魔术号码 input string EA_Comment = "XAUUSD_Dual_Martin"; // 订单注释 input group "=== 策略参数 ===" input double Initial_Lots = 0.04; // 初始入场手数 input double Price_Threshold = 0.4; // 价格变动阈值(美元) input double Martingale_Multiplier = 1.5; // 马丁格尔倍数 input double Profit_Target = 4; // 盈利目标(美元) input double Profit_Protection_Ratio = 0.9; // 盈利保护比例(0.1-1.0) input double Large_Position_Threshold = 0.8; // 大仓位阈值(手数) input double Price_Track_Distance = 0.6; // 价格追踪距离(美元) input bool Enable_Long_Martin = true; // 是否开启多方马丁 input bool Enable_Short_Martin = true; // 是否开启空方马丁 input bool Use_Async_Close = true; // 是否使用异步提交平仓 input int Async_Close_Max_Retries = 1; // 异步平仓最大重试次数 input int Async_Close_Retry_Seconds = 1; // 异步平仓重试间隔秒 input int Async_Close_Timeout_Seconds = 2; // 异步平仓超时秒,超时后切换同步 input group "=== ATR设置 ===" input int ATR_Period = 2; // ATR周期 input double ATR_Threshold = 0.6; // ATR阈值(美元) input double ATR_Distance_Multiplier = 0.9;// ATR加仓距离系数 input group "=== ADX趋势过滤 ===" input bool Enable_ADX_Filter = true; // 启用ADX趋势过滤 input int ADX_Period = 20; // ADX周期 input double ADX_Threshold = 30.0; // ADX阈值,大于此值停止逆势加仓 input group "=== DEMA风险控制 ===" input bool Enable_DEMA_Risk_Control = true; // 启用DEMA风险控制 input int DEMA_Short_Period = 30; // DEMA短周期 input int DEMA_Long_Period = 120; // DEMA长周期 input double DEMA_Risk_Lot_Threshold = 0.8; // DEMA风险控制手数阈值 input double DEMA_Difference_Threshold = 0.01; // DEMA差值恢复阈值 input bool Enable_DEMA_Status_Log = true; // 启用DEMA状态日志(建议关闭以减少日志) input group "=== 时间过滤 ===" input bool Enable_Time_Filter = false; // 启用时间过滤 input int Trade_Start_Hour = 6; // 交易开始小时 input int Trade_End_Hour = 22; // 交易结束小时 input group "=== 风险控制 ===" input bool Enable_Risk_Control = true; // 启用风险控制 input int Max_Add_Per_Bar = 2; // 单根K线单方向最大加仓次数 input double Volatile_Bar_Threshold = 8.0; // 剧烈波动K线阈值(美元) input int Volatile_Bar_Pause = 3; // 剧烈波动后暂停加仓K线数 input group "=== 重启设置 ===" input int Restart_Delay_Seconds = 1; // 重启延迟时间(秒) //+------------------------------------------------------------------+ //| 全局变量 | //+------------------------------------------------------------------+ // 多空方向状态 bool is_long_martin_active = false; // 多头马丁是否活跃 bool is_short_martin_active = false; // 空头马丁是否活跃 // 多头马丁状态 double long_last_entry_price = 0.0; // 多头最后入场价格 double long_current_lot_size = 0.0; // 多头当前手数大小 double long_trailing_stop_level = 0.0; // 多头追踪止损水平 double long_highest_profit = 0.0; // 多头最高盈利记录 int long_martin_add_count = 0; // 多头马丁加仓次数 bool long_large_position_mode = false; // 多头大仓位模式 double long_price_track_level = 0.0; // 多头价格追踪水平 // 空头马丁状态 double short_last_entry_price = 0.0; // 空头最后入场价格 double short_current_lot_size = 0.0; // 空头当前手数大小 double short_trailing_stop_level = 0.0; // 空头追踪止损水平 double short_highest_profit = 0.0; // 空头最高盈利记录 int short_martin_add_count = 0; // 空头马丁加仓次数 bool short_large_position_mode = false; // 空头大仓位模式 double short_price_track_level = 0.0; // 空头价格追踪水平 // 价格跟踪 double last_check_price = 0.0; // 上次检查价格 bool ea_started = false; // EA是否已启动 // ATR 句柄 int atr_handle = INVALID_HANDLE; // ADX 指标句柄 int adx_handle = INVALID_HANDLE; // DEMA 指标句柄 int dema_short_handle = INVALID_HANDLE; int dema_long_handle = INVALID_HANDLE; // ADX趋势状态 bool adx_trend_filter_active = false; // ADX趋势过滤是否激活 bool is_uptrend = false; // 当前是否为上升趋势 bool is_downtrend = false; // 当前是否为下降趋势 // 最近一次加仓距离计算的日志辅助 bool last_distance_used_atr = false; // 是否使用了ATR double last_distance_atr = 0.0; // 最近一次ATR数值 double last_distance_final = 0.0; // 最近一次计算得到的最终距离 // 异步平仓状态 bool long_async_closing = false; // 多头是否处于异步平仓中 bool short_async_closing = false; // 空头是否处于异步平仓中 datetime long_async_start_time = 0; // 多头异步平仓开始时间 datetime short_async_start_time = 0; // 空头异步平仓开始时间 int long_async_retries = 0; // 多头异步已重试次数 int short_async_retries = 0; // 空头异步已重试次数 datetime long_async_last_retry_time = 0; // 多头上次重试时间 datetime short_async_last_retry_time = 0; // 空头上次重试时间 // 风险控制状态 int long_add_count_this_bar = 0; // 当前K线多头加仓次数 int short_add_count_this_bar = 0; // 当前K线空头加仓次数 int current_bar_index = 0; // 当前K线索引 bool long_pause_after_volatile = false; // 多头因剧烈波动暂停 bool short_pause_after_volatile = false; // 空头因剧烈波动暂停 int long_pause_bars_remaining = 0; // 多头暂停剩余K线数 int short_pause_bars_remaining = 0; // 空头暂停剩余K线数 // DEMA风险控制状态 bool long_dema_risk_active = false; // 多头DEMA风险控制是否激活 bool short_dema_risk_active = false; // 空头DEMA风险控制是否激活 bool long_dema_pause = false; // 多头是否因DEMA风险控制暂停 bool short_dema_pause = false; // 空头是否因DEMA风险控制暂停 double long_max_lots = 0.0; // 多头最大手数 double short_max_lots = 0.0; // 空头最大手数 datetime last_dema_check_time = 0; // 上次DEMA检查时间 //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { // 设置交易参数 trade.SetExpertMagicNumber(Magic_Number); trade.SetDeviationInPoints(10); // 默认使用同步模式开仓;平仓时可按需临时切换到异步 trade.SetAsyncMode(false); if(Use_Async_Close) Print("开仓使用同步模式;平仓按设置使用异步提交"); else Print("开仓/平仓均使用同步模式"); // 初始化ATR指标 atr_handle = iATR(_Symbol, _Period, ATR_Period); if(atr_handle == INVALID_HANDLE) { Print("ATR指标创建失败,周期=", ATR_Period, ", 错误=", GetLastError()); } // 初始化ADX指标 adx_handle = iADX(_Symbol, _Period, ADX_Period); if(adx_handle == INVALID_HANDLE) { Print("ADX指标创建失败,周期=", ADX_Period, ", 错误=", GetLastError()); } // 初始化DEMA指标 dema_short_handle = iDEMA(_Symbol, _Period, DEMA_Short_Period, 0, 0); if(dema_short_handle == INVALID_HANDLE) { Print("DEMA短周期指标创建失败,周期=", DEMA_Short_Period, ", 错误=", GetLastError()); } dema_long_handle = iDEMA(_Symbol, _Period, DEMA_Long_Period, 0, 0); if(dema_long_handle == INVALID_HANDLE) { Print("DEMA长周期指标创建失败,周期=", DEMA_Long_Period, ", 错误=", GetLastError()); } // 初始化变量 is_long_martin_active = false; is_short_martin_active = false; long_last_entry_price = 0.0; long_current_lot_size = Initial_Lots; long_trailing_stop_level = 0.0; long_highest_profit = 0.0; long_martin_add_count = 0; long_large_position_mode = false; long_price_track_level = 0.0; short_last_entry_price = 0.0; short_current_lot_size = Initial_Lots; short_trailing_stop_level = 0.0; short_highest_profit = 0.0; short_martin_add_count = 0; short_large_position_mode = false; short_price_track_level = 0.0; last_check_price = 0.0; ea_started = false; // 初始化ADX状态 adx_trend_filter_active = false; is_uptrend = false; is_downtrend = false; // 初始化风险控制状态 long_add_count_this_bar = 0; short_add_count_this_bar = 0; current_bar_index = Bars(_Symbol, _Period); long_pause_after_volatile = false; short_pause_after_volatile = false; long_pause_bars_remaining = 0; // 初始化DEMA风险控制状态 long_dema_risk_active = false; short_dema_risk_active = false; long_dema_pause = false; short_dema_pause = false; long_max_lots = 0.0; short_max_lots = 0.0; last_dema_check_time = 0; // 显示时间过滤设置 if(Enable_Time_Filter) { Print("时间过滤:已启用,交易时间 ", Trade_Start_Hour, ":00 - ", Trade_End_Hour, ":00 (服务器时间)"); } else { Print("时间过滤:已禁用,24小时交易"); } // 显示ADX设置 if(Enable_ADX_Filter) { Print("ADX趋势过滤:已启用,周期=", ADX_Period, ",阈值=", ADX_Threshold); } else { Print("ADX趋势过滤:已禁用"); } // 显示DEMA设置 if(Enable_DEMA_Risk_Control) { Print("DEMA风险控制:已启用,短周期=", DEMA_Short_Period, ",长周期=", DEMA_Long_Period, ",手数阈值=", DEMA_Risk_Lot_Threshold, ",差值阈值=", DEMA_Difference_Threshold); } else { Print("DEMA风险控制:已禁用"); } Print("XAUUSD双向马丁EA初始化成功"); Print("大仓位阈值: ", Large_Position_Threshold, "手,价格追踪距离: ", Price_Track_Distance, "美元"); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { Print("XAUUSD双向马丁EA已停止"); if(atr_handle != INVALID_HANDLE) { IndicatorRelease(atr_handle); atr_handle = INVALID_HANDLE; } if(adx_handle != INVALID_HANDLE) { IndicatorRelease(adx_handle); adx_handle = INVALID_HANDLE; } if(dema_short_handle != INVALID_HANDLE) { IndicatorRelease(dema_short_handle); dema_short_handle = INVALID_HANDLE; } if(dema_long_handle != INVALID_HANDLE) { IndicatorRelease(dema_long_handle); dema_long_handle = INVALID_HANDLE; } } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { // 检查风险控制 CheckRiskControl(); // 检查DEMA风险控制 CheckDEMARiskControl(); // 检查是否在允许交易的时间段内 if(!IsInTradingTime()) { return; } double current_price = SymbolInfoDouble(_Symbol, SYMBOL_BID); // EA启动时立即开始多空双向入场 if(!ea_started) { StartDualMartin(); ea_started = true; return; } // 检查ADX趋势状态 CheckADXTrend(); // 每分钟输出一次马丁状态(包括是否被ADX和DEMA阻止) static datetime last_status_output = 0; if(TimeCurrent() - last_status_output >= 60) { string long_status = "多头马丁状态: "; string short_status = "空头马丁状态: "; // 多头状态 if(!Enable_Long_Martin) { long_status += "已禁用"; } else if(!is_long_martin_active) { long_status += "未激活"; // 检查阻止重启的原因 if(Enable_ADX_Filter && adx_trend_filter_active && is_downtrend) { long_status += "(被ADX阻止)"; } else if(Enable_DEMA_Risk_Control && long_dema_pause) { long_status += "(被DEMA阻止)"; } } else { long_status += "活跃"; // 检查加仓阻止原因 if(Enable_ADX_Filter && adx_trend_filter_active && is_downtrend) { long_status += "(加仓被ADX阻止)"; } else if(Enable_DEMA_Risk_Control && long_dema_pause) { long_status += "(加仓被DEMA阻止)"; } else if(Enable_Risk_Control && long_add_count_this_bar >= Max_Add_Per_Bar) { long_status += "(加仓次数超限)"; } else if(Enable_Risk_Control && long_pause_after_volatile) { long_status += "(剧烈波动暂停)"; } } // 空头状态 if(!Enable_Short_Martin) { short_status += "已禁用"; } else if(!is_short_martin_active) { short_status += "未激活"; // 检查阻止重启的原因 if(Enable_ADX_Filter && adx_trend_filter_active && is_uptrend) { short_status += "(被ADX阻止)"; } else if(Enable_DEMA_Risk_Control && short_dema_pause) { short_status += "(被DEMA阻止)"; } } else { short_status += "活跃"; // 检查加仓阻止原因 if(Enable_ADX_Filter && adx_trend_filter_active && is_uptrend) { short_status += "(加仓被ADX阻止)"; } else if(Enable_DEMA_Risk_Control && short_dema_pause) { short_status += "(加仓被DEMA阻止)"; } else if(Enable_Risk_Control && short_add_count_this_bar >= Max_Add_Per_Bar) { short_status += "(加仓次数超限)"; } else if(Enable_Risk_Control && short_pause_after_volatile) { short_status += "(剧烈波动暂停)"; } } Print(long_status, " | ", short_status); last_status_output = TimeCurrent(); } // 检查价格变动并触发加仓 CheckPriceMovement(current_price); // 检查出场条件 if(is_long_martin_active && Enable_Long_Martin) { CheckLongExitConditions(); } if(is_short_martin_active && Enable_Short_Martin) { CheckShortExitConditions(); } // 检查是否需要重新启动马丁批次 CheckRestartMartin(); // 若使用异步平仓,轮询平仓完成与超时 if(Use_Async_Close) { // 多头异步收尾 if(long_async_closing) { int remaining_long = GetLongPositionCount(); if(remaining_long == 0) { long_async_closing = false; // 重置多头马丁状态 is_long_martin_active = false; long_last_entry_price = 0.0; long_current_lot_size = Initial_Lots; long_trailing_stop_level = 0.0; long_highest_profit = 0.0; long_martin_add_count = 0; // 重置DEMA风险控制状态 long_dema_risk_active = false; long_dema_pause = false; long_max_lots = 0.0; // 重置大仓位模式状态 long_large_position_mode = false; long_price_track_level = 0.0; Print("多头异步平仓完成,状态已重置,等待重新启动"); } else { // 超时检查 if(TimeCurrent() - long_async_start_time > Async_Close_Timeout_Seconds) { Print("多头异步平仓超时,切换为同步强制平仓..."); ForceSyncCloseLong(); } // 重试检查 else if(TimeCurrent() - long_async_last_retry_time >= Async_Close_Retry_Seconds && long_async_retries < Async_Close_Max_Retries) { long_async_last_retry_time = TimeCurrent(); long_async_retries++; Print("多头异步平仓重试 第", long_async_retries, "次,剩余订单=", remaining_long); SubmitAsyncCloseLong(); } } } // 空头异步收尾 if(short_async_closing) { int remaining_short = GetShortPositionCount(); if(remaining_short == 0) { short_async_closing = false; // 重置空头马丁状态 is_short_martin_active = false; short_last_entry_price = 0.0; short_current_lot_size = Initial_Lots; short_trailing_stop_level = 0.0; short_highest_profit = 0.0; short_martin_add_count = 0; // 重置DEMA风险控制状态 short_dema_risk_active = false; short_dema_pause = false; short_max_lots = 0.0; // 重置大仓位模式状态 short_large_position_mode = false; short_price_track_level = 0.0; Print("空头异步平仓完成,状态已重置,等待重新启动"); } else { if(TimeCurrent() - short_async_start_time > Async_Close_Timeout_Seconds) { Print("空头异步平仓超时,切换为同步强制平仓..."); ForceSyncCloseShort(); } else if(TimeCurrent() - short_async_last_retry_time >= Async_Close_Retry_Seconds && short_async_retries < Async_Close_Max_Retries) { short_async_last_retry_time = TimeCurrent(); short_async_retries++; Print("空头异步平仓重试 第", short_async_retries, "次,剩余订单=", remaining_short); SubmitAsyncCloseShort(); } } } } } //+------------------------------------------------------------------+ //| 检查是否在允许交易的时间 | //+------------------------------------------------------------------+ bool IsInTradingTime() { if(!Enable_Time_Filter) return true; MqlDateTime dt; TimeToStruct(TimeCurrent(), dt); int current_hour = dt.hour; // 检查是否在交易时间段内 if(Trade_Start_Hour <= Trade_End_Hour) { // 交易时间在同一天内(如6:00-22:00) return (current_hour >= Trade_Start_Hour && current_hour < Trade_End_Hour); } else { // 交易时间跨越午夜(如22:00-次日6:00) return (current_hour >= Trade_Start_Hour || current_hour < Trade_End_Hour); } } //+------------------------------------------------------------------+ //| 启动双向马丁 | //+------------------------------------------------------------------+ void StartDualMartin() { double current_price = SymbolInfoDouble(_Symbol, SYMBOL_BID); // 根据参数决定是否启动多头马丁 if(Enable_Long_Martin) { if(OpenPosition(ORDER_TYPE_BUY, Initial_Lots)) { is_long_martin_active = true; long_last_entry_price = current_price; long_current_lot_size = Initial_Lots; long_trailing_stop_level = 0.0; long_highest_profit = 0.0; long_martin_add_count = 0; Print("启动多头马丁,入场价格: ", current_price, ",手数: ", Initial_Lots); } } else { Print("多头马丁已禁用,仅启动空头马丁"); } // 根据参数决定是否启动空头马丁 if(Enable_Short_Martin) { if(OpenPosition(ORDER_TYPE_SELL, Initial_Lots)) { is_short_martin_active = true; short_last_entry_price = current_price; short_current_lot_size = Initial_Lots; short_trailing_stop_level = 0.0; short_highest_profit = 0.0; short_martin_add_count = 0; Print("启动空头马丁,入场价格: ", current_price, ",手数: ", Initial_Lots); } } else { Print("空头马丁已禁用,仅启动多头马丁"); } last_check_price = current_price; // 根据启用的马丁方向显示启动信息 if(Enable_Long_Martin && Enable_Short_Martin) { Print("双向马丁启动完成,当前价格: ", current_price); } else if(Enable_Long_Martin) { Print("多头马丁启动完成,当前价格: ", current_price); } else if(Enable_Short_Martin) { Print("空头马丁启动完成,当前价格: ", current_price); } else { Print("警告:多空马丁都已禁用,EA将不会进行任何交易!"); } } //+------------------------------------------------------------------+ //| 检查价格变动并触发加仓 | //+------------------------------------------------------------------+ void CheckPriceMovement(double current_price) { if(last_check_price == 0.0) { last_check_price = current_price; return; } // 计算当前触发距离(仅用于预览,实际比较时重新计算) double preview_distance = CalculateAddOnDistance(1); // 多头加仓:根据ATR或固定阈值动态确定加仓距离 if(is_long_martin_active && Enable_Long_Martin) { // 风险控制:检查单根K线加仓次数限制 if(Enable_Risk_Control && long_add_count_this_bar >= Max_Add_Per_Bar) { static datetime last_bar_limit_log = 0; if(TimeCurrent() - last_bar_limit_log >= 60) { // 每分钟记录一次 Print("风险控制:多头马丁单根K线加仓次数已达上限(", Max_Add_Per_Bar, "次),暂停加仓"); last_bar_limit_log = TimeCurrent(); } return; } // 风险控制:检查剧烈波动暂停 if(Enable_Risk_Control && long_pause_after_volatile) { static datetime last_volatile_pause_log = 0; if(TimeCurrent() - last_volatile_pause_log >= 60) { // 每分钟记录一次 Print("风险控制:多头马丁因剧烈下降K线暂停加仓,剩余", long_pause_bars_remaining, "根K线"); last_volatile_pause_log = TimeCurrent(); } return; } // DEMA风险控制:检查多头是否因DEMA风险控制暂停 if(Enable_DEMA_Risk_Control && long_dema_pause) { if(Enable_DEMA_Status_Log) { static datetime last_dema_pause_log = 0; if(TimeCurrent() - last_dema_pause_log >= 300) { // 每5分钟记录一次,减少日志 Print("DEMA风险控制:多头马丁因DEMA信号暂停加仓,最大手数=", DoubleToString(long_max_lots, 2), ",开仓时间=", TimeToString(long_last_entry_price > 0 ? TimeCurrent() : 0)); last_dema_pause_log = TimeCurrent(); } } return; } // ADX趋势过滤:下降趋势时停止多头加仓 if(adx_trend_filter_active && is_downtrend) { // 不进行多头加仓,但记录日志 static datetime last_downtrend_block_log = 0; if(TimeCurrent() - last_downtrend_block_log >= 60) { // 每分钟记录一次 Print("ADX趋势过滤:下降趋势中,阻止多头马丁加仓"); last_downtrend_block_log = TimeCurrent(); } return; } double long_price_change = long_last_entry_price - current_price; int next_long_index = long_martin_add_count + 1; // 第几次加仓(从1开始) double required_distance_long = CalculateAddOnDistance(next_long_index); if(long_price_change > required_distance_long) { double new_lot_size = NormalizeDouble(long_current_lot_size * Martingale_Multiplier, 2); if(OpenPosition(ORDER_TYPE_BUY, new_lot_size)) { long_martin_add_count++; long_add_count_this_bar++; // 风险控制:增加当前K线加仓计数 long_last_entry_price = current_price; long_current_lot_size = new_lot_size; // 如果处于大仓位模式,重新计算盈亏平衡价位 if(long_large_position_mode) { long_price_track_level = GetAvgPrice(POSITION_TYPE_BUY); Print("多头大仓位模式加仓后更新盈亏平衡价位: ", long_price_track_level); } if(last_distance_used_atr) { Print("多头加仓成功(ATR),第", long_martin_add_count, "次,加仓手数:", new_lot_size, ",价格:", current_price, ",价差:+", long_price_change, ",触发: ATR=", last_distance_atr, " * ", ATR_Distance_Multiplier, " = ", required_distance_long, "; 阈值=", ATR_Threshold); } else { Print("多头加仓成功(固定阈值),第", long_martin_add_count, "次,加仓手数:", new_lot_size, ",价格:", current_price, ",价差:+", long_price_change, ",触发: 固定阈值=", required_distance_long); } } } } // 空头加仓:根据ATR或固定阈值动态确定加仓距离 if(is_short_martin_active && Enable_Short_Martin) { // 风险控制:检查单根K线加仓次数限制 if(Enable_Risk_Control && short_add_count_this_bar >= Max_Add_Per_Bar) { static datetime last_bar_limit_log = 0; if(TimeCurrent() - last_bar_limit_log >= 60) { // 每分钟记录一次 Print("风险控制:空头马丁单根K线加仓次数已达上限(", Max_Add_Per_Bar, "次),暂停加仓"); last_bar_limit_log = TimeCurrent(); } return; } // 风险控制:检查剧烈波动暂停 if(Enable_Risk_Control && short_pause_after_volatile) { static datetime last_volatile_pause_log = 0; if(TimeCurrent() - last_volatile_pause_log >= 60) { // 每分钟记录一次 Print("风险控制:空头马丁因剧烈上升K线暂停加仓,剩余", short_pause_bars_remaining, "根K线"); last_volatile_pause_log = TimeCurrent(); } return; } // DEMA风险控制:检查空头是否因DEMA风险控制暂停 if(Enable_DEMA_Risk_Control && short_dema_pause) { if(Enable_DEMA_Status_Log) { static datetime last_dema_pause_log = 0; if(TimeCurrent() - last_dema_pause_log >= 300) { // 每5分钟记录一次,减少日志 Print("DEMA风险控制:空头马丁因DEMA信号暂停加仓,最大手数=", DoubleToString(short_max_lots, 2), ",开仓时间=", TimeToString(short_last_entry_price > 0 ? TimeCurrent() : 0)); last_dema_pause_log = TimeCurrent(); } } return; } // ADX趋势过滤:上升趋势时停止空头加仓 if(adx_trend_filter_active && is_uptrend) { // 不进行空头加仓,但记录日志 static datetime last_uptrend_block_log = 0; if(TimeCurrent() - last_uptrend_block_log >= 60) { // 每分钟记录一次 Print("ADX趋势过滤:上升趋势中,阻止空头马丁加仓"); last_uptrend_block_log = TimeCurrent(); } return; } double short_price_change = current_price - short_last_entry_price; int next_short_index = short_martin_add_count + 1; // 第几次加仓(从1开始) double required_distance_short = CalculateAddOnDistance(next_short_index); if(short_price_change > required_distance_short) { double new_lot_size = NormalizeDouble(short_current_lot_size * Martingale_Multiplier, 2); if(OpenPosition(ORDER_TYPE_SELL, new_lot_size)) { short_martin_add_count++; short_add_count_this_bar++; // 风险控制:增加当前K线加仓计数 short_last_entry_price = current_price; short_current_lot_size = new_lot_size; // 如果处于大仓位模式,重新计算盈亏平衡价位 if(short_large_position_mode) { short_price_track_level = GetAvgPrice(POSITION_TYPE_SELL); Print("空头大仓位模式加仓后更新盈亏平衡价位: ", short_price_track_level); } if(last_distance_used_atr) { Print("空头加仓成功(ATR),第", short_martin_add_count, "次,加仓手数:", new_lot_size, ",价格:", current_price, ",价差:+", short_price_change, ",触发: ATR=", last_distance_atr, " * ", ATR_Distance_Multiplier, " = ", required_distance_short, "; 阈值=", ATR_Threshold); } else { Print("空头加仓成功(固定阈值),第", short_martin_add_count, "次,加仓手数:", new_lot_size, ",价格:", current_price, ",价差:+", short_price_change, ",触发: 固定阈值=", required_distance_short); } } } } last_check_price = current_price; } //+------------------------------------------------------------------+ //| 计算加仓触发距离(ATR>阈值时采用ATR*系数,否则用固定阈值) | //+------------------------------------------------------------------+ double CalculateAddOnDistance(int next_add_index) { // 优先使用ATR逻辑(当ATR句柄有效且ATR>阈值) if(atr_handle != INVALID_HANDLE) { double atr_values[1]; int copied = CopyBuffer(atr_handle, 0, 0, 1, atr_values); if(copied == 1) { double atr_now = atr_values[0]; if(atr_now > ATR_Threshold) { double distance_atr = atr_now * ATR_Distance_Multiplier; last_distance_used_atr = true; last_distance_atr = atr_now; last_distance_final = NormalizeDouble(distance_atr, 2); return last_distance_final; } } } // 否则使用固定价格阈值 last_distance_used_atr = false; last_distance_atr = 0.0; last_distance_final = NormalizeDouble(Price_Threshold, 2); return last_distance_final; } //+------------------------------------------------------------------+ //| 检查ADX趋势状态 | //+------------------------------------------------------------------+ void CheckADXTrend() { if(!Enable_ADX_Filter || adx_handle == INVALID_HANDLE) { adx_trend_filter_active = false; is_uptrend = false; is_downtrend = false; return; } double adx_values[1]; double plus_di_values[1]; double minus_di_values[1]; // 复制ADX、+DI、-DI数据 int copied_adx = CopyBuffer(adx_handle, 0, 0, 1, adx_values); // ADX主值 int copied_plus_di = CopyBuffer(adx_handle, 1, 0, 1, plus_di_values); // +DI int copied_minus_di = CopyBuffer(adx_handle, 2, 0, 1, minus_di_values); // -DI if(copied_adx == 1 && copied_plus_di == 1 && copied_minus_di == 1) { double adx_now = adx_values[0]; double plus_di_now = plus_di_values[0]; double minus_di_now = minus_di_values[0]; bool was_filter_active = adx_trend_filter_active; bool was_uptrend = is_uptrend; bool was_downtrend = is_downtrend; // 当ADX大于阈值时,激活趋势过滤 if(adx_now > ADX_Threshold) { adx_trend_filter_active = true; // 比较+DI和-DI确定趋势方向 if(plus_di_now > minus_di_now) { // +DI > -DI,上升趋势,停止空头马丁加仓 is_uptrend = true; is_downtrend = false; if(!was_uptrend || !was_filter_active) { Print("ADX趋势过滤激活:上升趋势,ADX=", DoubleToString(adx_now, 2), ",+DI=", DoubleToString(plus_di_now, 2), " > -DI=", DoubleToString(minus_di_now, 2), ",停止空头马丁加仓"); } } else if(plus_di_now < minus_di_now) { // +DI < -DI,下降趋势,停止多头马丁加仓 is_uptrend = false; is_downtrend = true; if(!was_downtrend || !was_filter_active) { Print("ADX趋势过滤激活:下降趋势,ADX=", DoubleToString(adx_now, 2), ",+DI=", DoubleToString(plus_di_now, 2), " < -DI=", DoubleToString(minus_di_now, 2), ",停止多头马丁加仓"); } } else { // +DI = -DI,趋势不明确 is_uptrend = false; is_downtrend = false; if(was_filter_active && (was_uptrend || was_downtrend)) { Print("ADX趋势过滤:趋势不明确,+DI=", DoubleToString(plus_di_now, 2), " = -DI=", DoubleToString(minus_di_now, 2), ",允许双向加仓"); } } } else { // ADX小于阈值,关闭趋势过滤,允许双向加仓 adx_trend_filter_active = false; is_uptrend = false; is_downtrend = false; if(was_filter_active) { Print("ADX趋势过滤关闭:ADX=", DoubleToString(adx_now, 2), " < ", ADX_Threshold, ",允许双向加仓"); } } } else { Print("ADX数据获取失败,错误:ADX=", copied_adx, ", +DI=", copied_plus_di, ", -DI=", copied_minus_di); } } //+------------------------------------------------------------------+ //| 风险控制检查 | //+------------------------------------------------------------------+ void CheckRiskControl() { if(!Enable_Risk_Control) return; int new_bar_index = Bars(_Symbol, _Period); // 新K线时重置加仓计数 if(new_bar_index != current_bar_index) { long_add_count_this_bar = 0; short_add_count_this_bar = 0; current_bar_index = new_bar_index; // 检查上一根K线是否剧烈波动 if(new_bar_index > 0) { double prev_open = iOpen(_Symbol, _Period, 1); double prev_close = iClose(_Symbol, _Period, 1); double bar_range = MathAbs(prev_close - prev_open); if(bar_range > Volatile_Bar_Threshold) { if(prev_close > prev_open) { // 剧烈上升 short_pause_after_volatile = true; short_pause_bars_remaining = Volatile_Bar_Pause; Print("风险控制:检测到剧烈上升K线(范围=", bar_range, "美元),暂停空头马丁", Volatile_Bar_Pause, "根K线"); } else { // 剧烈下降 long_pause_after_volatile = true; long_pause_bars_remaining = Volatile_Bar_Pause; Print("风险控制:检测到剧烈下降K线(范围=", bar_range, "美元),暂停多头马丁", Volatile_Bar_Pause, "根K线"); } } } // 更新暂停状态 if(long_pause_after_volatile && long_pause_bars_remaining > 0) { long_pause_bars_remaining--; if(long_pause_bars_remaining == 0) { long_pause_after_volatile = false; Print("风险控制:多头马丁暂停期结束,恢复加仓"); } } if(short_pause_after_volatile && short_pause_bars_remaining > 0) { short_pause_bars_remaining--; if(short_pause_bars_remaining == 0) { short_pause_after_volatile = false; Print("风险控制:空头马丁暂停期结束,恢复加仓"); } } } } //+------------------------------------------------------------------+ //| 计算指定方向持仓的真实保本价 (含点差成本) | //| posType: POSITION_TYPE_BUY 或 POSITION_TYPE_SELL | //+------------------------------------------------------------------+ double GetAvgPrice(int posType) { double totalLots = 0; double totalCost = 0; // 遍历持仓,计算加权开仓价 for(int i=0; i= 90) { // 每30秒打印一次调试信息 Print("[调试] 多头状态: 盈利=", long_total_profit, "美元, 总仓位=", long_total_lots, "手, 大仓位模式=", (long_large_position_mode ? "是" : "否"), ", 盈利目标=", Profit_Target, "美元, 大仓位阈值=", Large_Position_Threshold, "手"); last_debug_time = TimeCurrent(); } // 检查是否进入大仓位模式 if(!long_large_position_mode && long_total_lots > Large_Position_Threshold) { long_large_position_mode = true; // 计算马丁盈亏平衡价位(加权平均价) long_price_track_level = GetAvgPrice(POSITION_TYPE_BUY); Print("多头马丁进入大仓位模式,总仓位: ", long_total_lots, "手,马丁盈亏平衡价位: ", long_price_track_level); } // 更新最高盈利记录 if(long_total_profit > long_highest_profit) { long_highest_profit = long_total_profit; } if(long_large_position_mode) { // 大仓位模式:基于盈亏平衡价位的价格追踪止盈 double current_price = SymbolInfoDouble(_Symbol, SYMBOL_BID); double target_exit_price = long_price_track_level + Price_Track_Distance; Print("[调试] 多头大仓位: 当前价格=", current_price, ", 盈亏平衡价位=", long_price_track_level, ", 目标出场价位=", target_exit_price, ", 总盈亏=", long_total_profit, "美元"); if(current_price >= target_exit_price) { Print("多头大仓位价格追踪触发,平仓所有多头订单,盈亏平衡价位: ", long_price_track_level, ",当前价格: ", current_price, ",目标出场价位: ", target_exit_price, ",最终盈利: $", long_total_profit); CloseLongPositions(); } } else { // 小仓位模式:盈利保护机制 if(long_total_profit >= Profit_Target) { double protection_level = long_total_profit * Profit_Protection_Ratio; if(long_trailing_stop_level == 0.0) { // 首次激活盈利保护 long_trailing_stop_level = protection_level; Print("多头小仓位盈利保护激活,保护水平: ", protection_level, "美元,当前盈利: ", long_total_profit, "美元"); } else { // 动态更新保护水平:只有当新的保护水平更高时才更新 if(protection_level > long_trailing_stop_level) { double old_level = long_trailing_stop_level; long_trailing_stop_level = protection_level; Print("多头小仓位盈利保护更新:从", old_level, "美元 -> ", long_trailing_stop_level, "美元,当前盈利: ", long_total_profit, "美元"); } } // 检查是否触发保护 if(long_total_profit <= long_trailing_stop_level) { Print("多头小仓位盈利保护触发,平仓所有多头订单,最终盈利: $", long_total_profit); CloseLongPositions(); } } } } //+------------------------------------------------------------------+ //| 检查空头出场条件 | //+------------------------------------------------------------------+ void CheckShortExitConditions() { double short_total_profit = GetShortTotalProfit(); double short_total_lots = GetShortTotalLots(); // 添加调试信息 static datetime last_debug_time_short = 0; if(TimeCurrent() - last_debug_time_short >= 90) { // 每30秒打印一次调试信息 Print("[调试] 空头状态: 盈利=", short_total_profit, "美元, 总仓位=", short_total_lots, "手, 大仓位模式=", (short_large_position_mode ? "是" : "否"), ", 盈利目标=", Profit_Target, "美元, 大仓位阈值=", Large_Position_Threshold, "手"); last_debug_time_short = TimeCurrent(); } // 检查是否进入大仓位模式 if(!short_large_position_mode && short_total_lots > Large_Position_Threshold) { short_large_position_mode = true; // 计算马丁盈亏平衡价位(加权平均价) short_price_track_level = GetAvgPrice(POSITION_TYPE_SELL); Print("空头马丁进入大仓位模式,总仓位: ", short_total_lots, "手,马丁盈亏平衡价位: ", short_price_track_level); } // 更新最高盈利记录 if(short_total_profit > short_highest_profit) { short_highest_profit = short_total_profit; } if(short_large_position_mode) { // 大仓位模式:基于盈亏平衡价位的价格追踪止盈 double current_price = SymbolInfoDouble(_Symbol, SYMBOL_BID); double target_exit_price = short_price_track_level - Price_Track_Distance; Print("[调试] 空头大仓位: 当前价格=", current_price, ", 盈亏平衡价位=", short_price_track_level, ", 目标出场价位=", target_exit_price, ", 总盈亏=", short_total_profit, "美元"); if(current_price <= target_exit_price) { Print("空头大仓位价格追踪触发,平仓所有空头订单,盈亏平衡价位: ", short_price_track_level, ",当前价格: ", current_price, ",目标出场价位: ", target_exit_price, ",最终盈利: $", short_total_profit); CloseShortPositions(); } } else { // 小仓位模式:盈利保护机制 if(short_total_profit >= Profit_Target) { double protection_level = short_total_profit * Profit_Protection_Ratio; if(short_trailing_stop_level == 0.0) { // 首次激活盈利保护 short_trailing_stop_level = protection_level; Print("空头小仓位盈利保护激活,保护水平: ", protection_level, "美元,当前盈利: ", short_total_profit, "美元"); } else { // 动态更新保护水平:只有当新的保护水平更高时才更新 if(protection_level > short_trailing_stop_level) { double old_level = short_trailing_stop_level; short_trailing_stop_level = protection_level; Print("空头小仓位盈利保护更新:从", old_level, "美元 -> ", short_trailing_stop_level, "美元,当前盈利: ", short_total_profit, "美元"); } } // 检查是否触发保护 if(short_total_profit <= short_trailing_stop_level) { Print("空头小仓位盈利保护触发,平仓所有空头订单,最终盈利: $", short_total_profit); CloseShortPositions(); } } } } //+------------------------------------------------------------------+ //| 检查是否需要重新启动马丁批次 | //+------------------------------------------------------------------+ void CheckRestartMartin() { // 检查多头马丁重新启动:根据参数决定是否重新启动多头马丁 if(Enable_Long_Martin && !is_long_martin_active && GetLongPositionCount() == 0) { // ADX趋势过滤:下降趋势时阻止多头马丁重启 if(Enable_ADX_Filter && adx_trend_filter_active && is_downtrend) { static datetime last_downtrend_restart_block_log = 0; if(TimeCurrent() - last_downtrend_restart_block_log >= 60) { // 每分钟记录一次 Print("ADX趋势过滤:下降趋势中,阻止多头马丁重启"); last_downtrend_restart_block_log = TimeCurrent(); } return; } // DEMA风险控制:检查多头是否因DEMA风险控制暂停重启 if(Enable_DEMA_Risk_Control && long_dema_pause) { if(Enable_DEMA_Status_Log) { static datetime last_dema_restart_block_log = 0; if(TimeCurrent() - last_dema_restart_block_log >= 300) { // 每5分钟记录一次,减少日志 Print("DEMA风险控制:多头马丁因DEMA信号暂停重启,最大手数=", DoubleToString(long_max_lots, 2), ",开仓时间=", TimeToString(long_last_entry_price > 0 ? TimeCurrent() : 0)); last_dema_restart_block_log = TimeCurrent(); } } return; } // 添加延迟检查,确保上一批次完全平仓后再启动 static datetime long_last_close_time = 0; // 如果时间标记为0,说明是第一次检查,立即设置当前时间 if(long_last_close_time == 0) { long_last_close_time = TimeCurrent(); Print("多头马丁等待重启,开始计时..."); } // 等待指定时间确保完全平仓 if(TimeCurrent() - long_last_close_time >= Restart_Delay_Seconds) { double current_price = SymbolInfoDouble(_Symbol, SYMBOL_BID); if(OpenPosition(ORDER_TYPE_BUY, Initial_Lots)) { is_long_martin_active = true; long_last_entry_price = current_price; long_current_lot_size = Initial_Lots; long_trailing_stop_level = 0.0; long_highest_profit = 0.0; long_martin_add_count = 0; // 重置大仓位模式状态 long_large_position_mode = false; long_price_track_level = 0.0; long_last_close_time = 0; // 重置时间 Print("多头马丁重新启动,入场价格: ", current_price, ",手数: ", Initial_Lots); } } else { // 显示等待时间 int remaining_time = Restart_Delay_Seconds - (int)(TimeCurrent() - long_last_close_time); if(remaining_time > 0) { Print("多头马丁等待重启,剩余时间: ", remaining_time, "秒"); } } } // 检查空头马丁重新启动:根据参数决定是否重新启动空头马丁 if(Enable_Short_Martin && !is_short_martin_active && GetShortPositionCount() == 0) { // ADX趋势过滤:上升趋势时阻止空头马丁重启 if(Enable_ADX_Filter && adx_trend_filter_active && is_uptrend) { static datetime last_uptrend_restart_block_log = 0; if(TimeCurrent() - last_uptrend_restart_block_log >= 60) { // 每分钟记录一次 Print("ADX趋势过滤:上升趋势中,阻止空头马丁重启"); last_uptrend_restart_block_log = TimeCurrent(); } return; } // DEMA风险控制:检查空头马丁因DEMA信号暂停重启 if(Enable_DEMA_Risk_Control && short_dema_pause) { if(Enable_DEMA_Status_Log) { static datetime last_dema_restart_block_log = 0; if(TimeCurrent() - last_dema_restart_block_log >= 300) { // 每5分钟记录一次,减少日志 Print("DEMA风险控制:空头马丁因DEMA信号暂停重启,最大手数=", DoubleToString(short_max_lots, 2), ",开仓时间=", TimeToString(short_last_entry_price > 0 ? TimeCurrent() : 0)); last_dema_restart_block_log = TimeCurrent(); } } return; } // 添加延迟检查,确保上一批次完全平仓后再启动 static datetime short_last_close_time = 0; // 如果时间标记为0,说明是第一次检查,立即设置当前时间 if(short_last_close_time == 0) { short_last_close_time = TimeCurrent(); Print("空头马丁等待重启,开始计时..."); } // 等待指定时间确保完全平仓 if(TimeCurrent() - short_last_close_time >= Restart_Delay_Seconds) { double current_price = SymbolInfoDouble(_Symbol, SYMBOL_BID); if(OpenPosition(ORDER_TYPE_SELL, Initial_Lots)) { is_short_martin_active = true; short_last_entry_price = current_price; short_current_lot_size = Initial_Lots; short_trailing_stop_level = 0.0; short_highest_profit = 0.0; short_martin_add_count = 0; // 重置大仓位模式状态 short_large_position_mode = false; short_price_track_level = 0.0; short_last_close_time = 0; // 重置时间 Print("空头马丁重新启动,入场价格: ", current_price, ",手数: ", Initial_Lots); } } else { // 显示等待时间 int remaining_time = Restart_Delay_Seconds - (int)(TimeCurrent() - short_last_close_time); if(remaining_time > 0) { Print("空头马丁等待重启,剩余时间: ", remaining_time, "秒"); } } } } //+------------------------------------------------------------------+ //| 开仓函数 | //+------------------------------------------------------------------+ bool OpenPosition(ENUM_ORDER_TYPE order_type, double lot_size) { double price = (order_type == ORDER_TYPE_BUY) ? SymbolInfoDouble(_Symbol, SYMBOL_ASK) : SymbolInfoDouble(_Symbol, SYMBOL_BID); if(trade.PositionOpen(_Symbol, order_type, lot_size, price, 0, 0, EA_Comment)) { Print("开仓成功 - 类型: ", (order_type == ORDER_TYPE_BUY ? "买入" : "卖出"), ",手数: ", lot_size, ",价格: ", price); return true; } else { Print("开仓失败 - 错误代码: ", trade.ResultRetcode()); return false; } } //+------------------------------------------------------------------+ //| 平仓所有多头持仓 | //+------------------------------------------------------------------+ void CloseLongPositions() { double final_profit = GetLongTotalProfit(); int total_positions = GetLongPositionCount(); Print("开始批量平仓多头订单,当前总盈利=", final_profit, "美元,持仓数量=", total_positions); if(Use_Async_Close) { // 异步提交平仓请求:遍历并逐个提交,但不等待结果 int submit_count = 0; trade.SetAsyncMode(true); for(int i = PositionsTotal() - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if(PositionSelectByTicket(ticket)) { if(PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_MAGIC) == Magic_Number && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { if(trade.PositionClose(ticket)) { submit_count++; } else { Print("提交多头异步平仓失败: ", ticket, ", 错误: ", trade.ResultRetcode()); } } } } trade.SetAsyncMode(false); long_async_closing = true; long_async_start_time = TimeCurrent(); long_async_retries = 0; long_async_last_retry_time = TimeCurrent(); Print("已异步提交多头平仓指令,提交数量=", submit_count, ",等待成交..."); return; } // 同步路径:沿用原批量+逐个关闭逻辑 bool close_success = false; int positions_closed = 0; if(BatchCloseLongPositions()) { Print("多头批量平仓成功,关闭了", total_positions, "个订单,最终盈利=", final_profit, "美元"); close_success = true; } else { Print("多头批量平仓失败,尝试逐个平仓作为备选方案..."); positions_closed = 0; for(int i = PositionsTotal() - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if(PositionSelectByTicket(ticket)) { if(PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_MAGIC) == Magic_Number && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { if(trade.PositionClose(ticket)) { positions_closed++; } else { Print("平仓多头订单失败: ", ticket, ", 错误: ", trade.ResultRetcode()); } } } } Print("备选逐个平仓完成,成功关闭了", positions_closed, "个订单"); int remaining_positions = GetLongPositionCount(); if(remaining_positions == 0) { close_success = true; Print("验证完成:所有多头订单已成功平仓"); } else { Print("警告:仍有", remaining_positions, "个多头订单未能平仓!"); Print("这些订单将继续保留,EA不会重置马丁状态"); return; // 不重置状态,等待下次检查 } } if(close_success) { is_long_martin_active = false; long_last_entry_price = 0.0; long_current_lot_size = Initial_Lots; long_trailing_stop_level = 0.0; long_highest_profit = 0.0; long_martin_add_count = 0; // 重置大仓位模式状态 long_large_position_mode = false; long_price_track_level = 0.0; // 重置DEMA风险控制状态 long_dema_risk_active = false; long_dema_pause = false; long_max_lots = 0.0; Print("多头马丁状态已重置,等待重新启动"); Print("多头马丁平仓完成,等待", Restart_Delay_Seconds, "秒后重启检查"); } } //+------------------------------------------------------------------+ //| 平仓所有空头持仓 | //+------------------------------------------------------------------+ void CloseShortPositions() { double final_profit = GetShortTotalProfit(); int total_positions = GetShortPositionCount(); Print("开始批量平仓空头订单,当前总盈利=", final_profit, "美元,持仓数量=", total_positions); if(Use_Async_Close) { int submit_count = 0; trade.SetAsyncMode(true); for(int i = PositionsTotal() - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if(PositionSelectByTicket(ticket)) { if(PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_MAGIC) == Magic_Number && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) { if(trade.PositionClose(ticket)) { submit_count++; } else { Print("提交空头异步平仓失败: ", ticket, ", 错误: ", trade.ResultRetcode()); } } } } trade.SetAsyncMode(false); short_async_closing = true; short_async_start_time = TimeCurrent(); short_async_retries = 0; short_async_last_retry_time = TimeCurrent(); Print("已异步提交空头平仓指令,提交数量=", submit_count, ",等待成交..."); return; } // 同步路径:沿用原批量+逐个关闭逻辑 bool close_success = false; int positions_closed = 0; if(BatchCloseShortPositions()) { Print("空头批量平仓成功,关闭了", total_positions, "个订单,最终盈利=", final_profit, "美元"); close_success = true; } else { Print("空头批量平仓失败,尝试逐个平仓作为备选方案..."); positions_closed = 0; for(int i = PositionsTotal() - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if(PositionSelectByTicket(ticket)) { if(PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_MAGIC) == Magic_Number && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) { if(trade.PositionClose(ticket)) { positions_closed++; } else { Print("平仓空头订单失败: ", ticket, ", 错误: ", trade.ResultRetcode()); } } } } Print("备选逐个平仓完成,成功关闭了", positions_closed, "个订单"); int remaining_positions = GetShortPositionCount(); if(remaining_positions == 0) { close_success = true; Print("验证完成:所有空头订单已成功平仓"); } else { Print("警告:仍有", remaining_positions, "个空头订单未能平仓!"); Print("这些订单将继续保留,EA不会重置马丁状态"); return; // 不重置状态,等待下次检查 } } if(close_success) { is_short_martin_active = false; short_last_entry_price = 0.0; short_current_lot_size = Initial_Lots; short_trailing_stop_level = 0.0; short_highest_profit = 0.0; short_martin_add_count = 0; // 重置大仓位模式状态 short_large_position_mode = false; short_price_track_level = 0.0; // 重置DEMA风险控制状态 short_dema_risk_active = false; short_dema_pause = false; short_max_lots = 0.0; Print("空头马丁状态已重置,等待重新启动"); Print("空头马丁平仓完成,等待", Restart_Delay_Seconds, "秒后重启检查"); } } //+------------------------------------------------------------------+ //| 获取多头持仓数 | //+------------------------------------------------------------------+ int GetLongPositionCount() { int count = 0; for(int i = 0; i < PositionsTotal(); i++) { ulong ticket = PositionGetTicket(i); if(PositionSelectByTicket(ticket)) { if(PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_MAGIC) == Magic_Number && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { count++; } } } return count; } //+------------------------------------------------------------------+ //| 获取空头持仓数 | //+------------------------------------------------------------------+ int GetShortPositionCount() { int count = 0; for(int i = 0; i < PositionsTotal(); i++) { ulong ticket = PositionGetTicket(i); if(PositionSelectByTicket(ticket)) { if(PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_MAGIC) == Magic_Number && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) { count++; } } } return count; } //+------------------------------------------------------------------+ //| 计算多头总盈利 | //+------------------------------------------------------------------+ double GetLongTotalProfit() { double total_profit = 0.0; for(int i = 0; i < PositionsTotal(); i++) { ulong ticket = PositionGetTicket(i); if(PositionSelectByTicket(ticket)) { if(PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_MAGIC) == Magic_Number && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { total_profit += PositionGetDouble(POSITION_PROFIT); } } } return total_profit; } //+------------------------------------------------------------------+ //| 计算空头总盈利 | //+------------------------------------------------------------------+ double GetShortTotalProfit() { double total_profit = 0.0; for(int i = 0; i < PositionsTotal(); i++) { ulong ticket = PositionGetTicket(i); if(PositionSelectByTicket(ticket)) { if(PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_MAGIC) == Magic_Number && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) { total_profit += PositionGetDouble(POSITION_PROFIT); } } } return total_profit; } //+------------------------------------------------------------------+ //| 计算多头总仓位大小 | //+------------------------------------------------------------------+ double GetLongTotalLots() { double total_lots = 0.0; for(int i = 0; i < PositionsTotal(); i++) { ulong ticket = PositionGetTicket(i); if(PositionSelectByTicket(ticket)) { if(PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_MAGIC) == Magic_Number && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { total_lots += PositionGetDouble(POSITION_VOLUME); } } } return total_lots; } //+------------------------------------------------------------------+ //| 计算空头总仓位大小 | //+------------------------------------------------------------------+ double GetShortTotalLots() { double total_lots = 0.0; for(int i = 0; i < PositionsTotal(); i++) { ulong ticket = PositionGetTicket(i); if(PositionSelectByTicket(ticket)) { if(PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_MAGIC) == Magic_Number && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) { total_lots += PositionGetDouble(POSITION_VOLUME); } } } return total_lots; } //+------------------------------------------------------------------+ //| 在图表上显示信息 | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { // 在图表右上角显示策略状态 string info = ""; info += "XAUUSD双向马丁EA\n"; info += "魔术号: " + IntegerToString(Magic_Number) + "\n"; info += "价格阈值: $" + DoubleToString(Price_Threshold, 2) + "\n"; info += "盈利目标: $" + DoubleToString(Profit_Target, 2) + "\n"; info += "保护比例: " + DoubleToString(Profit_Protection_Ratio * 100, 0) + "%\n"; info += "多头马丁: " + (Enable_Long_Martin ? "启用" : "禁用") + "\n"; info += "空头马丁: " + (Enable_Short_Martin ? "启用" : "禁用") + "\n"; info += "ATR设置: 周期=" + IntegerToString(ATR_Period) + ", 阈值=" + DoubleToString(ATR_Threshold, 2) + ", 系数=" + DoubleToString(ATR_Distance_Multiplier, 2) + "\n"; // 当前ATR值 if(atr_handle != INVALID_HANDLE) { double atr_values_display[1]; if(CopyBuffer(atr_handle, 0, 0, 1, atr_values_display) == 1) { info += "当前ATR: $" + DoubleToString(atr_values_display[0], 2) + "\n"; } } // 显示DEMA设置和状态 if(Enable_DEMA_Risk_Control) { info += "DEMA风险控制: 已启用 (短周期=" + IntegerToString(DEMA_Short_Period) + ", 长周期=" + IntegerToString(DEMA_Long_Period) + ", 手数阈值=" + DoubleToString(DEMA_Risk_Lot_Threshold, 2) + ", 差值阈值=" + DoubleToString(DEMA_Difference_Threshold, 2) + ")\n"; if(dema_short_handle != INVALID_HANDLE && dema_long_handle != INVALID_HANDLE) { double dema_short_display[1]; double dema_long_display[1]; if(CopyBuffer(dema_short_handle, 0, 0, 1, dema_short_display) == 1 && CopyBuffer(dema_long_handle, 0, 0, 1, dema_long_display) == 1) { info += "当前DEMA: 短周期=" + DoubleToString(dema_short_display[0], _Digits) + ", 长周期=" + DoubleToString(dema_long_display[0], _Digits) + "\n"; if(long_dema_risk_active || short_dema_risk_active) { if(long_dema_pause) info += "多头DEMA状态: 暂停加仓\n"; else if(long_dema_risk_active) info += "多头DEMA状态: 允许加仓\n"; if(short_dema_pause) info += "空头DEMA状态: 暂停加仓\n"; else if(short_dema_risk_active) info += "空头DEMA状态: 允许加仓\n"; } else { info += "DEMA风险控制: 未激活\n"; } } } } else { info += "DEMA风险控制: 已禁用\n"; } // 显示ADX趋势过滤状态 if(Enable_ADX_Filter) { info += "ADX趋势过滤: 已启用 (周期=" + IntegerToString(ADX_Period) + ", 阈值=" + DoubleToString(ADX_Threshold, 1) + ")\n"; if(adx_handle != INVALID_HANDLE) { double adx_values_display[1]; double plus_di_values_display[1]; double minus_di_values_display[1]; if(CopyBuffer(adx_handle, 0, 0, 1, adx_values_display) == 1 && CopyBuffer(adx_handle, 1, 0, 1, plus_di_values_display) == 1 && CopyBuffer(adx_handle, 2, 0, 1, minus_di_values_display) == 1) { info += "当前ADX: " + DoubleToString(adx_values_display[0], 2) + ",+DI: " + DoubleToString(plus_di_values_display[0], 2) + ",-DI: " + DoubleToString(minus_di_values_display[0], 2) + "\n"; if(adx_trend_filter_active) { if(is_uptrend) info += "趋势状态: 上升趋势 (阻止空头加仓)\n"; else if(is_downtrend) info += "趋势状态: 下降趋势 (阻止多头加仓)\n"; else info += "趋势状态: 不明确 (允许双向加仓)\n"; } else { info += "趋势状态: 无强趋势 (允许双向加仓)\n"; } } } } else { info += "ADX趋势过滤: 已禁用\n"; } // 显示时间过滤状态 if(Enable_Time_Filter) { bool in_trading_time = IsInTradingTime(); info += "时间过滤: " + (in_trading_time ? "交易时间" : "非交易时间") + "\n"; info += "交易时段: " + IntegerToString(Trade_Start_Hour) + ":00-" + IntegerToString(Trade_End_Hour) + ":00\n"; } else { info += "时间过滤: 已禁用\n"; } info += "\n=== 多头马丁 ==="; info += "\n状态: " + (is_long_martin_active ? "活跃" : "等待") + "\n"; if(is_long_martin_active) { double long_total_lots = GetLongTotalLots(); info += "总仓位: " + DoubleToString(long_total_lots, 2) + "手\n"; info += "当前手数: " + DoubleToString(long_current_lot_size, 2) + "\n"; info += "最大手数: " + DoubleToString(long_max_lots, 2) + "\n"; info += "加仓次数: " + IntegerToString(long_martin_add_count) + "\n"; info += "总盈利: $" + DoubleToString(GetLongTotalProfit(), 2) + "\n"; info += "大仓位模式: " + (long_large_position_mode ? "已激活" : "未激活") + "\n"; if(long_large_position_mode && long_price_track_level > 0) { info += "价格追踪: " + DoubleToString(long_price_track_level, _Digits) + "\n"; } else if(long_trailing_stop_level > 0) { info += "保护线: $" + DoubleToString(long_trailing_stop_level, 2) + "\n"; } } info += "\n=== 空头马丁 ==="; info += "\n状态: " + (is_short_martin_active ? "活跃" : "等待") + "\n"; if(is_short_martin_active) { double short_total_lots = GetShortTotalLots(); info += "总仓位: " + DoubleToString(short_total_lots, 2) + "手\n"; info += "当前手数: " + DoubleToString(short_current_lot_size, 2) + "\n"; info += "最大手数: " + DoubleToString(short_max_lots, 2) + "\n"; info += "加仓次数: " + IntegerToString(short_martin_add_count) + "\n"; info += "总盈利: $" + DoubleToString(GetShortTotalProfit(), 2) + "\n"; info += "大仓位模式: " + (short_large_position_mode ? "已激活" : "未激活") + "\n"; if(short_large_position_mode && short_price_track_level > 0) { info += "价格追踪: " + DoubleToString(short_price_track_level, _Digits) + "\n"; } else if(short_trailing_stop_level > 0) { info += "保护线: $" + DoubleToString(short_trailing_stop_level, 2) + "\n"; } } // 显示当前价格信息 double current_price = SymbolInfoDouble(_Symbol, SYMBOL_BID); info += "\n当前价格: " + DoubleToString(current_price, _Digits) + "\n"; if(last_check_price > 0) { double price_change = current_price - last_check_price; info += "价格变动: " + DoubleToString(price_change, _Digits) + "\n"; } Comment(info); } //+------------------------------------------------------------------+ //| 批量平仓多头持仓 | //+------------------------------------------------------------------+ bool BatchCloseLongPositions() { int positions_to_close = 0; ulong tickets[]; // 首先收集所有需要平仓的多头订单号 for(int i = 0; i < PositionsTotal(); i++) { ulong ticket = PositionGetTicket(i); if(PositionSelectByTicket(ticket)) { if(PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_MAGIC) == Magic_Number && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { positions_to_close++; ArrayResize(tickets, positions_to_close); tickets[positions_to_close - 1] = ticket; } } } if(positions_to_close == 0) { Print("没有找到需要平仓的多头订单"); return true; } Print("准备批量平仓", positions_to_close, "个多头订单"); // 逐个平仓(因为MQL5没有真正的批量平仓API) int success_count = 0; for(int i = 0; i < positions_to_close; i++) { if(trade.PositionClose(tickets[i])) { success_count++; } else { Print("平仓多头订单失败: ", tickets[i], ", 错误: ", trade.ResultRetcode()); } } Print("批量平仓完成,成功: ", success_count, "/", positions_to_close); return (success_count == positions_to_close); } //+------------------------------------------------------------------+ //| 批量平仓空头持仓 | //+------------------------------------------------------------------+ bool BatchCloseShortPositions() { int positions_to_close = 0; ulong tickets[]; // 首先收集所有需要平仓的空头订单号 for(int i = 0; i < PositionsTotal(); i++) { ulong ticket = PositionGetTicket(i); if(PositionSelectByTicket(ticket)) { if(PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_MAGIC) == Magic_Number && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) { positions_to_close++; ArrayResize(tickets, positions_to_close); tickets[positions_to_close - 1] = ticket; } } } if(positions_to_close == 0) { Print("没有找到需要平仓的空头订单"); return true; } Print("准备批量平仓", positions_to_close, "个空头订单"); // 逐个平仓(因为MQL5没有真正的批量平仓API) int success_count = 0; for(int i = 0; i < positions_to_close; i++) { if(trade.PositionClose(tickets[i])) { success_count++; } else { Print("平仓空头订单失败: ", tickets[i], ", 错误: ", trade.ResultRetcode()); } } Print("批量平仓完成,成功: ", success_count, "/", positions_to_close); return (success_count == positions_to_close); } //+------------------------------------------------------------------+ //| 提交异步平仓 - 多头 | //+------------------------------------------------------------------+ void SubmitAsyncCloseLong() { trade.SetAsyncMode(true); int submit_count = 0; for(int i = PositionsTotal() - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if(PositionSelectByTicket(ticket)) { if(PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_MAGIC) == Magic_Number && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { if(trade.PositionClose(ticket)) { submit_count++; } else { Print("重试提交多头异步平仓失败: ", ticket, ", 错误: ", trade.ResultRetcode()); } } } } trade.SetAsyncMode(false); Print("已重试提交多头异步平仓,提交数量=", submit_count); } //+------------------------------------------------------------------+ //| 提交异步平仓 - 空头 | //+------------------------------------------------------------------+ void SubmitAsyncCloseShort() { trade.SetAsyncMode(true); int submit_count = 0; for(int i = PositionsTotal() - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if(PositionSelectByTicket(ticket)) { if(PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_MAGIC) == Magic_Number && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) { if(trade.PositionClose(ticket)) { submit_count++; } else { Print("重试提交空头异步平仓失败: ", ticket, ", 错误: ", trade.ResultRetcode()); } } } } trade.SetAsyncMode(false); Print("已重试提交空头异步平仓,提交数量=", submit_count); } //+------------------------------------------------------------------+ //| 超时回退:同步强制平仓 - 多头 | //+------------------------------------------------------------------+ void ForceSyncCloseLong() { trade.SetAsyncMode(false); int positions_closed = 0; for(int i = PositionsTotal() - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if(PositionSelectByTicket(ticket)) { if(PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_MAGIC) == Magic_Number && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { if(trade.PositionClose(ticket)) { positions_closed++; } else { Print("同步强制平仓多头失败: ", ticket, ", 错误: ", trade.ResultRetcode()); } } } } Print("同步强制平仓多头完成,成功关闭=", positions_closed); } //+------------------------------------------------------------------+ //| 超时回退:同步强制平仓 - 空头 | //+------------------------------------------------------------------+ void ForceSyncCloseShort() { trade.SetAsyncMode(false); int positions_closed = 0; for(int i = PositionsTotal() - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if(PositionSelectByTicket(ticket)) { if(PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_MAGIC) == Magic_Number && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) { if(trade.PositionClose(ticket)) { positions_closed++; } else { Print("同步强制平仓空头失败: ", ticket, ", 错误: ", trade.ResultRetcode()); } } } } Print("同步强制平仓空头完成,成功关闭=", positions_closed); } //+------------------------------------------------------------------+ //| 检查DEMA风险控制 | //+------------------------------------------------------------------+ void CheckDEMARiskControl() { if(!Enable_DEMA_Risk_Control) return; // 更新最大手数 UpdateMaxLots(); // 检查是否需要激活DEMA风险控制 if(!long_dema_risk_active && long_max_lots >= DEMA_Risk_Lot_Threshold) { long_dema_risk_active = true; Print("DEMA风险控制:多头最大手数(", long_max_lots, ")超过阈值(", DEMA_Risk_Lot_Threshold, "),激活DEMA风险控制"); } if(!short_dema_risk_active && short_max_lots >= DEMA_Risk_Lot_Threshold) { short_dema_risk_active = true; Print("DEMA风险控制:空头最大手数(", short_max_lots, ")超过阈值(", DEMA_Risk_Lot_Threshold, "),激活DEMA风险控制"); } // 如果已激活风险控制,在每根K线结束时检查DEMA if(long_dema_risk_active || short_dema_risk_active) { int current_bar = Bars(_Symbol, _Period); datetime current_bar_time = iTime(_Symbol, _Period, 0); // 只在K线结束时检查一次,避免噪音 if(current_bar_time != last_dema_check_time) { last_dema_check_time = current_bar_time; CheckDEMASignals(); } } } //+------------------------------------------------------------------+ //| 更新最大手数 | //+------------------------------------------------------------------+ void UpdateMaxLots() { long_max_lots = 0.0; short_max_lots = 0.0; for(int i = 0; i < PositionsTotal(); i++) { ulong ticket = PositionGetTicket(i); if(PositionSelectByTicket(ticket)) { if(PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_MAGIC) == Magic_Number) { double lot_size = PositionGetDouble(POSITION_VOLUME); if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { if(lot_size > long_max_lots) long_max_lots = lot_size; // 记录多头最大手数 } else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) { if(lot_size > short_max_lots) short_max_lots = lot_size; // 记录空头最大手数 } } } } } //+------------------------------------------------------------------+ //| 检查DEMA信号 | //+------------------------------------------------------------------+ void CheckDEMASignals() { if(dema_short_handle == INVALID_HANDLE || dema_long_handle == INVALID_HANDLE) { Print("DEMA指标句柄无效,无法检查DEMA信号"); return; } double dema_short_values[1]; double dema_long_values[1]; int copied_short = CopyBuffer(dema_short_handle, 0, 0, 1, dema_short_values); int copied_long = CopyBuffer(dema_long_handle, 0, 0, 1, dema_long_values); if(copied_short == 1 && copied_long == 1) { double dema_short = dema_short_values[0]; double dema_long = dema_long_values[0]; // 检查多头DEMA风险控制 if(long_dema_risk_active) { double long_difference = dema_short - dema_long; if(dema_short > dema_long && MathAbs(long_difference) > DEMA_Difference_Threshold) { if(long_dema_pause) { long_dema_pause = false; Print("DEMA风险控制:多头恢复加仓,DEMA", DEMA_Short_Period, "(", dema_short, ") > DEMA", DEMA_Long_Period, "(", dema_long, "),差值=", DoubleToString(long_difference, 2), " > ", DEMA_Difference_Threshold); } } else { if(!long_dema_pause) { long_dema_pause = true; if(dema_short <= dema_long) { Print("DEMA风险控制:多头暂停加仓,DEMA", DEMA_Short_Period, "(", dema_short, ") <= DEMA", DEMA_Long_Period, "(", dema_long, ")"); } else { Print("DEMA风险控制:多头暂停加仓,差值不足,DEMA", DEMA_Short_Period, "(", dema_short, ") > DEMA", DEMA_Long_Period, "(", dema_long, "),差值=", DoubleToString(long_difference, 2), " <= ", DEMA_Difference_Threshold); } } } } // 检查空头DEMA风险控制 if(short_dema_risk_active) { double short_difference = dema_long - dema_short; if(dema_short < dema_long && MathAbs(short_difference) > DEMA_Difference_Threshold) { if(short_dema_pause) { short_dema_pause = false; Print("DEMA风险控制:空头恢复加仓,DEMA", DEMA_Short_Period, "(", dema_short, ") < DEMA", DEMA_Long_Period, "(", dema_long, "),差值=", DoubleToString(short_difference, 2), " > ", DEMA_Difference_Threshold); } } else { if(!short_dema_pause) { short_dema_pause = true; if(dema_short >= dema_long) { Print("DEMA风险控制:空头暂停加仓,DEMA", DEMA_Short_Period, "(", dema_short, ") >= DEMA", DEMA_Long_Period, "(", dema_long, ")"); } else { Print("DEMA风险控制:空头暂停加仓,差值不足,DEMA", DEMA_Short_Period, "(", dema_short, ") < DEMA", DEMA_Long_Period, "(", dema_long, "),差值=", DoubleToString(short_difference, 2), " <= ", DEMA_Difference_Threshold); } } } } } else { Print("DEMA数据获取失败,错误:短周期=", copied_short, ",长周期=", copied_long); } } //+------------------------------------------------------------------+