mql5/Experts/双向马丁.mq5
2025-09-08 21:24:18 +08:00

1905 lines
85 KiB
MQL5

//+------------------------------------------------------------------+
//| XAUUSD_Dual_Martin_EA.mq5 |
//| Copyright 2025 |
//| |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024"
#property link ""
#property version "1.00"
#property description "XAUUSD双向马丁EA - 多空双向马丁策略,空方和多方仓位分开管理"
#include <Trade\Trade.mqh>
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<PositionsTotal(); i++) {
ulong ticket = PositionGetTicket(i);
if(PositionSelectByTicket(ticket)) {
if(PositionGetString(POSITION_SYMBOL) == _Symbol &&
PositionGetInteger(POSITION_MAGIC) == Magic_Number &&
PositionGetInteger(POSITION_TYPE) == posType) {
double lots = PositionGetDouble(POSITION_VOLUME);
double price = PositionGetDouble(POSITION_PRICE_OPEN);
totalLots += lots;
totalCost += lots * price;
}
}
}
if(totalLots == 0) return 0;
// 加权平均开仓价
double avgPrice = totalCost / totalLots;
Print("加权平均开仓价为:", avgPrice);
// 合约大小 (黄金一般是100)
double contract_size = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_CONTRACT_SIZE);
// 当前点差
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double spread = ask - bid;
// 点差对应的总成本(以美元计)
double spread_cost_total = spread * contract_size * totalLots;
// 每手分摊的价格修正
double spread_adjust = spread_cost_total / (contract_size * totalLots);
// 根据方向修正保本价
if(posType == POSITION_TYPE_BUY) {
double buyAvgPrice =avgPrice + spread_adjust;
return buyAvgPrice; // 多单需要更高的价格解套
} else {
double sellAvgPrice =avgPrice - spread_adjust;
return sellAvgPrice; // 空单需要更低的价格解套
}
}
//+------------------------------------------------------------------+
//| 检查多头出场条件 |
//+------------------------------------------------------------------+
void CheckLongExitConditions() {
double long_total_profit = GetLongTotalProfit();
double long_total_lots = GetLongTotalLots();
// 添加调试信息
static datetime last_debug_time = 0;
if(TimeCurrent() - last_debug_time >= 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);
}
}
//+------------------------------------------------------------------+