//+------------------------------------------------------------------+
//| TC_MA_Crossover.mq5                                              |
//| Tradi Coders — MA Crossover, Golden Cross & Death Cross          |
//| Free product: https://tradicoders.com                            |
//+------------------------------------------------------------------+
#property copyright   "Tradi Coders"
#property link        "https://tradicoders.com"
#property version     "1.00"
#property description "Moving Average crossover with Golden Cross and Death Cross signals."
#property description "Non-repainting arrows on closed bars. By Tradi Coders — tradicoders.com"
#property indicator_chart_window
#property indicator_buffers 4
#property indicator_plots   4
#property indicator_type1   DRAW_LINE
#property indicator_type2   DRAW_LINE
#property indicator_type3   DRAW_ARROW
#property indicator_type4   DRAW_ARROW
#property indicator_label1  "Fast MA"
#property indicator_label2  "Slow MA"
#property indicator_label3  "Golden Cross"
#property indicator_label4  "Death Cross"

#include <TC_Common.mqh>
#include <TC_Inputs.mqh>
#include <TC_BarTime.mqh>
#include <TC_MACross.mqh>

#define TC_PRODUCT_NAME  "TC MA Crossover"
#define TC_PRODUCT_VER   "1.00"

//--- plots
double ExtFastBuffer[];
double ExtSlowBuffer[];
double ExtBuyArrow[];
double ExtSellArrow[];

int    ExtHandleFast;
int    ExtHandleSlow;
int    ExtArrowBuy  = 233;
int    ExtArrowSell = 234;

//--- product inputs
input group "—— Crossover Signals ——"
input bool   InpShowMALines     = true;     // Show MA lines on chart
input bool   InpShowArrows      = true;     // Show Golden / Death arrows
input bool   InpAlertOnCross    = true;     // Alert on new cross (closed bar)
input int    InpArrowGapPoints  = 8;        // Arrow offset (points)

//+------------------------------------------------------------------+
int OnInit()
  {
   TC_ApplyTheme(InpTC_Theme);
   IndicatorSetString(INDICATOR_SHORTNAME,TC_BrandComment(TC_PRODUCT_NAME));

   SetIndexBuffer(0,ExtFastBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,ExtSlowBuffer,INDICATOR_DATA);
   SetIndexBuffer(2,ExtBuyArrow,INDICATOR_DATA);
   SetIndexBuffer(3,ExtSellArrow,INDICATOR_DATA);

   PlotIndexSetInteger(0,PLOT_DRAW_TYPE,InpShowMALines ? DRAW_LINE : DRAW_NONE);
   PlotIndexSetInteger(1,PLOT_DRAW_TYPE,InpShowMALines ? DRAW_LINE : DRAW_NONE);
   PlotIndexSetInteger(2,PLOT_DRAW_TYPE,InpShowArrows ? DRAW_ARROW : DRAW_NONE);
   PlotIndexSetInteger(3,PLOT_DRAW_TYPE,InpShowArrows ? DRAW_ARROW : DRAW_NONE);

   PlotIndexSetInteger(2,PLOT_ARROW,ExtArrowBuy);
   PlotIndexSetInteger(3,PLOT_ARROW,ExtArrowSell);

   PlotIndexSetInteger(0,PLOT_LINE_COLOR,TC_MaFast);
   PlotIndexSetInteger(1,PLOT_LINE_COLOR,TC_MaSlow);
   PlotIndexSetInteger(2,PLOT_LINE_COLOR,TC_SignalBuy);
   PlotIndexSetInteger(3,PLOT_LINE_COLOR,TC_SignalSell);

   PlotIndexSetDouble(2,PLOT_EMPTY_VALUE,EMPTY_VALUE);
   PlotIndexSetDouble(3,PLOT_EMPTY_VALUE,EMPTY_VALUE);

   IndicatorSetInteger(INDICATOR_DIGITS,_Digits);

   ExtHandleFast = iMA(_Symbol,_Period,InpTC_MA_Fast_Period,0,InpTC_MA_Method,InpTC_MA_Price);
   ExtHandleSlow = iMA(_Symbol,_Period,InpTC_MA_Slow_Period,0,InpTC_MA_Method,InpTC_MA_Price);

   if(ExtHandleFast==INVALID_HANDLE || ExtHandleSlow==INVALID_HANDLE)
     {
      Print(TC_PRODUCT_NAME,": failed to create MA handles");
      return INIT_FAILED;
     }

   if(!TC_BrandInputsApply(TC_PRODUCT_NAME,TC_PRODUCT_VER))
      Print(TC_PRODUCT_NAME,": branding panel warning");

   return INIT_SUCCEEDED;
  }

//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   if(ExtHandleFast!=INVALID_HANDLE) IndicatorRelease(ExtHandleFast);
   if(ExtHandleSlow!=INVALID_HANDLE) IndicatorRelease(ExtHandleSlow);
   TC_BrandDeinit();
  }

//+------------------------------------------------------------------+
void OnChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
   TC_BrandOnChartEvent(id,lparam,dparam,sparam);
  }

//+------------------------------------------------------------------+
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[])
  {
   if(rates_total < InpTC_MA_Slow_Period + 2)
      return 0;

   if(CopyBuffer(ExtHandleFast,0,0,rates_total,ExtFastBuffer)<=0)
      return prev_calculated;
   if(CopyBuffer(ExtHandleSlow,0,0,rates_total,ExtSlowBuffer)<=0)
      return prev_calculated;

   int begin = InpTC_MA_Slow_Period;
   if(prev_calculated > 1)
      begin = MathMax(begin, prev_calculated - 2);

   double gap = InpArrowGapPoints * _Point;

   for(int i=begin; i<rates_total && !IsStopped(); i++)
     {
      ExtBuyArrow[i]  = EMPTY_VALUE;
      ExtSellArrow[i] = EMPTY_VALUE;

      int cross = TC_MACross_Detect(ExtFastBuffer[i],ExtSlowBuffer[i],
                                  ExtFastBuffer[i-1],ExtSlowBuffer[i-1]);
      if(cross==TC_CROSS_GOLDEN)
         ExtBuyArrow[i] = low[i] - gap;
      else if(cross==TC_CROSS_DEATH)
         ExtSellArrow[i] = high[i] + gap;
     }

   if(InpAlertOnCross && rates_total >= 3)
     {
      int closed = rates_total - 2;
      int cross  = TC_MACross_Detect(ExtFastBuffer[closed],ExtSlowBuffer[closed],
                                     ExtFastBuffer[closed-1],ExtSlowBuffer[closed-1]);
      if(cross!=TC_CROSS_NONE)
        {
         string key = "MACross_"+_Symbol+IntegerToString(_Period);
         if(TC_AlertOncePerBar(key,time[closed]))
           {
            string lbl = TC_MACross_Label(cross);
            TC_SendAlert(TC_PRODUCT_NAME,
                         StringFormat("%s on %s %s | Fast=%d Slow=%d",
                                      lbl,_Symbol,EnumToString(_Period),
                                      InpTC_MA_Fast_Period,InpTC_MA_Slow_Period));
           }
        }
     }

   return rates_total;
  }
//+------------------------------------------------------------------+
