275 lines
10 KiB
Plaintext
275 lines
10 KiB
Plaintext
//+------------------------------------------------------------------+
|
|
//| 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);
|
|
}
|
|
//+------------------------------------------------------------------+ |