ICTLibraryEasy/Examples/Benchmark/OtherCode/Code7.mq5
2026-05-25 11:41:30 -05:00

208 lines
7.2 KiB
MQL5

//+------------------------------------------------------------------+
//| EA_FVG_Scanner.mq5 |
//| Copyright 2026, MetaQuotes Ltd. |
//+------------------------------------------------------------------+
#property copyright "Open Source"
#property version "1.00"
//--- Input Parameters for the Scanner Engine
input int InpHistoryDepth = 100; // Historical Bars to Evaluate
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
#include "..\\Utils\\MetricSaver.mqh"
//+------------------------------------------------------------------+
//| Class: CFVGScanner |
//| Purpose: Detects, draws, and manages Fair Value Gaps |
//+------------------------------------------------------------------+
class CFVGScanner
{
private:
string m_symbol; // Target symbol for the scanner
ENUM_TIMEFRAMES m_timeframe; // Target timeframe
int m_history_bars; // Depth of historical scan
string m_obj_prefix; // Prefix for graphical objects
color m_color_bullish; // Color for bullish imbalances
color m_color_bearish; // Color for bearish imbalances
void DrawRectangle(string name, datetime time1, double price1, datetime time2, double price2, color clr);
void ClearOldObjects(void);
public:
CFVGScanner(string symbol, ENUM_TIMEFRAMES tf, int depth);
~CFVGScanner(void);
void ScanAndDraw(void);
void SetColors(color bull, color bear);
};
//+------------------------------------------------------------------+
//| Constructor: Initializes the environment and routing variables |
//+------------------------------------------------------------------+
CFVGScanner::CFVGScanner(string symbol, ENUM_TIMEFRAMES tf, int depth)
{
m_symbol = (symbol == "") ? _Symbol : symbol;
m_timeframe = tf;
m_history_bars = (depth < 10) ? 10 : depth;
m_obj_prefix = "FVG_" + m_symbol + "_" + EnumToString(m_timeframe) + "_";
m_color_bullish = clrDarkGreen;
m_color_bearish = clrMaroon;
}
//+------------------------------------------------------------------+
//| Destructor: Systematic cleanup on terminal shutdown |
//+------------------------------------------------------------------+
CFVGScanner::~CFVGScanner(void)
{
ClearOldObjects();
}
//+------------------------------------------------------------------+
//| Core Engine: Extracts data, evaluates geometry, and filters voids|
//+------------------------------------------------------------------+
void CFVGScanner::ScanAndDraw(void)
{
MqlRates rates[];
ArraySetAsSeries(rates, true);
if(CopyRates(m_symbol, m_timeframe, 0, m_history_bars, rates) < m_history_bars)
{
PrintFormat("Warning: Failed to synchronize %s history for FVG scanner.", m_symbol);
return;
}
ClearOldObjects();
for(int i = m_history_bars - 1; i >= 3; i--)
{
double origin_high = rates[i].high;
double origin_low = rates[i].low;
double confirm_high = rates[i - 2].high;
double confirm_low = rates[i - 2].low;
bool is_bullish_fvg = (origin_high < confirm_low);
bool is_bearish_fvg = (origin_low > confirm_high);
if(is_bullish_fvg)
{
bool is_mitigated = false;
for(int j = i - 3; j >= 1; j--)
{
if(rates[j].low <= origin_high)
{ is_mitigated = true; break; }
}
if(!is_mitigated)
{
string name = m_obj_prefix + "BULL_" + IntegerToString(i);
DrawRectangle(name, rates[i].time, confirm_low, rates[1].time, origin_high, m_color_bullish);
}
}
if(is_bearish_fvg)
{
bool is_mitigated = false;
for(int j = i - 3; j >= 1; j--)
{
if(rates[j].high >= origin_low)
{ is_mitigated = true; break; }
}
if(!is_mitigated)
{
string name = m_obj_prefix + "BEAR_" + IntegerToString(i);
DrawRectangle(name, rates[i].time, origin_low, rates[1].time, confirm_high, m_color_bearish);
}
}
}
}
//+------------------------------------------------------------------+
//| Renders the institutional imbalance zone on the chart canvas |
//+------------------------------------------------------------------+
void CFVGScanner::DrawRectangle(string name, datetime time1, double price1, datetime time2, double price2, color clr)
{
if(ObjectFind(0, name) < 0)
{
ObjectCreate(0, name, OBJ_RECTANGLE, 0, time1, price1, time2, price2);
ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_SOLID);
ObjectSetInteger(0, name, OBJPROP_WIDTH, 1);
ObjectSetInteger(0, name, OBJPROP_BACK, false);
ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
}
else
{
ObjectSetInteger(0, name, OBJPROP_TIME, 1, time2);
}
}
//+------------------------------------------------------------------+
//| Prevents memory leaks by purging outdated graphical objects |
//+------------------------------------------------------------------+
void CFVGScanner::ClearOldObjects(void)
{
ObjectsDeleteAll(0, m_obj_prefix);
}
//+------------------------------------------------------------------+
//| Public method to allow developers to customize the visual output |
//+------------------------------------------------------------------+
void CFVGScanner::SetColors(color bull, color bear)
{
m_color_bullish = bull;
m_color_bearish = bear;
}
//--- Global Pointer to the encapsulated scanner object
CFVGScanner *g_fvg_engine;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
CMetricsSave::Start(FILE_CODE7);
g_fvg_engine = new CFVGScanner(_Symbol, PERIOD_CURRENT, InpHistoryDepth);
g_fvg_engine.SetColors(clrLimeGreen, clrRed);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
if(CheckPointer(g_fvg_engine) == POINTER_DYNAMIC)
{
delete g_fvg_engine;
}
CMetricsSave::Destroy();
}
//+------------------------------------------------------------------+
//| Expert tick function with strict CPU optimization |
//+------------------------------------------------------------------+
void OnTick()
{
static datetime last_bar_time = 0;
datetime current_bar_time = iTime(_Symbol, PERIOD_CURRENT, 0);
if(current_bar_time != last_bar_time)
{
last_bar_time = current_bar_time;
if(CheckPointer(g_fvg_engine) != POINTER_INVALID)
{
g_fvg_engine.ScanAndDraw();
}
}
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+