//+------------------------------------------------------------------+ //| SMC_OrderBlock_EA.mq5| //| Copyright 2023, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Software Corp." #property link "https://www.mql5.com" #property version "1.00" #property strict #include #include // // Input parameters input ENUM_TIMEFRAMES TimeFrame = PERIOD_M15; // Timeframe for analysis input double RiskPercent = 1.0; // Risk per trade (1-2%) input int ATR_Period = 14; // ATR period for volatility input int OrderBlockLength = 20; // Bars for consolidation input int ConfirmationCandles = 3; // Candles to confirm breakout input double StopLossMultiplier = 1.5; // Stop loss buffer input double TakeProfitRatio = 2.0; // Risk:Reward ratio input int TrailingStopPips = 50; // Trailing stop in pips // CTrade trade; CAccountInfo accountInfo; // double Ask = 0; double Bid = 0; // // Order Block structure struct OrderBlock { datetime startTime; double high; double low; }; // int atrHandler = INVALID_HANDLE; int maFastHandler = INVALID_HANDLE; int maSlowHandler = INVALID_HANDLE; // double atrs[]; double fastMAs[]; double slowMAs[]; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { // trade.SetExpertMagicNumber(123456); // Unique magic number // atrHandler = iATR(_Symbol, TimeFrame, ATR_Period); maFastHandler = iMA(_Symbol, TimeFrame, 20, 0, MODE_SMA, PRICE_CLOSE); maSlowHandler = iMA(_Symbol, TimeFrame, 50, 0, MODE_SMA, PRICE_CLOSE); // bool isValid = atrHandler != INVALID_HANDLE && maFastHandler != INVALID_HANDLE && maSlowHandler != INVALID_HANDLE; if (!isValid) { return (INIT_FAILED); } // return (INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { // // Cleanup code if needed ... IndicatorRelease(atrHandler); IndicatorRelease(maFastHandler); IndicatorRelease(maSlowHandler); // ZeroMemory(atrs); ZeroMemory(fastMAs); ZeroMemory(slowMAs); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { // Avoid multiple orders if (CheckOpenOrders()) return; // CopyBuffer(atrHandler, MAIN_LINE, 0, 200, atrs); // CopyBuffer(maFastHandler, MAIN_LINE, 0, 2, fastMAs); CopyBuffer(maSlowHandler, MAIN_LINE, 0, 2, slowMAs); // Ask = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK), _Digits); // Get the Ask Price Bid = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID), _Digits); // Get the Bid Price // // Check for trend and execute trades if (IsUptrend()) { OrderBlock block = FindBullishOrderBlock(); if (block.startTime != 0 && IsPriceInBlock(block)) { if (ConfirmBullishEntry()) ExecuteTrade(block, ORDER_TYPE_BUY); } } else if (IsDowntrend()) { OrderBlock block = FindBearishOrderBlock(); if (block.startTime != 0 && IsPriceInBlock(block)) { if (ConfirmBearishEntry()) ExecuteTrade(block, ORDER_TYPE_SELL); } } // Manage trailing stops TrailStop(); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Check if price is within the order block | //+------------------------------------------------------------------+ bool IsPriceInBlock(OrderBlock &block) { double currentPrice = (Ask + Bid) / 2; // Mid-price return (currentPrice >= block.low && currentPrice <= block.high); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Detect uptrend using moving averages | //+------------------------------------------------------------------+ bool IsUptrend() { // double maFast = fastMAs[0]; double maSlow = slowMAs[0]; // return (maFast > maSlow); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Detect downtrend using moving averages | //+------------------------------------------------------------------+ bool IsDowntrend() { // double maFast = fastMAs[0]; double maSlow = slowMAs[0]; // return (maFast < maSlow); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Find bullish order blocks | //+------------------------------------------------------------------+ OrderBlock FindBullishOrderBlock() { // OrderBlock block; block.startTime = 0; // for (int i = 1; i < 100; i++) { double prevHigh = iHigh(NULL, TimeFrame, i); double prevLow = iLow(NULL, TimeFrame, i); double prevClose = iClose(NULL, TimeFrame, i); double prevOpen = iOpen(NULL, TimeFrame, i); double atr = atrs[i]; if (prevClose - prevOpen > 1.5 * atr) { // Strong bullish candle double consolidationHigh = prevHigh; double consolidationLow = prevLow; bool isConsolidation = true; for (int j = 1; j <= OrderBlockLength; j++) { double newHigh = iHigh(NULL, TimeFrame, i - j); double newLow = iLow(NULL, TimeFrame, i - j); consolidationHigh = MathMax(consolidationHigh, newHigh); consolidationLow = MathMin(consolidationLow, newLow); if ((consolidationHigh - consolidationLow) > 0.5 * atr) { isConsolidation = false; break; } } if (isConsolidation) { block.high = consolidationHigh; block.low = consolidationLow; block.startTime = iTime(NULL, TimeFrame, i); return block; } } } return block; } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Find bearish order blocks | //+------------------------------------------------------------------+ OrderBlock FindBearishOrderBlock() { // OrderBlock block; block.startTime = 0; // for (int i = 1; i < 100; i++) { double prevHigh = iHigh(NULL, TimeFrame, i); double prevLow = iLow(NULL, TimeFrame, i); double prevClose = iClose(NULL, TimeFrame, i); double prevOpen = iOpen(NULL, TimeFrame, i); double atr = atrs[i]; if (prevOpen - prevClose > 1.5 * atr) { // Strong bearish candle double consolidationHigh = prevHigh; double consolidationLow = prevLow; bool isConsolidation = true; for (int j = 1; j <= OrderBlockLength; j++) { double newHigh = iHigh(NULL, TimeFrame, i - j); double newLow = iLow(NULL, TimeFrame, i - j); consolidationHigh = MathMax(consolidationHigh, newHigh); consolidationLow = MathMin(consolidationLow, newLow); if ((consolidationHigh - consolidationLow) > 0.5 * atr) { isConsolidation = false; break; } } if (isConsolidation) { block.high = consolidationHigh; block.low = consolidationLow; block.startTime = iTime(NULL, TimeFrame, i); return block; } } } return block; } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Confirm bullish entry with candle pattern | //+------------------------------------------------------------------+ bool ConfirmBullishEntry() { // int shift = iBarShift(NULL, TimeFrame, TimeCurrent()); double prevLow = iLow(NULL, TimeFrame, shift + 1); double currentClose = iClose(NULL, TimeFrame, shift); return (currentClose > prevLow && iOpen(NULL, TimeFrame, shift) < currentClose); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Confirm bearish entry with candle pattern | //+------------------------------------------------------------------+ bool ConfirmBearishEntry() { // int shift = iBarShift(NULL, TimeFrame, TimeCurrent()); double prevHigh = iHigh(NULL, TimeFrame, shift + 1); double currentClose = iClose(NULL, TimeFrame, shift); return (currentClose < prevHigh && iOpen(NULL, TimeFrame, shift) > currentClose); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Execute trade with risk management | //+------------------------------------------------------------------+ void ExecuteTrade(OrderBlock &block, ENUM_ORDER_TYPE orderType) { // double atr = atrs[0]; double stopLoss, takeProfit, lotSize; double entryPrice = (orderType == ORDER_TYPE_BUY) ? Ask : Bid; // Calculate stop loss and take profit if (orderType == ORDER_TYPE_BUY) { stopLoss = block.low - StopLossMultiplier * atr; takeProfit = entryPrice + (entryPrice - stopLoss) * TakeProfitRatio; } else { stopLoss = block.high + StopLossMultiplier * atr; takeProfit = entryPrice - (stopLoss - entryPrice) * TakeProfitRatio; } // Calculate lot size based on risk lotSize = CalculateLotSize(stopLoss, entryPrice, orderType); if (lotSize <= 0) return; // Place order if (orderType == ORDER_TYPE_BUY) { trade.Buy(lotSize, _Symbol, entryPrice, stopLoss, takeProfit, "SMC Bullish Order Block"); } else { trade.Sell(lotSize, _Symbol, entryPrice, stopLoss, takeProfit, "SMC Bearish Order Block"); } } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Calculate lot size based on risk per trade | //+------------------------------------------------------------------+ double CalculateLotSize(double stopLoss, double entryPrice, ENUM_ORDER_TYPE orderType) { double riskAmount = AccountBalance() * RiskPercent / 100; double stopLossPips = MathAbs((entryPrice - stopLoss) / SymbolInfoDouble(_Symbol, SYMBOL_POINT)); if (stopLossPips == 0) return 0; double pipValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE); double lotSize = riskAmount / (stopLossPips * pipValue); lotSize = NormalizeDouble(lotSize, 2); // Adjust to symbol's lot precision return MathMax(lotSize, SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN)); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Check for existing open orders | //+------------------------------------------------------------------+ bool CheckOpenOrders() { for (int i = 0; i < PositionsTotal(); i++) { if (PositionGetSymbol(i) == _Symbol) return true; } return false; } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Trailing stop logic | //+------------------------------------------------------------------+ void TrailStop() { for (int i = 0; i < PositionsTotal(); i++) { if (PositionGetSymbol(i) != _Symbol) continue; ulong ticket = PositionGetInteger(POSITION_TICKET); ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); double currentPrice = (type == POSITION_TYPE_BUY) ? Bid : Ask; double openPrice = PositionGetDouble(POSITION_PRICE_OPEN); double stopLoss = PositionGetDouble(POSITION_SL); double trailingStopPrice = (type == POSITION_TYPE_BUY) ? currentPrice - TrailingStopPips * SymbolInfoDouble(_Symbol, SYMBOL_POINT) : currentPrice + TrailingStopPips * SymbolInfoDouble(_Symbol, SYMBOL_POINT); // Update stop loss if price moves favorably if ((type == POSITION_TYPE_BUY && trailingStopPrice > stopLoss) || (type == POSITION_TYPE_SELL && trailingStopPrice < stopLoss)) { trade.PositionModify(ticket, trailingStopPrice, PositionGetDouble(POSITION_TP)); } } } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Calculate Account Balance | //+------------------------------------------------------------------+ double AccountBalance() { return accountInfo.Balance(); } //+------------------------------------------------------------------+