//+------------------------------------------------------------------+
//|                                               Ind_OrderBlock.mq5 |
//|                                  Copyright 2026, MetaQuotes Ltd. |
//+------------------------------------------------------------------+
#property copyright "Open Source"
#property version   "1.02"
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots   2

#property indicator_label1  "Bullish OB"
#property indicator_type1   DRAW_ARROW
#property indicator_color1  clrMediumSeaGreen

#property indicator_label2  "Bearish OB"
#property indicator_type2   DRAW_ARROW
#property indicator_color2  clrCrimson

#include <OrderBlockEngine\OrderBlock_Engine.mqh>

//--- Buffers and Engine
double             BufferBull[];
double             BufferBear[];
COrderBlockEngine *g_ob_engine;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
//--- Bind data array series to terminal drawing layer
   SetIndexBuffer(0, BufferBull, INDICATOR_DATA);
   SetIndexBuffer(1, BufferBear, INDICATOR_DATA);
   
//--- Set bullet dot characters for isolated pattern visualization
   PlotIndexSetInteger(0, PLOT_ARROW, 159);
   PlotIndexSetInteger(1, PLOT_ARROW, 159);
   
//--- Increase size of the dots so they are clearly visible on light backgrounds
   PlotIndexSetInteger(0, PLOT_LINE_WIDTH, 3);
   PlotIndexSetInteger(1, PLOT_LINE_WIDTH, 3);
   
//--- Allocate processing engine dynamically on system heap
   g_ob_engine = new COrderBlockEngine(_Symbol, PERIOD_CURRENT);
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- Release the pointer to prevent memory leaks
   if(CheckPointer(g_ob_engine) == POINTER_DYNAMIC)
     {
      delete g_ob_engine;
     }
}

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
//--- Check total available historical timeline dataset
   if(rates_total < 5) return 0;
   int start = (prev_calculated > 0) ? prev_calculated - 1 : 0;
   
//--- Traverse chart history bar by bar sequentially
   for(int i = start; i < rates_total && !IsStopped(); i++)
     {
      int shift = rates_total - 1 - i;
      OrderBlock active_zone;
      
      BufferBull[i] = EMPTY_VALUE;
      BufferBear[i] = EMPTY_VALUE;
      
      if(g_ob_engine.GetLatestZone(shift, active_zone))
        {
         if(active_zone.direction == 1)
           {
            BufferBull[i] = active_zone.high_price;
           }
         else if(active_zone.direction == -1)
           {
            BufferBear[i] = active_zone.low_price;
           }
        }
     }
   return(rates_total);
}