This commit is contained in:
2025-03-07 11:53:51 +03:30
parent 5534bde7e5
commit f050a00b44
5 changed files with 1119 additions and 68 deletions
+418
View File
@@ -0,0 +1,418 @@
//+------------------------------------------------------------------+
//| 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 <Trade/AccountInfo.mqh>
#include <Trade/Trade.mqh>
//
// 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();
}
//+------------------------------------------------------------------+