#property copyright   ""
#property link        ""

#property strict

#property indicator_separate_window
//#property indicator_chart_window

#property indicator_buffers 8

#property indicator_color1 Red
#property indicator_color2 Yellow
#property indicator_color3 Lime
#property indicator_color4 Aqua
#property indicator_color5 Crimson
#property indicator_color6 Maroon
#property indicator_color7 DarkBlue
#property indicator_color8 Orchid

#property indicator_level1 0

int    NCurrenciesUsed    = 0;//# of currencies in the cluster
string Indicator_Name     = "CCFp:";

double arrUSD[];
double arrEUR[];
double arrGBP[];
double arrCHF[];
double arrJPY[];
double arrAUD[];
double arrCAD[];
double arrNZD[];

 ENUM_MA_METHOD     MA_Method      = 3;//Moving average (MA) method
 ENUM_APPLIED_PRICE Price          = 6;//Price used on calculations
 int                Fast           = 3;//Fast MA period
 int                Slow           = 5;//Slow MA period
 bool               USD            = 1;//Add USD to cluster
 bool               EUR            = 1;//Add EUR to cluster
 bool               GBP            = 1;//Add GBP to cluster
 bool               CHF            = 1;//Add CHF to cluster
 bool               JPY            = 0;//Add JPY to cluster
 bool               AUD            = 1;//Add AUD to cluster
 bool               CAD            = 1;//Add CAD to cluster
 bool               NZD            = 1;//Add NZD to cluster
 color              Color_USD      = Red;
 color              Color_EUR      = Yellow;
 color              Color_GBP      = Lime;
 color              Color_CHF      = Aqua;
 color              Color_JPY      = Crimson;
 color              Color_AUD      = Maroon;
 color              Color_CAD      = DarkBlue;
 color              Color_NZD      = Orchid;
 int                Line_Thickness = 2;//Thickness for current pair lines
//input int                All_Bars       = 0;
//input int                Last_Bars      = 0;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
void OnInit(void)
{
   // 1) Set indicator name -------------------------------
   if(USD)
       Indicator_Name = StringConcatenate(Indicator_Name, " USD ");
   if(EUR)
       Indicator_Name = StringConcatenate(Indicator_Name, " EUR ");
   if(GBP)
       Indicator_Name = StringConcatenate(Indicator_Name, " GBP ");
   if(CHF)
       Indicator_Name = StringConcatenate(Indicator_Name, " CHF ");
   if(AUD)
       Indicator_Name = StringConcatenate(Indicator_Name, " AUD ");
   if(CAD)
       Indicator_Name = StringConcatenate(Indicator_Name, " CAD ");
   if(JPY)
       Indicator_Name = StringConcatenate(Indicator_Name, " JPY ");
   if(NZD)
       Indicator_Name = StringConcatenate(Indicator_Name, " NZD ");

   IndicatorShortName(Indicator_Name);
   IndicatorDigits(5);


   // 2) Set indicator legend "~" under each currency name --
   int cur =  0;//hztal position of objects
   int st  = 22;//spacing between objects in pixels

   if(USD){
     SetLegend("~", cur, Color_USD);
     cur += st;
   }
   if(EUR){
     SetLegend("~", cur, Color_EUR);
     cur += st;
   }
   if(GBP){
     SetLegend("~", cur, Color_GBP);
     cur += st;
   }
   if(CHF){
     SetLegend("~", cur, Color_CHF);
     cur += st;
   }
   if(AUD){
     SetLegend("~", cur, Color_AUD);
     cur += st;
   }
   if(CAD){
     SetLegend("~", cur, Color_CAD);
     cur += st;
   }
   if(JPY){
     SetLegend("~", cur, Color_JPY);
     cur += st;
   }
   if(NZD){
     SetLegend("~", cur, Color_NZD);
     cur += st;
   }

   // 3) Set indicator properties
   int width = 0;
   if(0 > StringFind(Symbol(), "USD", 0))
       width = 1;
   else 
       width = Line_Thickness;
   SetIndexStyle(0, DRAW_SECTION, DRAW_SECTION, width, Color_USD);
   SetIndexBuffer(0, arrUSD);
   SetIndexLabel(0, "USD"); 
   if(0 > StringFind(Symbol(), "EUR", 0))
       width = 1;
   else 
       width = Line_Thickness;
   SetIndexStyle(1, DRAW_SECTION, DRAW_SECTION, width, Color_EUR);
   SetIndexBuffer(1, arrEUR);
   SetIndexLabel(1, "EUR"); 
   if(0 > StringFind(Symbol(), "GBP", 0))
       width = 1;
   else 
       width = Line_Thickness;
   SetIndexStyle(2, DRAW_SECTION, DRAW_SECTION, width, Color_GBP);
   SetIndexBuffer(2, arrGBP);
   SetIndexLabel(2, "GBP"); 
   if(0 > StringFind(Symbol(), "CHF", 0))
       width = 1;
   else 
       width = Line_Thickness;
   SetIndexStyle(3, DRAW_SECTION, DRAW_SECTION, width, Color_CHF);
   SetIndexBuffer(3, arrCHF);
   SetIndexLabel(3, "CHF"); 
   if(0 > StringFind(Symbol(), "JPY", 0))
       width = 1;
   else 
       width = Line_Thickness;
   SetIndexStyle(4, DRAW_SECTION, DRAW_SECTION, width, Color_JPY);
   SetIndexBuffer(4, arrJPY);
   SetIndexLabel(4, "JPY"); 
   if(0 > StringFind(Symbol(), "AUD", 0))
       width = 1;
   else 
       width = Line_Thickness;
   SetIndexStyle(5, DRAW_SECTION, DRAW_SECTION, width, Color_AUD);
   SetIndexBuffer(5, arrAUD);
   SetIndexLabel(5, "AUD"); 
   if(0 > StringFind(Symbol(), "CAD", 0))
       width = 1;
   else 
       width = Line_Thickness;
   SetIndexStyle(6, DRAW_SECTION, DRAW_SECTION, width, Color_CAD);
   SetIndexBuffer(6, arrCAD);
   SetIndexLabel(6, "CAD"); 
   if(0 > StringFind(Symbol(), "NZD", 0))
       width = 1;
   else 
       width = Line_Thickness;
   SetIndexStyle(7, DRAW_SECTION, DRAW_SECTION, width, Color_NZD);
   SetIndexBuffer(7, arrNZD);
   SetIndexLabel(7, "NZD"); 

   // 4) place levels (horizontal reference lines on chart window)
   SetLevelStyle(STYLE_DOT, 1, Gray);
   SetLevelValue(0, 0);
}

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
  for(int i__ = 0; i__ < NCurrenciesUsed; i__++){
    if(!ObjectDelete(StringConcatenate("Legend_", i__)))
      Print("Deleting object ... error: code #", GetLastError());
  }
}

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate (
    const int      bars_total,           // size of input time series
    const int      bars_prev_calculated, // bars handled in previous call
    const datetime &time[],              // Time
    const double   &open[],              // Open
    const double   &high[],              // High
    const double   &low[],               // Low
    const double   &close[],             // Close
    const long     &tick_volume[],       // Tick Volume
    const long     &volume[],            // Real Volume
    const int      &spread[]             // Spread
    )
{
  static int iFreshBars;//bars to calculate
  int    i__;

  double EURUSD_Fast = 0,
         EURUSD_Slow = 0,
         GBPUSD_Fast = 0,
         GBPUSD_Slow = 0,
         AUDUSD_Fast = 0,
         AUDUSD_Slow = 0,
         NZDUSD_Fast = 0,
         NZDUSD_Slow = 0,
         USDCAD_Fast = 0,
         USDCAD_Slow = 0,
         USDCHF_Fast = 0,
         USDCHF_Slow = 0,
         USDJPY_Fast = 0,
         USDJPY_Slow = 0;

  if(0 == bars_prev_calculated){// first call to OnCalculate()
    iFreshBars = bars_total - 1 - Fast - Slow;//skip when there are not enough candles to calculate ma()
  }else{
    iFreshBars = bars_total - bars_prev_calculated + 1;
  }

  if(iFreshBars < 1)
    return (0);// exit if less than one bar (probably due to an error)

  for(i__ = iFreshBars; i__ >= 0; i__--){// BEGIN LOOP FOR
    // 1) Preliminary calculation -------------------------------------
    if(EUR){
      EURUSD_Fast = ma("EURUSD", Fast, MA_Method, Price, i__);
      EURUSD_Slow = ma("EURUSD", Slow, MA_Method, Price, i__);
      if(!EURUSD_Fast || !EURUSD_Slow)
        continue;//All indicators will be set to EMPTY_VALUE (to prevent Zero division)
    }
    if(GBP){
      // Preliminary calculation
      GBPUSD_Fast = ma("GBPUSD", Fast, MA_Method, Price, i__);
      GBPUSD_Slow = ma("GBPUSD", Slow, MA_Method, Price, i__);
      if(!GBPUSD_Fast || !GBPUSD_Slow)
        continue;//All indicators will be set to EMPTY_VALUE (to prevent Zero division)
    }
    if(AUD){
      // Preliminary calculation
      AUDUSD_Fast = ma("AUDUSD", Fast, MA_Method, Price, i__);
      AUDUSD_Slow = ma("AUDUSD", Slow, MA_Method, Price, i__);
      if(!AUDUSD_Fast || !AUDUSD_Slow)
        continue;//All indicators will be set to EMPTY_VALUE (to prevent Zero division)
    }
    if(NZD){
      // Preliminary calculation
      NZDUSD_Fast = ma("NZDUSD", Fast, MA_Method, Price, i__);
      NZDUSD_Slow = ma("NZDUSD", Slow, MA_Method, Price, i__);
      if(!NZDUSD_Fast || !NZDUSD_Slow)
        continue;//All indicators will be set to EMPTY_VALUE (to prevent Zero division)
    }
    if(CAD){
      // Preliminary calculation
      USDCAD_Fast = ma("USDCAD", Fast, MA_Method, Price, i__);
      USDCAD_Slow = ma("USDCAD", Slow, MA_Method, Price, i__);
      if(!USDCAD_Fast || !USDCAD_Slow)
        continue;//All indicators will be set to EMPTY_VALUE (to prevent Zero division)
    }
    if(CHF){
      // Preliminary calculation
      USDCHF_Fast = ma("USDCHF", Fast, MA_Method, Price, i__);
      USDCHF_Slow = ma("USDCHF", Slow, MA_Method, Price, i__);
      if(!USDCHF_Fast || !USDCHF_Slow)
        continue;//All indicators will be set to EMPTY_VALUE (to prevent Zero division)
    }
    if(JPY){
      // Preliminary calculation
      USDJPY_Fast = ma("USDJPY", Fast, MA_Method, Price, i__);
      USDJPY_Slow = ma("USDJPY", Slow, MA_Method, Price, i__);
      if(!USDJPY_Fast || !USDJPY_Slow)
        continue;//All indicators will be set to EMPTY_VALUE (to prevent Zero division)
    }

    // 2) calculation of currencies -----------------------------------
    if(USD){
      arrUSD[i__] = 0;
      if(EUR) 
        arrUSD[i__] += EURUSD_Slow / EURUSD_Fast - 1;
      if(GBP) 
        arrUSD[i__] += GBPUSD_Slow / GBPUSD_Fast - 1;
      if(AUD) 
        arrUSD[i__] += AUDUSD_Slow / AUDUSD_Fast - 1;
      if(NZD) 
        arrUSD[i__] += NZDUSD_Slow / NZDUSD_Fast - 1;
      if(CHF) 
        arrUSD[i__] += USDCHF_Fast / USDCHF_Slow - 1;
      if(CAD) 
        arrUSD[i__] += USDCAD_Fast / USDCAD_Slow - 1;
      if(JPY) 
        arrUSD[i__] += USDJPY_Fast / USDJPY_Slow - 1;
    }// end if USD
    if(EUR){
      arrEUR[i__] = 0;
      if(USD) 
        arrEUR[i__] += EURUSD_Fast / EURUSD_Slow - 1;
      if(GBP) 
        arrEUR[i__] += (EURUSD_Fast / GBPUSD_Fast) / 
          (EURUSD_Slow/GBPUSD_Slow) - 1;
      if(AUD) 
        arrEUR[i__] += (EURUSD_Fast / AUDUSD_Fast) / 
          (EURUSD_Slow/AUDUSD_Slow) - 1;
      if(NZD) 
        arrEUR[i__] += (EURUSD_Fast / NZDUSD_Fast) / 
          (EURUSD_Slow/NZDUSD_Slow) - 1;
      if(CHF) 
        arrEUR[i__] += (EURUSD_Fast*USDCHF_Fast) / 
          (EURUSD_Slow*USDCHF_Slow) - 1;
      if(CAD) 
        arrEUR[i__] += (EURUSD_Fast*USDCAD_Fast) / 
          (EURUSD_Slow*USDCAD_Slow) - 1;
      if(JPY) 
        arrEUR[i__] += (EURUSD_Fast*USDJPY_Fast) / 
          (EURUSD_Slow*USDJPY_Slow) - 1;
    }// end if EUR
    if(GBP){
      arrGBP[i__] = 0;
      if(USD) 
        arrGBP[i__] += GBPUSD_Fast / GBPUSD_Slow - 1;
      if(EUR) 
        arrGBP[i__] += (EURUSD_Slow / GBPUSD_Slow) / 
          (EURUSD_Fast / GBPUSD_Fast) - 1;
      if(AUD) 
        arrGBP[i__] += (GBPUSD_Fast / AUDUSD_Fast) / 
          (GBPUSD_Slow / AUDUSD_Slow) - 1;
      if(NZD) 
        arrGBP[i__] += (GBPUSD_Fast / NZDUSD_Fast) / 
          (GBPUSD_Slow / NZDUSD_Slow) - 1;
      if(CHF) 
        arrGBP[i__] += (GBPUSD_Fast*USDCHF_Fast) / 
          (GBPUSD_Slow*USDCHF_Slow) - 1;
      if(CAD) 
        arrGBP[i__] += (GBPUSD_Fast*USDCAD_Fast) / 
          (GBPUSD_Slow*USDCAD_Slow) - 1;
      if(JPY) 
        arrGBP[i__] += (GBPUSD_Fast*USDJPY_Fast) / 
          (GBPUSD_Slow*USDJPY_Slow) - 1;
    }// end if GBP
    if(AUD){
      arrAUD[i__] = 0;
      if(USD) 
        arrAUD[i__] += AUDUSD_Fast / AUDUSD_Slow - 1;
      if(EUR) 
        arrAUD[i__] += (EURUSD_Slow / AUDUSD_Slow) / 
          (EURUSD_Fast / AUDUSD_Fast) - 1;
      if(GBP) 
        arrAUD[i__] += (GBPUSD_Slow / AUDUSD_Slow) / 
          (GBPUSD_Fast / AUDUSD_Fast) - 1;
      if(NZD) 
        arrAUD[i__] += (AUDUSD_Fast/NZDUSD_Fast) / 
          (AUDUSD_Slow / NZDUSD_Slow) - 1;
      if(CHF) 
        arrAUD[i__] += (AUDUSD_Fast*USDCHF_Fast) / 
          (AUDUSD_Slow*USDCHF_Slow) - 1;
      if(CAD) 
        arrAUD[i__] += (AUDUSD_Fast*USDCAD_Fast) / 
          (AUDUSD_Slow*USDCAD_Slow) - 1;
      if(JPY) 
        arrAUD[i__] += (AUDUSD_Fast*USDJPY_Fast) / 
          (AUDUSD_Slow*USDJPY_Slow) - 1;
    }// end if AUD
    if(NZD){
      arrNZD[i__] = 0;
      if(USD) 
        arrNZD[i__] += NZDUSD_Fast / NZDUSD_Slow - 1;
      if(EUR) 
        arrNZD[i__] += (EURUSD_Slow / NZDUSD_Slow) / 
          (EURUSD_Fast/NZDUSD_Fast) - 1;
      if(GBP) 
        arrNZD[i__] += (GBPUSD_Slow / NZDUSD_Slow) / 
          (GBPUSD_Fast / NZDUSD_Fast) - 1;
      if(AUD) 
        arrNZD[i__] += (AUDUSD_Slow / NZDUSD_Slow) / 
          (AUDUSD_Fast / NZDUSD_Fast) - 1;
      if(CHF) 
        arrNZD[i__] += (NZDUSD_Fast*USDCHF_Fast) / 
          (NZDUSD_Slow*USDCHF_Slow) - 1;
      if(CAD) 
        arrNZD[i__] += (NZDUSD_Fast*USDCAD_Fast) / 
          (NZDUSD_Slow*USDCAD_Slow) - 1;
      if(JPY) 
        arrNZD[i__] += (NZDUSD_Fast*USDJPY_Fast) / 
          (NZDUSD_Slow*USDJPY_Slow) - 1;
    }// end if NZD
    if(CAD){
      arrCAD[i__] = 0;
      if(USD) 
        arrCAD[i__] += USDCAD_Slow / USDCAD_Fast - 1;
      if(EUR) 
        arrCAD[i__] += (EURUSD_Slow*USDCAD_Slow) / 
          (EURUSD_Fast*USDCAD_Fast) - 1;
      if(GBP) 
        arrCAD[i__] += (GBPUSD_Slow*USDCAD_Slow) / 
          (GBPUSD_Fast*USDCAD_Fast) - 1;
      if(AUD) 
        arrCAD[i__] += (AUDUSD_Slow*USDCAD_Slow) / 
          (AUDUSD_Fast*USDCAD_Fast) - 1;
      if(NZD) 
        arrCAD[i__] += (NZDUSD_Slow*USDCAD_Slow) / 
          (NZDUSD_Fast*USDCAD_Fast) - 1;
      if(CHF) 
        arrCAD[i__] += (USDCHF_Fast / USDCAD_Fast) / 
          (USDCHF_Slow / USDCAD_Slow) - 1;
      if(JPY) 
        arrCAD[i__] += (USDJPY_Fast / USDCAD_Fast) / 
          (USDJPY_Slow / USDCAD_Slow) - 1;
    }// end if CAD
    if(CHF){
      arrCHF[i__] = 0;
      if(USD) 
        arrCHF[i__] += USDCHF_Slow / USDCHF_Fast - 1;
      if(EUR) 
        arrCHF[i__] += (EURUSD_Slow*USDCHF_Slow) / 
          (EURUSD_Fast*USDCHF_Fast) - 1;
      if(GBP) 
        arrCHF[i__] += (GBPUSD_Slow*USDCHF_Slow) / 
          (GBPUSD_Fast*USDCHF_Fast) - 1;
      if(AUD) 
        arrCHF[i__] += (AUDUSD_Slow*USDCHF_Slow) / 
          (AUDUSD_Fast*USDCHF_Fast) - 1;
      if(NZD) 
        arrCHF[i__] += (NZDUSD_Slow*USDCHF_Slow) / 
          (NZDUSD_Fast*USDCHF_Fast) - 1;
      if(CAD) 
        arrCHF[i__] += (USDCHF_Slow / USDCAD_Slow) / 
          (USDCHF_Fast / USDCAD_Fast) - 1;
      if(JPY) 
        arrCHF[i__] += (USDJPY_Fast / USDCHF_Fast) / 
          (USDJPY_Slow / USDCHF_Slow) - 1;
    }// end if CHF
    if(JPY){
      arrJPY[i__] = 0;
      if(USD) 
        arrJPY[i__] += USDJPY_Slow / USDJPY_Fast - 1;
      if(EUR) 
        arrJPY[i__] += (EURUSD_Slow*USDJPY_Slow) / 
          (EURUSD_Fast*USDJPY_Fast) - 1;
      if(GBP) 
        arrJPY[i__] += (GBPUSD_Slow*USDJPY_Slow) / 
          (GBPUSD_Fast*USDJPY_Fast) - 1;
      if(AUD) 
        arrJPY[i__] += (AUDUSD_Slow*USDJPY_Slow) / 
          (AUDUSD_Fast*USDJPY_Fast) - 1;
      if(NZD) 
        arrJPY[i__] += (NZDUSD_Slow*USDJPY_Slow) / 
          (NZDUSD_Fast*USDJPY_Fast) - 1;
      if(CAD) 
        arrJPY[i__] += (USDJPY_Slow/USDCAD_Slow) / 
          (USDJPY_Fast/USDCAD_Fast) - 1;
      if(CHF) 
        arrJPY[i__] += (USDJPY_Slow/USDCHF_Slow) / 
          (USDJPY_Fast/USDCHF_Fast) - 1;
    }// end if JPY
  }//--END loop for

  return(bars_total);//bars_total will be next bars_prev_calculated 
}

//+------------------------------------------------------------------+
//|  Subroutines                                                     |
//+------------------------------------------------------------------+
double ma(string sym, int per, int mode, int price, int i)
{
  int    k        = 1,
         ma_shift = 0,
         tf       = 0;
  double res      = 0;
  switch(Period())
  {
    case 1:     res += iMA(sym, tf, per*k, ma_shift, mode, price, i); 
                k += 5;
    case 5:     res += iMA(sym, tf, per*k, ma_shift, mode, price, i); 
                k += 3;
    case 15:    res += iMA(sym, tf, per*k, ma_shift, mode, price, i); 
                k += 2;
    case 30:    res += iMA(sym, tf, per*k, ma_shift, mode, price, i); 
                k += 2;
    case 60:    res += iMA(sym, tf, per*k, ma_shift, mode, price, i); 
                k += 4;
    case 240:   res += iMA(sym, tf, per*k, ma_shift, mode, price, i); 
                k += 6;
    case 1440:  res += iMA(sym, tf, per*k, ma_shift, mode, price, i); 
                k += 4;
    case 10080: res += iMA(sym, tf, per*k, ma_shift, mode, price, i); 
                k +=4;
    case 43200: res += iMA(sym, tf, per*k, ma_shift, mode, price, i); 
  } 
  return(res);
}   

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void SetLegend(string sym, int y, color col)
{
  int    window   = WindowFind(Indicator_Name);
  int    y_offset = 25;//pixels to offset from origin
  string ID       = StringConcatenate("Legend_", NCurrenciesUsed);

  NCurrenciesUsed++;

  if(ObjectCreate(ID, OBJ_LABEL, window, 0, 0)){
    //ObjectSet(ID, OBJPROP_CORNER, 1);
    ObjectSet(ID, OBJPROP_XDISTANCE, y + y_offset);
    ObjectSet(ID, OBJPROP_YDISTANCE, 0);
    ObjectSetText(ID, sym, 18, "Arial Black", col);
  }
}   

//+------------------------------------------------------------------+
