//+------------------------------------------------------------------+ //| OrderBlockDetector.mq5| //| Copyright 2023, MetaQuotes Software Corp. | //| https://www.mql5.com| //+------------------------------------------------------------------+ #property strict // // Input Parameters input int ConsolidationPeriod = 20; // Bars for consolidation detection input int AtrPeriod = 14; // ATR period for volatility input double AtrMultiplier = 2.0; // Threshold multiplier (ATR * multiplier) input int VolumeThreshold = 1000; // Minimum volume for breakout input bool RequireRetest = true; // Retest confirmation required? input int VpvrBars = 50; // Bars for VPVR calculation input int TrendCheckPeriod = 30; // Bars for trend structure analysis input int MACDFast = 12; // MACD Fast EMA period input int MACDSlow = 26; // MACD Slow EMA period input int MACDSignal = 9; // MACD Signal period input int RSIPeriod = 14; // RSI period input double RSILevel = 50; // RSI threshold level // Global Variables int ObjectId = 0; string Prefix = "OrderBlock_"; // enum ENUM_X_DIRECTION { X_DIRECTION_NONE, X_DIRECTION_BULISH, X_DIRECTION_BEARISH, }; // int atrHandler = INVALID_HANDLE; double atrBuffer[]; // int rsiHandler = INVALID_HANDLE; double rsiBuffer[]; // int macdHandler = INVALID_HANDLE; double macdMainBuffer[]; double macdSignalBuffer[]; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { // ArraySetAsSeries(atrBuffer, true); atrHandler = iATR(_Symbol, _Period, AtrPeriod); // ArraySetAsSeries(rsiBuffer, true); rsiHandler = iRSI(_Symbol, _Period, RSIPeriod, PRICE_CLOSE); // ArraySetAsSeries(macdMainBuffer, true); ArraySetAsSeries(macdSignalBuffer, true); macdHandler = iMACD(_Symbol, _Period, MACDFast, MACDSlow, MACDSignal, PRICE_CLOSE); // ObjectsDeleteAll(0, Prefix); return (INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { // IndicatorRelease(atrHandler); ObjectsDeleteAll(0, Prefix); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { DetectOrderBlocks(); } //+------------------------------------------------------------------+ //| Detect Order Blocks with ATR Dynamic Threshold | //+------------------------------------------------------------------+ void DetectOrderBlocks() { double high, low, vpvrPrice, atr, dynamicThreshold; datetime startTime, endTime; bool isBullish, isBearish; int bars = Bars(_Symbol, _Period); for (int i = ConsolidationPeriod; i < bars; i++) { // // Get consolidation range high = iHigh(_Symbol, _Period, iHighest(_Symbol, _Period, MODE_HIGH, ConsolidationPeriod, i)); low = iLow(_Symbol, _Period, iLowest(_Symbol, _Period, MODE_LOW, ConsolidationPeriod, i)); double range = high - low; // // Calculate dynamic threshold using ATR CopyBuffer(atrHandler, MAIN_LINE, i, 2, atrBuffer); atr = atrBuffer[0]; dynamicThreshold = atr * AtrMultiplier; // Check if consolidation range is within ATR-based threshold if (range <= dynamicThreshold) { // VPVR Integration vpvrPrice = CalculateVPVR(i, ConsolidationPeriod); bool validVPVR = (vpvrPrice > low && vpvrPrice < high); // Check breakout direction isBullish = iClose(_Symbol, _Period, i - ConsolidationPeriod) > high; isBearish = iClose(_Symbol, _Period, i - ConsolidationPeriod) < low; // Trend Verification ENUM_X_DIRECTION trend = CheckTrendStructure(TrendCheckPeriod); // MACD/RSI Verification bool macdValid = CheckMACD(trend); bool rsiValid = CheckRSI(trend); // Validate all conditions if ((isBullish || isBearish) && validVPVR && (trend != -1) && macdValid && rsiValid) { double breakoutVolume = (double)iVolume(_Symbol, _Period, i - ConsolidationPeriod); if (breakoutVolume < VolumeThreshold) continue; // Define order block time window startTime = iTime(_Symbol, _Period, i); endTime = iTime(_Symbol, _Period, i + ConsolidationPeriod); // Check retest (if required) if (RequireRetest) { bool retestFound = false; for (int j = i - ConsolidationPeriod; j > 0; j--) { if ((isBullish && iLow(_Symbol, _Period, j) <= low && iLow(_Symbol, _Period, j) >= high) || (isBearish && iHigh(_Symbol, _Period, j) >= high && iHigh(_Symbol, _Period, j) <= low)) { retestFound = true; break; } } if (!retestFound) continue; } // Draw order block with ATR annotation string name = Prefix + IntegerToString(ObjectId++); DrawOrderBlock(name, startTime, endTime, low, high, isBullish ? clrGreen : clrRed, vpvrPrice, dynamicThreshold); } } } } //+------------------------------------------------------------------+ //| Trend Detection using Price Structure | //+------------------------------------------------------------------+ ENUM_X_DIRECTION CheckTrendStructure(int period) { int currentStart = 1; int previousStart = period + 1; double currentHigh = iHigh(_Symbol, _Period, iHighest(_Symbol, _Period, MODE_HIGH, period, currentStart)); double previousHigh = iHigh(_Symbol, _Period, iHighest(_Symbol, _Period, MODE_HIGH, period, previousStart)); double currentLow = iLow(_Symbol, _Period, iLowest(_Symbol, _Period, MODE_LOW, period, currentStart)); double previousLow = iLow(_Symbol, _Period, iLowest(_Symbol, _Period, MODE_LOW, period, previousStart)); if (currentHigh > previousHigh && currentLow > previousLow) return (X_DIRECTION_BULISH); // Uptrend else if (currentHigh < previousHigh && currentLow < previousLow) return (X_DIRECTION_BEARISH); // Downtrend else return (X_DIRECTION_NONE); // No clear trend } //+------------------------------------------------------------------+ //| MACD Trend Verification | //+------------------------------------------------------------------+ bool CheckMACD(ENUM_X_DIRECTION trend) { // CopyBuffer(macdHandler, MAIN_LINE, 0, 1, macdMainBuffer); CopyBuffer(macdHandler, SIGNAL_LINE, 0, 1, macdSignalBuffer); double macdMain = macdMainBuffer[0]; double macdSignal = macdSignalBuffer[0]; // if (trend == X_DIRECTION_BULISH) return (macdMain > macdSignal); if (trend == X_DIRECTION_BEARISH) return (macdMain < macdSignal); return (false); } //+------------------------------------------------------------------+ //| RSI Trend Verification | //+------------------------------------------------------------------+ bool CheckRSI(ENUM_X_DIRECTION trend) { // CopyBuffer(rsiHandler, MAIN_LINE, 0, 1, rsiBuffer); double rsiValue = rsiBuffer[0]; // if (trend == X_DIRECTION_BULISH) return (rsiValue > RSILevel); if (trend == X_DIRECTION_BEARISH) return (rsiValue < RSILevel); return (false); } //+------------------------------------------------------------------+ //| Calculate VPVR High Volume Node | //+------------------------------------------------------------------+ double CalculateVPVR(int startIdx, int period) { double maxVolume = 0; double vpvrPrice = 0; double price, volume; for (int i = startIdx; i < startIdx + period; i++) { price = (iHigh(_Symbol, _Period, i) + iLow(_Symbol, _Period, i)) / 2; volume = (double)iVolume(_Symbol, _Period, i); if (volume > maxVolume) { maxVolume = volume; vpvrPrice = price; } } return (vpvrPrice); } //+------------------------------------------------------------------+ //| Draw Order Block with ATR Annotation | //+------------------------------------------------------------------+ void DrawOrderBlock(string name, datetime startTime, datetime endTime, double bottom, double top, color clr, double vpvrPrice, double atrThreshold) { // Draw rectangle ObjectCreate(0, name + "_rect", OBJ_RECTANGLE, 0, startTime, top, endTime, bottom); ObjectSetInteger(0, name + "_rect", OBJPROP_COLOR, clr); ObjectSetInteger(0, name + "_rect", OBJPROP_FILL, true); ObjectSetInteger(0, name + "_rect", OBJPROP_BACK, true); ObjectSetInteger(0, name + "_rect", OBJPROP_WIDTH, 2); // Draw VPVR marker if (vpvrPrice > 0) { ObjectCreate(0, name + "_vpvr", OBJ_HLINE, 0, 0, vpvrPrice); ObjectSetInteger(0, name + "_vpvr", OBJPROP_COLOR, clrYellow); ObjectSetInteger(0, name + "_vpvr", OBJPROP_WIDTH, 1); } // Add ATR threshold label string atrLabel = StringFormat("ATR Threshold: %.5f", atrThreshold); ObjectCreate(0, name + "_atr", OBJ_TEXT, 0, startTime, top); ObjectSetString(0, name + "_atr", OBJPROP_TEXT, atrLabel); ObjectSetInteger(0, name + "_atr", OBJPROP_COLOR, clrWhite); } //+------------------------------------------------------------------+