有没有懂的大佬帮我看一下这个能用吗,靠谱吗
//+------------------------------------------------------------------+
//| EURUSD_Risk_EA_V2_Fixed.mq4 |
//| Copyright 2024, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "2.01"
#property strict
// 基础交易参数(EUR/USD专属)
input double LotSize = 0.1; // 初始手数
input int StopLoss = 30; // 止损点数(30点=0.0030)
input int TakeProfit = 60; // 止盈点数(盈亏比2:1)
input int TrailingStop_Initial = 10; // 初始移动止损步长(盈利≤30点)
input int TrailingStop_Enhanced = 15;// 增强移动止损步长(盈利>30点)
input int TrailingTrigger = 15; // 移动止损触发阈值(盈利15点启动)
input int MagicNumber = 12345; // 魔术号(唯一标识EA订单)
input int Slippage = 3; // 允许滑点(点)
// 风控核心参数
input double MaxRiskPerTrade = 0.01; // 单笔最大风险(账户资金的1%)
input int MaxOrdersPerDay = 5; // 单日最大开仓次数
input double MaxDrawdown = 0.05; // 最大账户回撤(5%)
input int TrendFilterPeriod = 200; // 趋势过滤均线周期(EUR/USD专属)
input double MaxSpread = 0.3; // 最大允许点差(0.3点)
// 开仓信号参数(可切换)
input ENUM_SIGNAL_TYPE SignalType = SIGNAL_MACD_RSI; // 信号类型:MACD+RSI/布林带/双均线
enum ENUM_SIGNAL_TYPE {
SIGNAL_MACD_RSI, // MACD+RSI组合信号
SIGNAL_BOLLINGER, // 布林带突破信号
SIGNAL_MA_CROSS // 双均线金叉死叉信号
};
// 信号专属参数
input int MACD_Fast = 12; // MACD快速周期
input int MACD_Slow = 26; // MACD慢速周期
input int MACD_Signal = 9; // MACD信号周期
input int RSI_Period = 14; // RSI周期
input int RSI_Overbought = 70;// RSI超买阈值
input int RSI_Oversold = 30; // RSI超卖阈值
input int Bollinger_Period = 20; // 布林带周期
input int Bollinger_Dev = 2; // 布林带标准差
input int MA_Short = 50; // 短期均线周期
input int MA_Long = 200; // 长期均线周期
// 全局变量
int OrdersToday = 0; // 今日开仓次数
double MaxEquity; // 历史最高权益(用于回撤计算)
datetime LastTradeDate; // 最后交易日期
datetime LastSignalTime; // 最后信号触发时间(防重复开仓)
const int SignalFilterPeriod = 60; // 信号过滤周期(60秒内不重复触发)
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// 初始化历史最高权益(首次为当前权益)
MaxEquity = AccountEquity();
LastTradeDate = 0;
OrdersToday = 0;
LastSignalTime = 0;
// 日志初始化
Print("=== EURUSD Risk EA V2.01 初始化成功 ===");
Print("初始账户权益:", AccountEquity(), " USD");
Print("最大允许回撤:", MaxDrawdown*100, "%");
Print("信号类型:", SignalTypeToString(SignalType));
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
Print("=== EA退出 ===");
Print("退出原因:", DeinitReasonToString(reason));
Print("今日开仓次数:", OrdersToday);
Print("当前账户权益:", AccountEquity(), " USD");
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// 1. 更新历史最高权益
UpdateMaxEquity();
// 2. 风控前置检查(失败直接返回)
if(!RiskCheck()) return;
// 3. 信号过滤(60秒内不重复触发)
if(TimeCurrent() - LastSignalTime < SignalFilterPeriod) return;
// 4. 获取开仓信号(带指标容错)
bool BuySignal = GetBuySignal();
bool SellSignal = GetSellSignal();
// 5. 开仓逻辑(无对应方向订单时开仓)
if(BuySignal && !OrderExists(OP_BUY))
{
if(OpenOrder(OP_BUY, LotSize, StopLoss, TakeProfit))
LastSignalTime = TimeCurrent();
}
else if(SellSignal && !OrderExists(OP_SELL))
{
if(OpenOrder(OP_SELL, LotSize, StopLoss, TakeProfit))
LastSignalTime = TimeCurrent();
}
// 6. 优化版移动止损(带重试机制)
UpdateTrailingStop_Enhanced();
}
//+------------------------------------------------------------------+
//| 风控检查函数(核心优化) |
//+------------------------------------------------------------------+
bool RiskCheck()
{
// 检查账户回撤(基于历史最高权益)
double CurrentDrawdown = (MaxEquity - AccountEquity()) / MaxEquity;
if(CurrentDrawdown >= MaxDrawdown)
{
Print("【风控拦截】账户回撤达到", DoubleToStr(CurrentDrawdown*100, 2), "%, 暂停交易");
return false;
}
// 检查单日开仓次数(跨日重置)
if(TimeDay(TimeLocal()) != TimeDay(LastTradeDate) || TimeMonth(TimeLocal()) != TimeMonth(LastTradeDate) || TimeYear(TimeLocal()) != TimeYear(LastTradeDate))
{
OrdersToday = 0;
LastTradeDate = TimeLocal();
Print("【日期重置】今日开仓次数清零,当前日期:", TimeToStr(TimeLocal(), TIME_DATE));
}
if(OrdersToday >= MaxOrdersPerDay)
{
Print("【风控拦截】今日开仓次数达到", MaxOrdersPerDay, "次,暂停交易");
return false;
}
// 检查点差(单位修正)
double CurrentSpread = (Ask - Bid) / Point; // 转换为点数
if(CurrentSpread > MaxSpread)
{
Print("【风控拦截】当前点差", DoubleToStr(CurrentSpread, 2), "点,超过允许值", MaxSpread, "点");
return false;
}
// 检查账户资金(最低100美元)
if(AccountBalance() < 100)
{
Print("【风控拦截】账户资金不足100美元,暂停交易");
return false;
}
// 检查市场状态(是否开盘)
if(!IsMarketOpen())
{
Print("【风控拦截】市场未开盘,暂停交易");
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| 开仓函数(MT4兼容版本) |
//+------------------------------------------------------------------+
bool OpenOrder(int orderType, double lot, int sl, int tp)
{
// 计算风险手数(取最小手数、初始手数、风险手数的最小值)
double RiskLot = CalculateRiskLot(sl);
double MinLot = MarketInfo(_Symbol, MODE_MINLOT);
double MaxLot = MarketInfo(_Symbol, MODE_MAXLOT);
lot = MathMin(MathMax(lot, MinLot), MaxLot); // 限制在手数范围内
lot = MathMin(lot, RiskLot); // 不超过风险手数
// 计算止损止盈价格(防止价格异常)
double openPrice = 0.0;
double slPrice = 0.0;
double tpPrice = 0.0;
if(orderType == OP_BUY)
{
openPrice = Ask;
slPrice = (sl > 0) ? NormalizeDouble(Bid - sl * Point, Digits) : 0;
tpPrice = (tp > 0) ? NormalizeDouble(Bid + tp * Point, Digits) : 0;
// 止损不能大于当前价格,止盈不能小于当前价格
if((slPrice > 0 && slPrice >= Bid) || (tpPrice > 0 && tpPrice <= Bid))
{
Print("【开仓失败】多单止损/止盈价格异常,SL:", slPrice, ",TP:", tpPrice);
return false;
}
}
else if(orderType == OP_SELL)
{
openPrice = Bid;
slPrice = (sl > 0) ? NormalizeDouble(Ask + sl * Point, Digits) : 0;
tpPrice = (tp > 0) ? NormalizeDouble(Ask - tp * Point, Digits) : 0;
// 止损不能小于当前价格,止盈不能大于当前价格
if((slPrice > 0 && slPrice <= Ask) || (tpPrice > 0 && tpPrice >= Ask))
{
Print("【开仓失败】空单止损/止盈价格异常,SL:", slPrice, ",TP:", tpPrice);
return false;
}
}
// MT4兼容的订单发送
int ticket = OrderSend(_Symbol, orderType, lot, openPrice, Slippage, slPrice, tpPrice,
"", MagicNumber, 0, (orderType == OP_BUY) ? clrBlue : clrRed);
if(ticket > 0)
{
Print("【开仓成功】类型:", (orderType == OP_BUY ? "多头" : "空头"),
",手数:", DoubleToStr(lot, 2),
",开仓价:", DoubleToStr(openPrice, Digits),
",SL:", (slPrice > 0 ? DoubleToStr(slPrice, Digits) : "无"),
",TP:", (tpPrice > 0 ? DoubleToStr(tpPrice, Digits) : "无"));
OrdersToday++;
LastTradeDate = TimeLocal();
return true;
}
else
{
int error = GetLastError();
Print("【开仓失败】类型:", (orderType == OP_BUY ? "多头" : "空头"),
",错误代码:", error, ",错误描述:", ErrorDescription(error));
return false;
}
}
//+------------------------------------------------------------------+
//| 计算风险手数函数(精准适配) |
//+------------------------------------------------------------------+
double CalculateRiskLot(int sl)
{
double accountBalance = AccountBalance();
double riskAmount = accountBalance * MaxRiskPerTrade; // 单笔风险金额
double tickValue = MarketInfo(_Symbol, MODE_TICKVALUE); // 每点价值
double slPoints = (double)sl; // 止损点数
// 容错处理:避免除零错误
if(tickValue <= 0 || slPoints <= 0 || accountBalance <= 0)
{
Print("【风险手数计算警告】参数异常,返回最小手数");
return MarketInfo(_Symbol, MODE_MINLOT);
}
double lot = riskAmount / (slPoints * tickValue);
double minLot = MarketInfo(_Symbol, MODE_MINLOT);
double maxLot = MarketInfo(_Symbol, MODE_MAXLOT);
double step = MarketInfo(_Symbol, MODE_LOTSTEP);
// 标准化手数
lot = MathMin(MathMax(lot, minLot), maxLot);
lot = NormalizeDouble(lot / step, 0) * step;
return lot;
}
//+------------------------------------------------------------------+
//| 检查订单是否存在函数(精准过滤) |
//+------------------------------------------------------------------+
bool OrderExists(int orderType)
{
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
// 过滤条件:当前品种、魔术号、订单类型、未关闭状态
if(OrderSymbol() == _Symbol &&
OrderMagicNumber() == MagicNumber &&
OrderType() == orderType &&
OrderCloseTime() == 0)
{
return true;
}
}
}
return false;
}
//+------------------------------------------------------------------+
//| 优化版移动止损函数(MT4兼容) |
//+------------------------------------------------------------------+
void UpdateTrailingStop_Enhanced()
{
if(TrailingTrigger <= 0) return;
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) &&
OrderSymbol() == _Symbol &&
OrderMagicNumber() == MagicNumber &&
OrderCloseTime() == 0)
{
double currentPrice = (OrderType() == OP_BUY) ? Bid : Ask;
double profitPoints = 0;
// 计算盈利点数(基于价格变动)
if(OrderType() == OP_BUY)
{
profitPoints = (currentPrice - OrderOpenPrice()) / Point;
}
else if(OrderType() == OP_SELL)
{
profitPoints = (OrderOpenPrice() - currentPrice) / Point;
}
// 盈利未达阈值,不启动移动止损
if(profitPoints < TrailingTrigger) continue;
// 根据盈利大小选择移动止损步长
int trailingStep = (profitPoints > 30) ? TrailingStop_Enhanced : TrailingStop_Initial;
double newSl = 0.0;
bool needModify = false;
// 计算新止损价格(仅向上/向下调整,不回落)
if(OrderType() == OP_BUY)
{
newSl = NormalizeDouble(currentPrice - trailingStep * Point, Digits);
// 新止损>原止损 或 原止损为0(未设置),才修改
if(newSl > OrderStopLoss() || OrderStopLoss() == 0)
{
needModify = true;
}
}
else if(OrderType() == OP_SELL)
{
newSl = NormalizeDouble(currentPrice + trailingStep * Point, Digits);
// 新止损<原止损 或 原止损为0(未设置),才修改
if((newSl < OrderStopLoss() || OrderStopLoss() == 0) && newSl > 0)
{
needModify = true;
}
}
if(needModify)
{
ModifyOrder(OrderTicket(), OrderOpenPrice(), newSl, OrderTakeProfit());
}
}
}
}
//+------------------------------------------------------------------+
//| 订单修改函数(MT4兼容) |
//+------------------------------------------------------------------+
bool ModifyOrder(int ticket, double openPrice, double sl, double tp)
{
int retryCount = 0;
const int maxRetry = 3; // 最多重试3次
while(retryCount < maxRetry)
{
if(OrderModify(ticket, openPrice, sl, tp, 0, clrNONE))
{
Print("【止损更新成功】订单号:", ticket, ",新SL:", DoubleToStr(sl, Digits));
return true;
}
else
{
retryCount++;
int error = GetLastError();
Print("【止损更新失败】订单号:", ticket, ",错误代码:", error, ",重试次数:", retryCount);
Sleep(500); // 延迟500ms后重试
}
}
Print("【止损更新失败】订单号:", ticket, ",已达最大重试次数");
return false;
}
//+------------------------------------------------------------------+
//| 获取多头开仓信号函数 |
//+------------------------------------------------------------------+
bool GetBuySignal()
{
switch(SignalType)
{
case SIGNAL_MACD_RSI:
return GetMACD_RSI_BuySignal();
case SIGNAL_BOLLINGER:
return GetBollinger_BuySignal();
case SIGNAL_MA_CROSS:
return GetMA_Cross_BuySignal();
default:
return false;
}
}
//+------------------------------------------------------------------+
//| 获取空头开仓信号函数 |
//+------------------------------------------------------------------+
bool GetSellSignal()
{
switch(SignalType)
{
case SIGNAL_MACD_RSI:
return GetMACD_RSI_SellSignal();
case SIGNAL_BOLLINGER:
return GetBollinger_SellSignal();
case SIGNAL_MA_CROSS:
return GetMA_Cross_SellSignal();
default:
return false;
}
}
//+------------------------------------------------------------------+
//| MACD+RSI多头信号 |
//+------------------------------------------------------------------+
bool GetMACD_RSI_BuySignal()
{
double macdCurrent = iMACD(NULL, 0, MACD_Fast, MACD_Slow, MACD_Signal, PRICE_CLOSE, MODE_MAIN, 0);
double macdPrevious = iMACD(NULL, 0, MACD_Fast, MACD_Slow, MACD_Signal, PRICE_CLOSE, MODE_MAIN, 1);
double rsiCurrent = iRSI(NULL, 0, RSI_Period, PRICE_CLOSE, 0);
// MACD金叉 + RSI超卖区域反弹
return (macdPrevious < 0 && macdCurrent > 0 && rsiCurrent < RSI_Oversold);
}
//+------------------------------------------------------------------+
//| MACD+RSI空头信号 |
//+------------------------------------------------------------------+
bool GetMACD_RSI_SellSignal()
{
double macdCurrent = iMACD(NULL, 0, MACD_Fast, MACD_Slow, MACD_Signal, PRICE_CLOSE, MODE_MAIN, 0);
double macdPrevious = iMACD(NULL, 0, MACD_Fast, MACD_Slow, MACD_Signal, PRICE_CLOSE, MODE_MAIN, 1);
double rsiCurrent = iRSI(NULL, 0, RSI_Period, PRICE_CLOSE, 0);
// MACD死叉 + RSI超买区域回落
return (macdPrevious > 0 && macdCurrent < 0 && rsiCurrent > RSI_Overbought);
}
//+------------------------------------------------------------------+
//| 布林带多头信号 |
//+------------------------------------------------------------------+
bool GetBollinger_BuySignal()
{
double upperBand = iBands(NULL, 0, Bollinger_Period, Bollinger_Dev, 0, PRICE_CLOSE, MODE_UPPER, 0);
double lowerBand = iBands(NULL, 0, Bollinger_Period, Bollinger_Dev, 0, PRICE_CLOSE, MODE_LOWER, 0);
double middleBand = iBands(NULL, 0, Bollinger_Period, Bollinger_Dev, 0, PRICE_CLOSE, MODE_MAIN, 0);
// 价格触及下轨 + 开始反弹
return (Low[0] <= lowerBand && Close[0] > Open[0] && Close[0] > middleBand);
}
//+------------------------------------------------------------------+
//| 布林带空头信号 |
//+------------------------------------------------------------------+
bool GetBollinger_SellSignal()
{
double upperBand = iBands(NULL, 0, Bollinger_Period, Bollinger_Dev, 0, PRICE_CLOSE, MODE_UPPER, 0);
double lowerBand = iBands(NULL, 0, Bollinger_Period, Bollinger_Dev, 0, PRICE_CLOSE, MODE_LOWER, 0);
double middleBand = iBands(NULL, 0, Bollinger_Period, Bollinger_Dev, 0, PRICE_CLOSE, MODE_MAIN, 0);
// 价格触及上轨 + 开始回落
return (High[0] >= upperBand && Close[0] < Open[0] && Close[0] < middleBand);
}
//+------------------------------------------------------------------+
//| 均线交叉多头信号 |
//+------------------------------------------------------------------+
bool GetMA_Cross_BuySignal()
{
double maShortCurrent = iMA(NULL, 0, MA_Short, 0, MODE_EMA, PRICE_CLOSE, 0);
double maLongCurrent = iMA(NULL, 0, MA_Long, 0, MODE_EMA, PRICE_CLOSE, 0);
double maShortPrevious = iMA(NULL, 0, MA_Short, 0, MODE_EMA, PRICE_CLOSE, 1);
double maLongPrevious = iMA(NULL, 0, MA_Long, 0, MODE_EMA, PRICE_CLOSE, 1);
// 短期均线上穿长期均线(金叉)
return (maShortPrevious <= maLongPrevious && maShortCurrent > maLongCurrent);
}
//+------------------------------------------------------------------+
//| 均线交叉空头信号 |
//+------------------------------------------------------------------+
bool GetMA_Cross_SellSignal()
{
double maShortCurrent = iMA(NULL, 0, MA_Short, 0, MODE_EMA, PRICE_CLOSE, 0);
double maLongCurrent = iMA(NULL, 0, MA_Long, 0, MODE_EMA, PRICE_CLOSE, 0);
double maShortPrevious = iMA(NULL, 0, MA_Short, 0, MODE_EMA, PRICE_CLOSE, 1);
double maLongPrevious = iMA(NULL, 0, MA_Long, 0, MODE_EMA, PRICE_CLOSE, 1);
// 短期均线下穿长期均线(死叉)
return (maShortPrevious >= maLongPrevious && maShortCurrent < maLongCurrent);
}
//+------------------------------------------------------------------+
//| 辅助函数 |
//+------------------------------------------------------------------+
// 更新历史最高权益
void UpdateMaxEquity()
{
double currentEquity = AccountEquity();
if(currentEquity > MaxEquity)
{
MaxEquity = currentEquity;
}
}
// 检查市场开盘时间
bool IsMarketOpen()
{
int dayOfWeek = TimeDayOfWeek(TimeCurrent());
int hour = TimeHour(TimeCurrent());
// 周末不交易
if(dayOfWeek == 0 || dayOfWeek == 6)
return false;
// 交易时段:周一至周五(可根据具体市场调整)
// 这里简单返回true,实际使用时可根据需要完善
return true;
}
// 错误描述函数
string ErrorDescription(int errorCode)
{
switch(errorCode)
{
case 0: return "成功";
case 1: return "没有错误";
case 2: return "常见错误";
case 3: return "无效交易参数";
case 4: return "服务器忙";
case 5: return "旧版本";
case 6: return "无连接";
case 7: return "没有足够权限";
case 8: return "太频繁请求";
case 9: return "违规操作";
case 64: return "账户被禁用";
case 65: return "无效账户";
case 128: return "交易超时";
case 129: return "无效价格";
case 130: return "无效止损";
case 131: return "无效交易量";
case 132: return "市场关闭";
case 133: return "交易被禁用";
case 134: return "资金不足";
case 135: return "价格已变化";
case 136: return "无价格";
case 137: return "经纪人忙";
case 138: return "重新报价";
case 139: return "订单被锁定";
case 140: return "买入订单不被允许";
case 141: return "太多请求";
case 145: return "交易被修改被禁止";
case 146: return "交易上下文忙";
case 147: return "过期时间被禁止";
case 148: return "订单太多";
case 149: return "挂单交易被对冲订单禁止";
case 150: return "交易被禁止";
default: return "未知错误: " + IntegerToString(errorCode);
}
}
// 信号类型转字符串
string SignalTypeToString(ENUM_SIGNAL_TYPE type)
{
switch(type)
{
case SIGNAL_MACD_RSI: return "MACD+RSI组合信号";
case SIGNAL_BOLLINGER: return "布林带突破信号";
case SIGNAL_MA_CROSS: return "双均线金叉死叉信号";
default: return "未知信号类型";
}
}
// EA退出原因转字符串
string DeinitReasonToString(int reason)
{
switch(reason)
{
case REASON_ACCOUNT: return "账户变更";
case REASON_CHARTCHANGE: return "图表变更";
case REASON_CHARTCLOSE: return "图表关闭";
case REASON_CLOSE: return "终端关闭";
case REASON_INITFAILED: return "初始化失败";
case REASON_PARAMETERS: return "参数变更";
case REASON_RECOMPILE: return "重新编译";
case REASON_REMOVE: return "EA移除";
case REASON_TEMPLATE: return "模板变更";
default: return "未知原因: " + IntegerToString(reason);
}
}
//+------------------------------------------------------------------+ |