568 行
37 KiB
MQL5
568 行
37 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| MACD_Scalper_EA_v7.0.mq5 |
|
|
//| MACD Scalper Expert Advisor v7.0 - OPTIMIZED |
|
|
//| Improvements: Trend Filter, Risk Management, Better Signals |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "MACD Scalper Trading - v7.0"
|
|
#property link "https://www.mql5.com"
|
|
#property version "7.00"
|
|
#property strict
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| INPUT PARAMETERS |
|
|
//+------------------------------------------------------------------+
|
|
|
|
//--- MACD INDICATOR
|
|
input int macdFastPeriod = 12; // MACD Fast EMA Period
|
|
input int macdSlowPeriod = 26; // MACD Slow EMA Period
|
|
input int macdSignalPeriod = 9; // MACD Signal Line Period
|
|
|
|
//--- STOCHASTIC INDICATOR (OPTIMIZED)
|
|
input int stochKPeriod = 14; // Stochastic K Period
|
|
input int stochDPeriod = 3; // Stochastic D Period
|
|
input int stochSlowing = 3; // Stochastic Slowing
|
|
input int stochOverbought = 85; // Overbought Level (WAS 80, NOW MORE EXTREME)
|
|
input int stochOversold = 15; // Oversold Level (WAS 20, NOW MORE EXTREME)
|
|
|
|
//--- TREND FILTER (NEW)
|
|
input int emaTrendPeriod = 50; // EMA Trend Confirmation Period
|
|
input double macdHistStrength = 0.0001; // Min MACD Histogram strength
|
|
|
|
//--- MONEY MANAGEMENT (OPTIMIZED)
|
|
input double lotSize = 0.05; // Lot Size (REDUCED from 0.1 for risk management)
|
|
input int slPips = 70; // Stop Loss (pips) (WAS 120, NOW TIGHTER)
|
|
input int tpPips = 150; // Take Profit (pips) (WAS 120, NOW LARGER - 1:2.14 R:R)
|
|
input int maxDailyLoss = 500; // Max Daily Loss in USD (NEW)
|
|
|
|
//--- FILTERS
|
|
input int maxSpread = 20; // Maximum Spread (pips)
|
|
input int maxSlippage = 15; // Maximum Slippage (pips)
|
|
input ulong magicNumber = 12347; // Magic Number (UPDATED for v7.0)
|
|
|
|
//--- INDICATOR INITIALIZATION
|
|
input int minBarsForMACD = 35; // Minimum bars for MACD
|
|
input int minBarsForStoch = 20; // Minimum bars for Stochastic
|
|
input int minBarsForEMA = 55; // Minimum bars for EMA
|
|
|
|
//--- TRADING HOURS FILTER (NEW)
|
|
input int startHour = 2; // Start trading hour (London open)
|
|
input int endHour = 22; // End trading hour
|
|
input bool useTradingHours = true; // Enable trading hours filter
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| GLOBAL VARIABLES |
|
|
//+------------------------------------------------------------------+
|
|
|
|
int macdHandle = INVALID_HANDLE; // MACD Indicator Handle
|
|
int stochHandle = INVALID_HANDLE; // Stochastic Indicator Handle
|
|
int emaHandle = INVALID_HANDLE; // EMA Trend Indicator Handle (NEW)
|
|
int atrHandle = INVALID_HANDLE; // ATR Volatility Handle (NEW)
|
|
|
|
double macdMain[3]; // MACD Main Line (Buffer 0)
|
|
double macdSignal[3]; // MACD Signal Line (Buffer 1)
|
|
double macdHist[3]; // MACD Histogram (Manual: Main - Signal)
|
|
double stochK[3]; // Stochastic K Buffer (3 bars)
|
|
double emaTrend[2]; // EMA Trend (2 bars) (NEW)
|
|
double atrValue[2]; // ATR Value (2 bars) (NEW)
|
|
|
|
bool isInitialized = false; // Initialization Flag
|
|
bool indicatorsReady = false; // Indicators Ready Flag
|
|
int tradeCount = 0; // Total trades opened
|
|
double dailyProfit = 0; // Daily Profit Tracker (NEW)
|
|
datetime lastDayReset = 0; // Last daily reset time (NEW)
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| HELPER FUNCTIONS |
|
|
//+------------------------------------------------------------------+
|
|
|
|
/// Get current Bid price
|
|
double GetBid()
|
|
{
|
|
return SymbolInfoDouble(Symbol(), SYMBOL_BID);
|
|
}
|
|
|
|
/// Get current Ask price
|
|
double GetAsk()
|
|
{
|
|
return SymbolInfoDouble(Symbol(), SYMBOL_ASK);
|
|
}
|
|
|
|
/// Get current Spread in pips
|
|
int GetSpread()
|
|
{
|
|
return (int)((GetAsk() - GetBid()) / Point());
|
|
}
|
|
|
|
/// Check if spread is acceptable
|
|
bool IsSpreadOK()
|
|
{
|
|
return GetSpread() <= maxSpread;
|
|
}
|
|
|
|
/// Check if trading within allowed hours (NEW) - FIXED
|
|
bool IsTradingHours()
|
|
{
|
|
if(!useTradingHours)
|
|
return true;
|
|
|
|
datetime currentTime = TimeCurrent();
|
|
MqlDateTime timeStruct;
|
|
TimeToStruct(currentTime, timeStruct);
|
|
|
|
int hour = timeStruct.hour;
|
|
return (hour >= startHour && hour < endHour);
|
|
}
|
|
|
|
/// Update daily profit tracker (NEW) - FIXED
|
|
void UpdateDailyProfit()
|
|
{
|
|
datetime currentTime = TimeCurrent();
|
|
MqlDateTime timeStruct;
|
|
TimeToStruct(currentTime, timeStruct);
|
|
|
|
// Get start of day (00:00:00)
|
|
datetime dayStart = currentTime - (timeStruct.hour * 3600 + timeStruct.min * 60 + timeStruct.sec);
|
|
|
|
if(lastDayReset != dayStart)
|
|
{
|
|
lastDayReset = dayStart;
|
|
dailyProfit = 0;
|
|
Print("✓ Daily profit reset: ", TimeToString(currentTime));
|
|
}
|
|
|
|
// Calculate current day P&L from all positions
|
|
dailyProfit = 0;
|
|
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
|
{
|
|
if(!PositionGetTicket(i)) continue;
|
|
if(PositionGetString(POSITION_SYMBOL) == Symbol() &&
|
|
PositionGetInteger(POSITION_MAGIC) == magicNumber)
|
|
{
|
|
double profit = PositionGetDouble(POSITION_PROFIT);
|
|
dailyProfit += profit;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Check daily loss limit (NEW)
|
|
bool IsDailyLossOK()
|
|
{
|
|
UpdateDailyProfit();
|
|
|
|
if(dailyProfit < -maxDailyLoss)
|
|
{
|
|
Print("⚠️ Daily loss limit reached: ", DoubleToString(dailyProfit, 2), " USD");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| INDICATOR UPDATE FUNCTION |
|
|
//+------------------------------------------------------------------+
|
|
|
|
/// Update indicator buffers - v7.0 with all filters
|
|
bool UpdateIndicators()
|
|
{
|
|
// Check handles validity
|
|
if(macdHandle == INVALID_HANDLE || stochHandle == INVALID_HANDLE ||
|
|
emaHandle == INVALID_HANDLE || atrHandle == INVALID_HANDLE)
|
|
return false;
|
|
|
|
// Check if indicators are calculated
|
|
if(BarsCalculated(macdHandle) < minBarsForMACD ||
|
|
BarsCalculated(stochHandle) < minBarsForStoch ||
|
|
BarsCalculated(emaHandle) < minBarsForEMA ||
|
|
BarsCalculated(atrHandle) < minBarsForEMA)
|
|
return false;
|
|
|
|
// Copy MACD Main Line (Buffer 0) - 3 bars
|
|
if(CopyBuffer(macdHandle, 0, 0, 3, macdMain) < 3)
|
|
return false;
|
|
|
|
// Copy MACD Signal Line (Buffer 1) - 3 bars
|
|
if(CopyBuffer(macdHandle, 1, 0, 3, macdSignal) < 3)
|
|
return false;
|
|
|
|
// Calculate MACD Histogram MANUALLY (Main - Signal)
|
|
for(int i = 0; i < 3; i++)
|
|
{
|
|
macdHist[i] = macdMain[i] - macdSignal[i];
|
|
}
|
|
|
|
// Copy Stochastic K (Buffer 0) - 3 bars
|
|
if(CopyBuffer(stochHandle, 0, 0, 3, stochK) < 3)
|
|
return false;
|
|
|
|
// Copy EMA Trend (Buffer 0) - 2 bars (NEW)
|
|
if(CopyBuffer(emaHandle, 0, 0, 2, emaTrend) < 2)
|
|
return false;
|
|
|
|
// Copy ATR Value (Buffer 0) - 2 bars (NEW)
|
|
if(CopyBuffer(atrHandle, 0, 0, 2, atrValue) < 2)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| SIGNAL CHECKING FUNCTIONS |
|
|
//+------------------------------------------------------------------+
|
|
|
|
/// Check for BUY signal (Enhanced with trend filter + volatility)
|
|
bool CheckBuySignal()
|
|
{
|
|
// FILTER 1: Trading hours check (NEW)
|
|
if(!IsTradingHours())
|
|
return false;
|
|
|
|
// FILTER 2: Daily loss limit (NEW)
|
|
if(!IsDailyLossOK())
|
|
return false;
|
|
|
|
// FILTER 3: Spread check
|
|
if(!IsSpreadOK())
|
|
return false;
|
|
|
|
// FILTER 4: Trend confirmation - Price above EMA50 (NEW)
|
|
double bid = GetBid();
|
|
if(bid <= emaTrend[1])
|
|
return false; // Not in uptrend
|
|
|
|
// FILTER 5: MACD Momentum strength check (NEW)
|
|
double macdHistAbs = MathAbs(macdHist[1]);
|
|
if(macdHistAbs < macdHistStrength)
|
|
return false; // Momentum too weak
|
|
|
|
// FILTER 6: MACD Momentum: crossed below zero → above zero
|
|
if(!(macdHist[2] <= 0 && macdHist[1] > 0))
|
|
return false;
|
|
|
|
// FILTER 7: Stochastic: in oversold area AND rising (OPTIMIZED)
|
|
// Now uses stricter levels: oversold < 15
|
|
if(!(stochK[2] < stochOversold && stochK[1] > stochK[2]))
|
|
return false; // Stoch not rising from extreme oversold
|
|
|
|
// FILTER 8: Volatility check - ATR sanity (NEW)
|
|
// Only trade if volatility is reasonable
|
|
if(atrValue[1] < 0.0005 * GetAsk())
|
|
return false; // Too low volatility
|
|
|
|
return true;
|
|
}
|
|
|
|
/// Check for SELL signal (Enhanced with trend filter + volatility)
|
|
bool CheckSellSignal()
|
|
{
|
|
// FILTER 1: Trading hours check (NEW)
|
|
if(!IsTradingHours())
|
|
return false;
|
|
|
|
// FILTER 2: Daily loss limit (NEW)
|
|
if(!IsDailyLossOK())
|
|
return false;
|
|
|
|
// FILTER 3: Spread check
|
|
if(!IsSpreadOK())
|
|
return false;
|
|
|
|
// FILTER 4: Trend confirmation - Price below EMA50 (NEW)
|
|
double ask = GetAsk();
|
|
if(ask >= emaTrend[1])
|
|
return false; // Not in downtrend
|
|
|
|
// FILTER 5: MACD Momentum strength check (NEW)
|
|
double macdHistAbs = MathAbs(macdHist[1]);
|
|
if(macdHistAbs < macdHistStrength)
|
|
return false; // Momentum too weak
|
|
|
|
// FILTER 6: MACD Momentum: crossed above zero → below zero
|
|
if(!(macdHist[2] >= 0 && macdHist[1] < 0))
|
|
return false;
|
|
|
|
// FILTER 7: Stochastic: in overbought area AND falling (OPTIMIZED)
|
|
// Now uses stricter levels: overbought > 85
|
|
if(!(stochK[2] > stochOverbought && stochK[1] < stochK[2]))
|
|
return false; // Stoch not falling from extreme overbought
|
|
|
|
// FILTER 8: Volatility check - ATR sanity (NEW)
|
|
if(atrValue[1] < 0.0005 * GetAsk())
|
|
return false; // Too low volatility
|
|
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| ORDER FUNCTIONS |
|
|
//+------------------------------------------------------------------+
|
|
|
|
/// Check if position TP is reached
|
|
bool IsTPReached()
|
|
{
|
|
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
|
{
|
|
if(!PositionGetTicket(i)) continue;
|
|
if(PositionGetString(POSITION_SYMBOL) != Symbol() ||
|
|
PositionGetInteger(POSITION_MAGIC) != magicNumber) continue;
|
|
|
|
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
|
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
|
|
double currentPrice = (posType == POSITION_TYPE_BUY) ? GetBid() : GetAsk();
|
|
|
|
if(posType == POSITION_TYPE_BUY)
|
|
{
|
|
if(currentPrice >= openPrice + (tpPips * Point()))
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
if(currentPrice <= openPrice - (tpPips * Point()))
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// Close all positions
|
|
void CloseAllPositions()
|
|
{
|
|
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
|
{
|
|
if(!PositionGetTicket(i)) continue;
|
|
if(PositionGetString(POSITION_SYMBOL) != Symbol() ||
|
|
PositionGetInteger(POSITION_MAGIC) != magicNumber) continue;
|
|
|
|
ulong ticket = PositionGetInteger(POSITION_TICKET);
|
|
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
|
|
double closingProfit = PositionGetDouble(POSITION_PROFIT);
|
|
|
|
MqlTradeRequest request = {};
|
|
MqlTradeResult result = {};
|
|
|
|
request.action = TRADE_ACTION_DEAL;
|
|
request.symbol = Symbol();
|
|
request.type = (posType == POSITION_TYPE_BUY) ? ORDER_TYPE_SELL : ORDER_TYPE_BUY;
|
|
request.position = ticket;
|
|
request.deviation = maxSlippage;
|
|
request.comment = "Close by TP";
|
|
request.type_filling = ORDER_FILLING_IOC;
|
|
|
|
if(!OrderSend(request, result))
|
|
{
|
|
Print("❌ Failed to close position: ", GetLastError());
|
|
}
|
|
else
|
|
{
|
|
Print("✓ Position closed with profit: ", DoubleToString(closingProfit, 2), " USD");
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Open BUY order
|
|
void OpenBuyOrder()
|
|
{
|
|
if(!IsSpreadOK())
|
|
return;
|
|
|
|
double ask = GetAsk();
|
|
double sl = ask - (slPips * Point());
|
|
double tp = ask + (tpPips * Point());
|
|
|
|
MqlTradeRequest request = {};
|
|
MqlTradeResult result = {};
|
|
|
|
request.action = TRADE_ACTION_DEAL;
|
|
request.type = ORDER_TYPE_BUY;
|
|
request.symbol = Symbol();
|
|
request.volume = lotSize;
|
|
request.price = ask;
|
|
request.sl = sl;
|
|
request.tp = tp;
|
|
request.deviation = maxSlippage;
|
|
request.magic = magicNumber;
|
|
request.comment = "MACD Scalper v7.0 BUY";
|
|
request.type_filling = ORDER_FILLING_IOC;
|
|
|
|
if(OrderSend(request, result))
|
|
{
|
|
tradeCount++;
|
|
Print("✓ BUY #", tradeCount, " @ ", DoubleToString(ask, Digits()),
|
|
" SL=", DoubleToString(sl, Digits()), " TP=", DoubleToString(tp, Digits()),
|
|
" R:R=1:", DoubleToString((double)tpPips / (double)slPips, 2));
|
|
}
|
|
else
|
|
{
|
|
Print("❌ Failed to open BUY: ", GetLastError());
|
|
}
|
|
}
|
|
|
|
/// Open SELL order
|
|
void OpenSellOrder()
|
|
{
|
|
if(!IsSpreadOK())
|
|
return;
|
|
|
|
double bid = GetBid();
|
|
double sl = bid + (slPips * Point());
|
|
double tp = bid - (tpPips * Point());
|
|
|
|
MqlTradeRequest request = {};
|
|
MqlTradeResult result = {};
|
|
|
|
request.action = TRADE_ACTION_DEAL;
|
|
request.type = ORDER_TYPE_SELL;
|
|
request.symbol = Symbol();
|
|
request.volume = lotSize;
|
|
request.price = bid;
|
|
request.sl = sl;
|
|
request.tp = tp;
|
|
request.deviation = maxSlippage;
|
|
request.magic = magicNumber;
|
|
request.comment = "MACD Scalper v7.0 SELL";
|
|
request.type_filling = ORDER_FILLING_IOC;
|
|
|
|
if(OrderSend(request, result))
|
|
{
|
|
tradeCount++;
|
|
Print("✓ SELL #", tradeCount, " @ ", DoubleToString(bid, Digits()),
|
|
" SL=", DoubleToString(sl, Digits()), " TP=", DoubleToString(tp, Digits()),
|
|
" R:R=1:", DoubleToString((double)tpPips / (double)slPips, 2));
|
|
}
|
|
else
|
|
{
|
|
Print("❌ Failed to open SELL: ", GetLastError());
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| INITIALIZATION FUNCTION |
|
|
//+------------------------------------------------------------------+
|
|
|
|
int OnInit()
|
|
{
|
|
// Create MACD indicator
|
|
macdHandle = iMACD(Symbol(), Period(), macdFastPeriod, macdSlowPeriod,
|
|
macdSignalPeriod, PRICE_CLOSE);
|
|
if(macdHandle == INVALID_HANDLE)
|
|
{
|
|
Print("❌ Error creating MACD");
|
|
return INIT_FAILED;
|
|
}
|
|
|
|
// Create Stochastic indicator
|
|
stochHandle = iStochastic(Symbol(), Period(), stochKPeriod, stochDPeriod,
|
|
stochSlowing, MODE_SMA, STO_LOWHIGH);
|
|
if(stochHandle == INVALID_HANDLE)
|
|
{
|
|
Print("❌ Error creating Stochastic");
|
|
return INIT_FAILED;
|
|
}
|
|
|
|
// Create EMA Trend indicator (NEW)
|
|
emaHandle = iMA(Symbol(), Period(), emaTrendPeriod, 0, MODE_EMA, PRICE_CLOSE);
|
|
if(emaHandle == INVALID_HANDLE)
|
|
{
|
|
Print("❌ Error creating EMA");
|
|
return INIT_FAILED;
|
|
}
|
|
|
|
// Create ATR indicator (NEW)
|
|
atrHandle = iATR(Symbol(), Period(), 14);
|
|
if(atrHandle == INVALID_HANDLE)
|
|
{
|
|
Print("❌ Error creating ATR");
|
|
return INIT_FAILED;
|
|
}
|
|
|
|
// Set arrays as series
|
|
ArraySetAsSeries(macdMain, true);
|
|
ArraySetAsSeries(macdSignal, true);
|
|
ArraySetAsSeries(macdHist, true);
|
|
ArraySetAsSeries(stochK, true);
|
|
ArraySetAsSeries(emaTrend, true);
|
|
ArraySetAsSeries(atrValue, true);
|
|
|
|
isInitialized = true;
|
|
Print("✓ EA v7.0 Initialized Successfully!");
|
|
Print("✓ Improvements: EMA Trend, ATR Volatility, Daily Loss Limit");
|
|
Print("✓ Optimized Stoch Levels: Oversold=", stochOversold, " Overbought=", stochOverbought);
|
|
Print("✓ Better R:R Ratio: 1:", DoubleToString((double)tpPips / (double)slPips, 2));
|
|
|
|
return INIT_SUCCEEDED;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| DEINITIALIZATION FUNCTION |
|
|
//+------------------------------------------------------------------+
|
|
|
|
void OnDeinit(const int reason)
|
|
{
|
|
// Release indicator handles
|
|
if(macdHandle != INVALID_HANDLE)
|
|
IndicatorRelease(macdHandle);
|
|
if(stochHandle != INVALID_HANDLE)
|
|
IndicatorRelease(stochHandle);
|
|
if(emaHandle != INVALID_HANDLE)
|
|
IndicatorRelease(emaHandle);
|
|
if(atrHandle != INVALID_HANDLE)
|
|
IndicatorRelease(atrHandle);
|
|
|
|
Print("✓ EA v7.0 Deinitialized");
|
|
Print("✓ Total trades: ", tradeCount);
|
|
Print("✓ Final daily profit: ", DoubleToString(dailyProfit, 2), " USD");
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| MAIN TRADING LOOP |
|
|
//+------------------------------------------------------------------+
|
|
|
|
void OnTick()
|
|
{
|
|
if(!isInitialized)
|
|
return;
|
|
|
|
// Update indicators
|
|
if(!UpdateIndicators())
|
|
{
|
|
if(!indicatorsReady)
|
|
return;
|
|
}
|
|
else if(!indicatorsReady)
|
|
{
|
|
indicatorsReady = true;
|
|
Print("✓ Indicators ready! Starting to trade...");
|
|
}
|
|
|
|
if(!indicatorsReady)
|
|
return;
|
|
|
|
// Check if position exists
|
|
bool hasPosition = false;
|
|
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
|
{
|
|
if(!PositionGetTicket(i)) continue;
|
|
if(PositionGetString(POSITION_SYMBOL) == Symbol() &&
|
|
PositionGetInteger(POSITION_MAGIC) == magicNumber)
|
|
{
|
|
hasPosition = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Close position if TP reached
|
|
if(hasPosition && IsTPReached())
|
|
CloseAllPositions();
|
|
|
|
// Check entry signals (only if no position)
|
|
if(!hasPosition)
|
|
{
|
|
if(CheckBuySignal())
|
|
OpenBuyOrder();
|
|
else if(CheckSellSignal())
|
|
OpenSellOrder();
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| END OF EXPERT ADVISOR v7.0 - OPTIMIZED & IMPROVED |
|
|
//+------------------------------------------------------------------+
|