//+------------------------------------------------------------------+
//|                                          FisherReversal.mq4      |
//|   Nonlinear Fisher Transform Reversal Indicator                  |
//|                                                                  |
//| This indicator calculates the Fisher Transform on the median     |
//| price over a specified period and generates arrow signals when   |
//| the Fisher value crosses from above a high threshold (sell) or   |
//| from below a low threshold (buy). It uses only closed bars so      |
//| that it does not repaint.                                          |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property strict

//--- External Inputs
extern int    FisherPeriod         = 50;    // Look-back period for Fisher Transform
extern double FisherHighThreshold  = 0.65;   // High threshold for Fisher (sell signal when crossing down)
extern double FisherLowThreshold   = -0.65;  // Low threshold for Fisher (buy signal when crossing up)
extern double ArrowOffset          = 5.0;   // Arrow offset in points

//--- Indicator buffers (for drawing arrows)
#property indicator_buffers 2
#property indicator_color1 Blue     // Up arrow (buy signal) color
#property indicator_color2 Red      // Down arrow (sell signal) color
#property indicator_width1 2
#property indicator_width2 2
#property indicator_style1 DRAW_ARROW
#property indicator_style2 DRAW_ARROW

double UpArrowBuffer[];
double DownArrowBuffer[];

//--- Internal array for Fisher Transform values
double FisherBuffer[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
{
   // Resize arrays to the total number of bars
   ArrayResize(UpArrowBuffer, Bars);
   ArrayResize(DownArrowBuffer, Bars);
   ArrayResize(FisherBuffer, Bars);
   
   // Bind the visible arrow buffers
   IndicatorBuffers(2);
   SetIndexBuffer(0, UpArrowBuffer);
   SetIndexBuffer(1, DownArrowBuffer);
   
   // Set drawing properties for the arrow buffers
   SetIndexStyle(0, DRAW_ARROW, 0, 2, Blue);
   SetIndexArrow(0, 233);  // Wingdings up arrow
   SetIndexStyle(1, DRAW_ARROW, 0, 2, Red);
   SetIndexArrow(1, 234);  // Wingdings down arrow
   
   // Set arrays as series (index 0 is the most recent bar)
   ArraySetAsSeries(UpArrowBuffer, true);
   ArraySetAsSeries(DownArrowBuffer, true);
   ArraySetAsSeries(FisherBuffer, true);
   
   return(0);
}

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
{
   return(0);
}

//+------------------------------------------------------------------+
//| Fisher Transform Reversal indicator iteration function           |
//+------------------------------------------------------------------+
int start()
{
   int counted_bars = IndicatorCounted();
   if(counted_bars < 0)
      return(-1);
   if(counted_bars > 0)
      counted_bars--;
      
   // Calculate the number of bars available for processing.
   int limit = Bars - counted_bars;
   if(limit < FisherPeriod)
      return(0);
      
   //--- 1. Compute Fisher Transform values for each bar.
   // Loop from the oldest bar (index Bars-1) down to the most recent (index 0)
   for(int i = Bars - 1; i >= 0; i--)
   {
      if(i + FisherPeriod > Bars)
      {
         // Not enough data for the full look-back period.
         FisherBuffer[i] = 0.0;
      }
      else
      {
         double highest = -DBL_MAX;
         double lowest  = DBL_MAX;
         for(int j = i; j < i + FisherPeriod; j++)
         {
            double medianPrice = (High[j] + Low[j]) / 2.0;
            if(medianPrice > highest) highest = medianPrice;
            if(medianPrice < lowest)  lowest  = medianPrice;
         }
         double currentPrice = (High[i] + Low[i]) / 2.0;
         double value = 0.0;
         if(highest != lowest)
            value = 0.33 * 2 * ((currentPrice - lowest) / (highest - lowest) - 0.5);
         if(value > 0.99) value = 0.999;
         if(value < -0.99) value = -0.999;
         
         // Use recursion to smooth the Fisher Transform.
         if(i == Bars - 1)
            FisherBuffer[i] = 0.0;  // Initialize the oldest bar
         else
            FisherBuffer[i] = 0.5 * MathLog((1 + value) / (1 - value)) + 0.5 * FisherBuffer[i + 1];
      }
   }
   
   //--- 2. Generate arrow signals on confirmed (closed) bars.
   // (Since arrays are series, index 0 is the current forming bar; we process bars with index>=1.)
   for(int i = 1; i < limit - 1; i++)
   {
      UpArrowBuffer[i]   = EMPTY_VALUE;
      DownArrowBuffer[i] = EMPTY_VALUE;
      
      // Sell Signal (Down Arrow):
      // If the Fisher value is at or above FisherHighThreshold on the current bar and
      // then falls below FisherHighThreshold on the next older bar, signal a sell.
      if(FisherBuffer[i] >= FisherHighThreshold && FisherBuffer[i+1] < FisherHighThreshold)
         DownArrowBuffer[i] = High[i] + ArrowOffset * Point;
      
      // Buy Signal (Up Arrow):
      // If the Fisher value is at or below FisherLowThreshold on the current bar and
      // then rises above FisherLowThreshold on the next older bar, signal a buy.
      if(FisherBuffer[i] <= FisherLowThreshold && FisherBuffer[i+1] > FisherLowThreshold)
         UpArrowBuffer[i] = Low[i] - ArrowOffset * Point;
   }
   
   // Clear signals on the current (forming) bar.
   UpArrowBuffer[0] = EMPTY_VALUE;
   DownArrowBuffer[0] = EMPTY_VALUE;
   
   return(0);
}
//+------------------------------------------------------------------+
