//+------------------------------------------------------------------+
//|                                     t27_OsMA_PDC_recreate.mq4     |
//|                                                                    |
//|  Independent recreation attempt of "t27_OsMA+PDC 3.5", built      |
//|  from the visible chart behavior and the Inputs tab only — NOT    |
//|  decompiled or copied from the original .ex4. It will not be a   |
//|  pixel-perfect match; the original's exact pivot/divergence       |
//|  algorithm is unknown, so this uses a standard, well-known        |
//|  approach (fractal swing points + classic divergence rules).      |
//|                                                                    |
//|  What it does:                                                    |
//|   - Plots OsMA = MACD main line minus its signal line (a          |
//|     standard, non-proprietary formula), using the same            |
//|     FastEMA / SlowEMA / SignalSMA / Metod / Price inputs shown    |
//|     in the screenshot.                                            |
//|   - Finds swing highs/lows ("Proboy" points) on the OsMA line     |
//|     and draws short horizontal marker lines at them, mirrored     |
//|     on the price chart at the matching bar.                       |
//|   - Compares consecutive swing highs/lows between price and       |
//|     OsMA to flag classic bullish/bearish divergence (price and    |
//|     oscillator disagree) and convergence (price and oscillator    |
//|     agree), drawing connecting diagonal lines + markers for       |
//|     each, on both the indicator and the price chart.              |
//|                                                                    |
//|  PivotStrength and ProboyExtendBars are assumptions (not shown    |
//|  in the supplied screenshot) — adjust them to taste.              |
//+------------------------------------------------------------------+
#property copyright "Independent recreation — not derived from t27_OsMA+PDC 3.5 source"
#property version   "1.00"
#property strict
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_color1  clrWhite
#property indicator_width1  1
#property indicator_level1  0.0
#property indicator_levelstyle STYLE_DOT

//==================================================================
//  INPUTS — names/defaults match the original's Inputs tab
//==================================================================
input int                DeepBars               = 3000;               // Bars to scan for pivots/lines
input int                FastEMA                = 12;                 // Fast EMA period
input int                SlowEMA                = 26;                 // Slow EMA period
input int                SignalSMA              = 9;                  // Signal period
input ENUM_MA_METHOD     Metod                  = MODE_EMA;           // Signal-line smoothing method
input ENUM_APPLIED_PRICE Price                  = PRICE_CLOSE;        // Applied price
input bool                DrawIndiProboyLines    = true;               // Draw swing lines on the indicator
input bool                DrawPriceProboyLines   = true;               // Draw swing lines on the price chart
input bool                DrawIndiDivergenceLines= true;               // Draw divergence lines on the indicator
input bool                DrawPriceDivergenceLines=true;               // Draw divergence lines on the price chart
input bool                DrawIndiConvergenceLines=true;               // Draw convergence lines on the indicator
input bool                DrawPriceConvergenceLines=true;              // Draw convergence lines on the price chart
input color                UpProboy               = clrDodgerBlue;      // Swing-high line color
input color                DnProboy               = clrMediumVioletRed; // Swing-low line color
input int                 ProboyLineWidth         = 3;                 // Swing line thickness (px)

//--- not shown in the supplied screenshot; needed to make the
//    recreation work — tune to taste
input int    PivotStrength    = 3;   // bars required on each side to confirm a swing point
input int    ProboyExtendBars = 6;   // how many bars each swing-line segment spans

//--- fixed colors for divergence / convergence (not in the input list;
//    picked to match the look of the screenshots)
color BearDivergenceColor = clrOrange;
color BullDivergenceColor = clrLimeGreen;
color BullConvergenceColor= clrDarkOrange;
color BearConvergenceColor= clrTeal;

//==================================================================
double OsMA[];

#define PFX "t27r_"
int    gObjCounter = 0;

struct Pivot
{
   int      barIndex;   // series index (0 = current bar) at time of detection
   datetime time;
   double   priceVal;   // high[] or low[] of the pivot bar
   double   osmaVal;
   bool     isHigh;
};

//+------------------------------------------------------------------+
int OnInit()
{
   SetIndexBuffer(0,OsMA);
   SetIndexStyle(0,DRAW_LINE);
   SetIndexLabel(0,"OsMA");
   IndicatorShortName(StringFormat("t27_OsMA+PDC recreate (%d,%d,%d)",FastEMA,SlowEMA,SignalSMA));
   return(INIT_SUCCEEDED);
}

void OnDeinit(const int reason)
{
   ObjectsDeleteAll(0,PFX);
}

//+------------------------------------------------------------------+
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[])
{
   int bars = MathMin(rates_total,DeepBars);
   int minBars = SlowEMA+SignalSMA+PivotStrength*2+5;
   if(bars < minBars) return(rates_total);

   //--- MACD main line (standard, non-proprietary formula)
   double macdMain[];
   ArrayResize(macdMain,bars);
   ArraySetAsSeries(macdMain,true);
   for(int i=0;i<bars;i++)
      macdMain[i] = iMA(NULL,0,FastEMA,0,MODE_EMA,Price,i) - iMA(NULL,0,SlowEMA,0,MODE_EMA,Price,i);

   //--- signal line = Metod-smoothed MACD main line
   double sig[];
   ArrayResize(sig,bars);
   ArraySetAsSeries(sig,true);
   for(int i=0;i<bars;i++)
      sig[i] = iMAOnArray(macdMain,bars,SignalSMA,0,Metod,i);

   //--- OsMA = main - signal
   for(int i=0;i<bars;i++)
      OsMA[i] = macdMain[i]-sig[i];

   //--- clear previous objects and rebuild (simplest correct approach;
   //    fine performance-wise up to a few thousand bars)
   ObjectsDeleteAll(0,PFX);
   gObjCounter = 0;

   //--- find swing pivots on OsMA, oldest -> newest
   Pivot pivots[];
   int pivotCount = 0;
   ArrayResize(pivots,bars);

   for(int i = bars-1-PivotStrength; i >= PivotStrength; i--)
   {
      bool isHigh = true, isLow = true;
      for(int k=1;k<=PivotStrength;k++)
      {
         if(OsMA[i] < OsMA[i-k] || OsMA[i] < OsMA[i+k]) isHigh=false;
         if(OsMA[i] > OsMA[i-k] || OsMA[i] > OsMA[i+k]) isLow=false;
      }
      if(isHigh || isLow)
      {
         pivots[pivotCount].barIndex = i;
         pivots[pivotCount].time     = time[i];
         pivots[pivotCount].osmaVal  = OsMA[i];
         pivots[pivotCount].priceVal = isHigh ? high[i] : low[i];
         pivots[pivotCount].isHigh   = isHigh;
         pivotCount++;
      }
   }

   //--- draw Proboy swing lines + detect divergence/convergence
   //    between each pivot and the previous pivot of the same type
   int lastHigh = -1, lastLow = -1;
   for(int p=0;p<pivotCount;p++)
   {
      DrawProboyLine(pivots[p], time, bars);

      if(pivots[p].isHigh)
      {
         if(lastHigh>=0) CompareAndDraw(pivots[lastHigh],pivots[p],true);
         lastHigh = p;
      }
      else
      {
         if(lastLow>=0) CompareAndDraw(pivots[lastLow],pivots[p],false);
         lastLow = p;
      }
   }

   return(rates_total);
}

//+------------------------------------------------------------------+
//  Horizontal marker line at a swing pivot (both panes, per inputs)
//+------------------------------------------------------------------+
void DrawProboyLine(const Pivot &pv, const datetime &time[], int bars)
{
   int endIdx = MathMax(pv.barIndex-ProboyExtendBars,0);
   datetime t1 = pv.time;
   datetime t2 = time[endIdx];
   color    clr = pv.isHigh ? UpProboy : DnProboy;

   if(DrawIndiProboyLines)
   {
      string name = PFX+"IP"+IntegerToString(gObjCounter++);
      ObjectCreate(0,name,OBJ_TREND,ChartWindowFind(),t1,pv.osmaVal,t2,pv.osmaVal);
      ObjectSetInteger(0,name,OBJPROP_COLOR,clr);
      ObjectSetInteger(0,name,OBJPROP_WIDTH,ProboyLineWidth);
      ObjectSetInteger(0,name,OBJPROP_RAY_RIGHT,false);
      ObjectSetInteger(0,name,OBJPROP_RAY_LEFT,false);
      ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);
   }
   if(DrawPriceProboyLines)
   {
      string name = PFX+"PP"+IntegerToString(gObjCounter++);
      ObjectCreate(0,name,OBJ_TREND,0,t1,pv.priceVal,t2,pv.priceVal);
      ObjectSetInteger(0,name,OBJPROP_COLOR,clr);
      ObjectSetInteger(0,name,OBJPROP_WIDTH,ProboyLineWidth);
      ObjectSetInteger(0,name,OBJPROP_RAY_RIGHT,false);
      ObjectSetInteger(0,name,OBJPROP_RAY_LEFT,false);
      ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);
   }
}

//+------------------------------------------------------------------+
//  Compares two same-type pivots (both highs or both lows) and draws
//  a divergence or convergence line + marker between them.
//+------------------------------------------------------------------+
void CompareAndDraw(const Pivot &prev, const Pivot &cur, bool isHighPair)
{
   bool priceUp = cur.priceVal > prev.priceVal;
   bool osmaUp  = cur.osmaVal  > prev.osmaVal;

   bool bearishDivergence = isHighPair &&  priceUp && !osmaUp;   // price HH, OsMA LH
   bool bullishDivergence = !isHighPair && !priceUp &&  osmaUp;  // price LL, OsMA HL
   bool bullishConvergence= isHighPair &&  priceUp &&  osmaUp;   // price HH, OsMA HH
   bool bearishConvergence= !isHighPair && !priceUp && !osmaUp;  // price LL, OsMA LL

   if(bearishDivergence && (DrawIndiDivergenceLines||DrawPriceDivergenceLines))
      DrawLinkLine(prev,cur,BearDivergenceColor,STYLE_DOT,true,SYMBOL_ARROWDOWN,clrRed,
                   DrawIndiDivergenceLines,DrawPriceDivergenceLines);

   if(bullishDivergence && (DrawIndiDivergenceLines||DrawPriceDivergenceLines))
      DrawLinkLine(prev,cur,BullDivergenceColor,STYLE_DOT,true,SYMBOL_ARROWUP,clrLime,
                   DrawIndiDivergenceLines,DrawPriceDivergenceLines);

   if(bullishConvergence && (DrawIndiConvergenceLines||DrawPriceConvergenceLines))
      DrawLinkLine(prev,cur,BullConvergenceColor,STYLE_DOT,false,SYMBOL_ARROWUP,BullConvergenceColor,
                   DrawIndiConvergenceLines,DrawPriceConvergenceLines);

   if(bearishConvergence && (DrawIndiConvergenceLines||DrawPriceConvergenceLines))
      DrawLinkLine(prev,cur,BearConvergenceColor,STYLE_DOT,false,SYMBOL_ARROWDOWN,BearConvergenceColor,
                   DrawIndiConvergenceLines,DrawPriceConvergenceLines);
}

//+------------------------------------------------------------------+
//  Draws a diagonal connecting line between two pivots, on the
//  indicator and/or price pane, plus an arrow marker at the newer
//  pivot (star-like marker for divergence, small arrow for
//  convergence — matches the two marker styles seen on the chart).
//+------------------------------------------------------------------+
void DrawLinkLine(const Pivot &a, const Pivot &b, color clr, int style, bool starMarker,
                   int arrowCode, color arrowColor, bool onIndi, bool onPrice)
{
   if(onIndi)
   {
      string ln = PFX+"IL"+IntegerToString(gObjCounter++);
      ObjectCreate(0,ln,OBJ_TREND,ChartWindowFind(),a.time,a.osmaVal,b.time,b.osmaVal);
      ObjectSetInteger(0,ln,OBJPROP_COLOR,clr);
      ObjectSetInteger(0,ln,OBJPROP_STYLE,style);
      ObjectSetInteger(0,ln,OBJPROP_WIDTH,1);
      ObjectSetInteger(0,ln,OBJPROP_RAY_RIGHT,false);
      ObjectSetInteger(0,ln,OBJPROP_SELECTABLE,false);

      string mk = PFX+"IM"+IntegerToString(gObjCounter++);
      ObjectCreate(0,mk,OBJ_ARROW,ChartWindowFind(),b.time,b.osmaVal);
      ObjectSetInteger(0,mk,OBJPROP_ARROWCODE,starMarker?SYMBOL_STOPSIGN:arrowCode);
      ObjectSetInteger(0,mk,OBJPROP_COLOR,arrowColor);
      ObjectSetInteger(0,mk,OBJPROP_WIDTH,1);
      ObjectSetInteger(0,mk,OBJPROP_SELECTABLE,false);
   }
   if(onPrice)
   {
      string ln = PFX+"PL"+IntegerToString(gObjCounter++);
      ObjectCreate(0,ln,OBJ_TREND,0,a.time,a.priceVal,b.time,b.priceVal);
      ObjectSetInteger(0,ln,OBJPROP_COLOR,clr);
      ObjectSetInteger(0,ln,OBJPROP_STYLE,style);
      ObjectSetInteger(0,ln,OBJPROP_WIDTH,1);
      ObjectSetInteger(0,ln,OBJPROP_RAY_RIGHT,false);
      ObjectSetInteger(0,ln,OBJPROP_SELECTABLE,false);

      string mk = PFX+"PM"+IntegerToString(gObjCounter++);
      ObjectCreate(0,mk,OBJ_ARROW,0,b.time,b.priceVal);
      ObjectSetInteger(0,mk,OBJPROP_ARROWCODE,starMarker?SYMBOL_STOPSIGN:arrowCode);
      ObjectSetInteger(0,mk,OBJPROP_COLOR,arrowColor);
      ObjectSetInteger(0,mk,OBJPROP_WIDTH,1);
      ObjectSetInteger(0,mk,OBJPROP_SELECTABLE,false);
   }
}
//+------------------------------------------------------------------+
