//+------------------------------------------------------------------+
//|  HurstProfile.mq5                                                |
//|  Market Microstructure in MQL5: Measuring Long Memory (Part 2)   |
//|                                                                  |
//|  PURPOSE                                                         |
//|  Plots the confidence-weighted Hurst exponent H*(t) bar by bar.  |
//|  Three horizontal reference lines mark the anti-persistence      |
//|  zone (H < 0.4), random walk boundary (H = 0.5), and             |
//|  persistence zone (H > 0.6). A separate Regime buffer encodes    |
//|  the zone as +1 (persistent), -1 (anti-persistent), or 0.        |
//|                                                                  |
//|  USAGE                                                           |
//|  Place this file in:                                             |
//|    MQL5\Indicators\HurstProfile\                                 |
//|  Place the foundation header in:                                 |
//|    MQL5\Indicators\HurstProfile\Includes\                        |
//|  Attach to any M1 chart. Recommended period: 90 bars.            |
//|                                                                  |
//|  OUTPUTS                                                         |
//|  Buffer 0 — H_buffer    : blended Hurst exponent per bar         |
//|             EMPTY_VALUE for bars 0..InpPeriod-1                  |
//|  Buffer 1 — Conf_buffer : estimator confidence per bar (0 to 1)  |
//|             EMPTY_VALUE for bars 0..InpPeriod-1                  |
//|  Buffer 2 — Regime_buffer: +1 persistent / -1 anti-pers. / 0     |
//|             0.0 when confidence < HURST_CONF_THRESHOLD           |
//|                                                                  |
//|  FIX v2.03: Completely rewritten HurstFromClose. Now copies      |
//|  the required close prices into a chronological window first,    |
//|  eliminating all series-indexed out-of-range errors.             |
//|                                                                  |
//|  DEPENDS ON : MicroStructure_Foundation.mqh (Parts 1 and 2)      |
//+------------------------------------------------------------------+
#property copyright   "Max Brown"
#property link        ""
#property version     "2.03"
#property indicator_separate_window
#property indicator_buffers 3
#property indicator_plots   3

//--- Plot 0: Hurst exponent line
#property indicator_label1  "H*(t)"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrDodgerBlue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  2

//--- Plot 1: Confidence line (thinner, greyed)
#property indicator_label2  "Confidence"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrSilver
#property indicator_style2  STYLE_DOT
#property indicator_width2  1

//--- Plot 2: Regime bar (histogram for quick regime read)
#property indicator_label3  "Regime"
#property indicator_type3   DRAW_HISTOGRAM
#property indicator_color3  clrTomato
#property indicator_style3  STYLE_SOLID
#property indicator_width3  3

#include "Includes\MicroStructure_Foundation.mqh"

//--- Indicator inputs
input int    InpPeriod          = 90;    // Lookback period in bars
input double InpPersistThresh   = 0.60;  // H above this → persistent regime
input double InpAntiPersThresh  = 0.40;  // H below this → anti-persistent regime
input bool   InpShowConfidence  = true;  // Plot confidence buffer

//--- Indicator buffers
double H_buffer[];
double Conf_buffer[];
double Regime_buffer[];

//--- Reference line objects (drawn once in OnInit)
#define LINE_PERSIST   "HP_Persist"   // Object name for the persistence threshold line (H = 0.60)
#define LINE_RANDOM    "HP_Random"    // Object name for the random walk boundary line (H = 0.50)
#define LINE_ANTIPRS   "HP_AntiPers"  // Object name for the anti-persistence threshold line (H = 0.40)

//+------------------------------------------------------------------+
//| OnInit: register buffers and draw reference lines.               |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Register buffers in the order matching #property declarations
   SetIndexBuffer(0, H_buffer,      INDICATOR_DATA);
   SetIndexBuffer(1, Conf_buffer,   INDICATOR_DATA);
   SetIndexBuffer(2, Regime_buffer, INDICATOR_DATA);
//--- Initialise all buffers to empty
   ArrayInitialize(H_buffer,      EMPTY_VALUE);
   ArrayInitialize(Conf_buffer,   EMPTY_VALUE);
   ArrayInitialize(Regime_buffer, EMPTY_VALUE);
//--- Plot labels
   PlotIndexSetString(0, PLOT_LABEL, "H*(t)");
   PlotIndexSetString(1, PLOT_LABEL, "Confidence");
   PlotIndexSetString(2, PLOT_LABEL, "Regime");
//--- Minimum bars required before the first valid output
   PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, InpPeriod);
   PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, InpPeriod);
   PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, InpPeriod);
//--- Hide confidence plot if user disabled it
   if(!InpShowConfidence)
      PlotIndexSetInteger(1, PLOT_DRAW_TYPE, DRAW_NONE);
//--- Draw horizontal reference lines
   DrawHLine(LINE_PERSIST, InpPersistThresh, clrForestGreen,
             STYLE_DASH, 1);
   DrawHLine(LINE_RANDOM,  0.5,              clrDarkGray,
             STYLE_DOT,  1);
   DrawHLine(LINE_ANTIPRS, InpAntiPersThresh, clrTomato,
             STYLE_DASH, 1);
//--- Indicator short name shown in the sub-window header
   IndicatorSetString(INDICATOR_SHORTNAME,
                      StringFormat("HurstProfile(%d)", InpPeriod));
   return INIT_SUCCEEDED;
  }

//+------------------------------------------------------------------+
//| OnDeinit: remove reference lines on indicator removal.           |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   ObjectDelete(0, LINE_PERSIST);
   ObjectDelete(0, LINE_RANDOM);
   ObjectDelete(0, LINE_ANTIPRS);
  }

//+------------------------------------------------------------------+
//| HurstFromClose: compute confidence-weighted H from a slice of    |
//| the close[] array passed into OnCalculate.                       |
//|                                                                  |
//| This avoids CopyClose() entirely and safely handles both         |
//| series-indexed and chronological close[] arrays.                 |
//|                                                                  |
//| FIX v2.03: Copies the required close prices into a local         |
//| chronological window first, eliminating all index-out-of-range   |
//| errors. The return calculation then proceeds sequentially from   |
//| index 1, so j-1 is always valid.                                 |
//|                                                                  |
//| Parameters                                                       |
//|   close[]    — full close array from OnCalculate (series-indexed)|
//|   bar        — index of the bar being calculated                 |
//|   period     — lookback window in bars                           |
//|   confidence — output: blended confidence weight                 |
//|                                                                  |
//| Returns H in [0.01, 0.99]; 0.5 with confidence = 0.0 on failure. |
//+------------------------------------------------------------------+
double HurstFromClose(const double &close[], int bar,
                      int period, double &confidence)
  {
   confidence = 0.0;
   int total_bars = ArraySize(close);
//--- Valid bar index check
   if(bar < 0 || bar >= total_bars)
      return 0.5;
//--- Calculate start index (series-indexed)
   int start = bar - period + 1;
   if(start < 1 || start >= total_bars)
      return 0.5;
//--- Copy the required window into chronological order (oldest first)
   double close_window[];
   ArrayResize(close_window, period);
   for(int idx = 0; idx < period; idx++)
     {
      close_window[idx] = close[start + idx];
     }
//--- Build log-return array from chronological window
   double returns[];
   ArrayResize(returns, period - 1);
   int valid = 0;
   for(int j = 1; j < period; j++)     // j starts at 1 → j-1 always safe
     {
      if(close_window[j] <= 0 || close_window[j - 1] <= 0)
         continue;
      double r = SafeLog(close_window[j]) - SafeLog(close_window[j - 1]);
      if(MathAbs(r) < 0.1)
         returns[valid++] = r;
     }
   if(valid < HURST_MIN_BARS)
     {
      confidence = 0.0;
      return 0.5;
     }
   ArrayResize(returns, valid);
//--- Run all three estimators on the windowed returns
   double conf_rs, conf_av, conf_am;
   double h_rs = HurstExponentRS(returns, valid, conf_rs);
   double h_av = AdvancedHurstExponent(returns, valid, 0, conf_av);
   double h_am = AdvancedHurstExponent(returns, valid, 1, conf_am);
//--- Confidence-weighted blend
   double ws = 0.0, tw = 0.0;
   if(conf_rs > HURST_CONF_THRESHOLD)
     {
      ws += h_rs * conf_rs;
      tw += conf_rs;
     }
   if(conf_av > HURST_CONF_THRESHOLD)
     {
      ws += h_av * conf_av;
      tw += conf_av;
     }
   if(conf_am > HURST_CONF_THRESHOLD)
     {
      ws += h_am * conf_am;
      tw += conf_am;
     }
   if(tw <= 0)
     {
      confidence = 0.0;
      return 0.5;
     }
   confidence = MathMin(1.0, tw / 3.0);
   return MathMax(0.01, MathMin(0.99, ws / tw));
  }

//+------------------------------------------------------------------+
//| OnCalculate: compute H*(t) for each bar using the close[] array. |
//|                                                                  |
//| Buffer behaviour:                                                |
//|   Bars 0 .. InpPeriod-1 : EMPTY_VALUE (not enough history)       |
//|   Bar InpPeriod onward  : calculated H, confidence, regime       |
//|                                                                  |
//| On the first call (prev_calculated == 0) all historical bars are |
//| processed. On subsequent calls only the new bar is calculated.   |
//| This ensures each bar receives the data that existed at that bar,|
//| not the current most-recent data.                                |
//+------------------------------------------------------------------+
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[])
  {
//--- Need at least InpPeriod + 1 bars before any output is possible
   if(rates_total < InpPeriod + 1)
      return 0;
//--- On first call fill pre-period bars with EMPTY_VALUE explicitly
   if(prev_calculated == 0)
     {
      for(int i = 0; i < InpPeriod; i++)
        {
         H_buffer     [i] = EMPTY_VALUE;
         Conf_buffer  [i] = EMPTY_VALUE;
         Regime_buffer[i] = EMPTY_VALUE;
        }
     }
//--- Start bar: on first call process all bars from InpPeriod onward;
//--- on subsequent calls recalculate only the last bar
   int start = (prev_calculated == 0) ? InpPeriod : prev_calculated - 1;
   for(int i = start; i < rates_total; i++)
     {
      double conf = 0.0;
      double h    = HurstFromClose(close, i, InpPeriod, conf);
      H_buffer   [i] = h;
      Conf_buffer[i] = conf;
      //--- Regime: 0.0 when confidence is too low to trust (matches article)
      if(conf < HURST_CONF_THRESHOLD)
         Regime_buffer[i] = 0.0;
      else
         if(h >= InpPersistThresh)
            Regime_buffer[i] =  1.0;   // Persistent — trend-following conditions
         else
            if(h <= InpAntiPersThresh)
               Regime_buffer[i] = -1.0;   // Anti-persistent — mean-reversion conditions
            else
               Regime_buffer[i] =  0.0;   // Transition zone — no directional bias
     }
   return rates_total;
  }

//+------------------------------------------------------------------+
//| DrawHLine: creates a named horizontal line in the sub-window.    |
//| Safe to call repeatedly — deletes any existing object with the   |
//| same name before recreating it.                                  |
//+------------------------------------------------------------------+
void DrawHLine(const string name, const double price,
               const color clr, const int style, const int width)
  {
   ObjectDelete(0, name);
   ObjectCreate(0, name, OBJ_HLINE, 0, 0, price);
   ObjectSetInteger(0, name, OBJPROP_COLOR,  clr);
   ObjectSetInteger(0, name, OBJPROP_STYLE,  style);
   ObjectSetInteger(0, name, OBJPROP_WIDTH,  width);
   ObjectSetInteger(0, name, OBJPROP_BACK,   true);
   ObjectSetString(0, name, OBJPROP_TOOLTIP, name);
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
