//+------------------------------------------------------------------+
//| 123RulePro.mq5 |
//| ForexHelper.AI 增强版123法则策略 |
//| Last Update: 2024-06-15 |
//+------------------------------------------------------------------+
#property copyright "ForexHelper.AI"
#property version "3.3"
#property strict
//--- 输入参数
input double RiskPerTrade = 0.01; // 单笔风险比例(0.01=1%)
input int ATRPeriod = 18; // ATR周期(14-20)
input double RewardRatio = 3.5; // 最小盈亏比(3:1-5:1)
input int MaxDailyRisk = 2; // 最大单日风险(%)
input int TradingStartHour = 2; // 开始交易小时(GMT)
input int TradingEndHour = 20; // 结束交易小时(GMT)
input bool EnableTrendFilter= true; // 启用趋势过滤
input ENUM_TIMEFRAMES TrendTF = PERIOD_H4; // 趋势时间框架
input double ADXThreshold = 18.0; // ADX趋势强度阈值
input int MaxSpread = 30; // 最大允许点差
//--- 全局变量
int handleATR, handleADX, handleMATrend;
double atrBuffer[], adxBuffer[], maTrendBuffer[];
datetime lastTradeTime;
//+------------------------------------------------------------------+
//| 初始化函数 |
//+------------------------------------------------------------------+
int OnInit()
{
handleATR = iATR(_Symbol, _Period, ATRPeriod);
handleADX = iADX(_Symbol, TrendTF, 14);
handleMATrend = iMA(_Symbol, TrendTF, 50, 0, MODE_SMA, PRICE_CLOSE);
ArraySetAsSeries(atrBuffer, true);
ArraySetAsSeries(adxBuffer, true);
ArraySetAsSeries(maTrendBuffer, true);
if(RiskPerTrade > 5) Alert("风险比例过高!建议不超过5%");
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| 主执行函数 |
//+------------------------------------------------------------------+
void OnTick()
{
if(!IsNewBar() || !IsTradingTime() || !VerifyMarketCondition()) return;
if(CopyBuffer(handleATR, 0, 0, 3, atrBuffer) < 3) return;
if(CopyBuffer(handleADX, 0, 0, 2, adxBuffer) < 2) return;
if(CopyBuffer(handleMATrend, 0, 0, 2, maTrendBuffer) < 2) return;
double atrValue = NormalizeDouble(atrBuffer[0], _Digits);
double currentADX = adxBuffer[1];
bool trendUp = maTrendBuffer[0] > maTrendBuffer[1];
int signal = Check123Pattern(currentADX, trendUp, atrValue);
if(signal == 0) return;
if(GetDailyRisk() >= MaxDailyRisk) {
Comment("达到单日最大风险限制!");
return;
}
MqlTick last_tick;
SymbolInfoTick(_Symbol, last_tick);
double price = (signal == 1) ? last_tick.ask : last_tick.bid;
double sl = CalculateSL(signal, price, atrValue);
double tp = (signal == 1) ? price + (price - sl)*RewardRatio
: price - (sl - price)*RewardRatio;
double lotSize = CalculateLotSize(price, sl);
if(lotSize <= 0) return;
SmartOrderSend(signal, lotSize, sl, tp);
lastTradeTime = TimeCurrent();
}
//+------------------------------------------------------------------+
//| 增强版123法则信号检测 |
//+------------------------------------------------------------------+
int Check123Pattern(double adxValue, bool trendUp, double atr)
{
double high1 = iHigh(_Symbol, _Period, 1);
double high2 = iHigh(_Symbol, _Period, 2);
double low1 = iLow(_Symbol, _Period, 1);
double low2 = iLow(_Symbol, _Period, 2);
double close0 = iClose(_Symbol, _Period, 0);
double close1 = iClose(_Symbol, _Period, 1);
if(EnableTrendFilter && adxValue < ADXThreshold)
return 0;
if(trendUp)
{
if(low2 < low1 && high1 > high2)
if(close1 > (high1 + low1)*0.6)
if(close0 > high1 + atr*0.3)
return 1;
}
else
{
if(high2 > high1 && low1 < low2)
if(close1 < (high1 + low1)*0.4)
if(close0 < low1 - atr*0.3)
return -1;
}
return 0;
}
//+------------------------------------------------------------------+
//| 智能订单发送函数 |
//+------------------------------------------------------------------+
void SmartOrderSend(int signal, double lots, double sl, double tp)
{
MqlTradeRequest request;
ZeroMemory(request);
MqlTradeResult result;
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = NormalizeLotSize(lots);
request.type = (signal == 1) ? ORDER_TYPE_BUY : ORDER_TYPE_SELL;
request.deviation = 50;
request.type_filling = ORDER_FILLING_FOK;
for(int i=0; i<3; i++)
{
MqlTick last_tick;
if(!SymbolInfoTick(_Symbol, last_tick))
{
Print("获取报价失败!");
return;
}
// 更新价格和订单参数
request.price = (signal == 1) ? last_tick.ask : last_tick.bid;
request.sl = sl;
request.tp = tp;
// 检查价格偏差(5点内)
double currentPrice = (signal == 1) ? last_tick.ask : last_tick.bid;
double priceDiff = MathAbs(request.price - currentPrice) / _Point;
if(priceDiff > 5)
{
Print("价格偏差过大:", priceDiff, "点,取消交易");
return;
}
// 发送订单
bool sent = OrderSend(request, result);
if(sent)
{
if(result.retcode == TRADE_RETCODE_DONE)
{
Print("订单执行成功,成交价:", result.price);
break;
}
else
{
Print("订单发送失败,错误代码:", result.retcode);
Sleep(500);
}
}
else
{
Print("OrderSend()失败,错误代码:", GetLastError());
Sleep(500);
}
}
}
//+------------------------------------------------------------------+
//| 动态止损计算 |
//+------------------------------------------------------------------+
double CalculateSL(int signal, double entryPrice, double atr)
{
double baseSL = (signal == 1) ? iLow(_Symbol, _Period, 2)
: iHigh(_Symbol, _Period, 2);
double atrSL = (signal == 1) ? entryPrice - 1.5*atr
: entryPrice + 1.5*atr;
return (signal == 1) ? MathMin(baseSL, atrSL) : MathMax(baseSL, atrSL);
}
//+------------------------------------------------------------------+
//| 精确手数计算 |
//+------------------------------------------------------------------+
double CalculateLotSize(double entry, double sl)
{
double riskAmount = AccountInfoDouble(ACCOUNT_EQUITY) * RiskPerTrade/100;
double riskPoints = MathAbs(entry - sl)/_Point;
double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
if(riskPoints == 0 || tickValue == 0) return 0;
return NormalizeLotSize(riskAmount / (riskPoints * tickValue));
}
//+------------------------------------------------------------------+
//| 辅助函数实现区 |
//+------------------------------------------------------------------+
bool IsNewBar()
{
static datetime lastBar=0;
datetime currentBar=(datetime)SeriesInfoInteger(_Symbol,_Period,SERIES_LASTBAR_DATE);
if(lastBar != currentBar) {
lastBar = currentBar;
return true;
}
return false;
}
bool IsTradingTime()
{
MqlDateTime currentTime;
TimeCurrent(currentTime);
return (currentTime.hour >= TradingStartHour) && (currentTime.hour < TradingEndHour);
}
bool VerifyMarketCondition()
{
int currentSpread=(int)SymbolInfoInteger(_Symbol,SYMBOL_SPREAD);
if(currentSpread > MaxSpread) return false;
return SeriesInfoInteger(_Symbol,_Period,SERIES_SERVER_FIRSTDATE) != 0;
}
double GetDailyRisk()
{
MqlDateTime todayStart;
TimeCurrent(todayStart); // 获取当前时间
todayStart.hour = 0;
todayStart.min = 0;
todayStart.sec = 0;
datetime startTime = StructToTime(todayStart);
double dailyProfit=0;
HistorySelect(startTime, TimeCurrent());
int totalDeals=(int)HistoryDealsTotal();
for(int i=0;i<totalDeals;i++)
{
ulong ticket=HistoryDealGetTicket(i);
if(HistoryDealGetString(ticket,DEAL_SYMBOL)==_Symbol)
dailyProfit+=HistoryDealGetDouble(ticket,DEAL_PROFIT);
}
return (MathAbs(dailyProfit)/AccountInfoDouble(ACCOUNT_EQUITY))*100;
}
double NormalizeLotSize(double lots)
{
double min=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
double max=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX);
double step=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);
lots = MathRound(lots / step) * step;
lots = MathMax(min, MathMin(max, lots));
return NormalizeDouble(lots, 2);
}
- MQL5 Ordersend for Binary Options?
- Errors, bugs, questions
- KARAUL!!! HELP. 4 hours and 45 minutes to go!!!

【新手必看】如何防止机器人误判:讨论代码时请使用代码表述功能
- 2023.06.13
- Sky All
- www.mql5.com
大家好,我是官网版主。 官网内部有机器人辅助管理,目的是自动下架一些有误导性的内容。 内容过长,或同一个IP多次注册,容易导致机器人误判,而被无辜删帖。 如果您被无故删帖,我们对这种体验感到万分抱歉。 为了防止机器人误判,请在讨论代码的时候使用代码表述功能...