//+------------------------------------------------------------------+
//|                                        Tradable Correlations.mq4 |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2011, smjones"
#property link      "sjcoinc2000@yahoo.com"

#property indicator_chart_window

extern int     CorrelationPeriods = 50;
extern int     CorrelationTimeFrame = 1440;
extern double  PositiveAbove = 75;
extern double  NegativeBelow = -75;
extern int     StochTimeFrame = 5;
extern int     K = 100;
extern int     D = 1;
extern int     S = 1;
extern int     FontSize = 10;
extern bool    SortByColumns = true;
extern int     Columns = 3;
extern int     Rows = 22;
extern int     X_Spacing = 300;
extern int     Y_Spacing = 17;
extern color   PositiveColor = Aqua;
extern color   NegativeColor = Red;
extern color   HighlightColor = Green;
extern color   TitleColor = Yellow;

//datetime cor_once = 0;
string m="",title,T;
string s[24],temp_p[576],temp_n[576],pc[576],nc[576];
double c[24][24];

int lastAlert[24][24];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
      m = StringSubstr(Symbol(),6,StringLen(Symbol())-6);
      
      s[0]="AUDCAD"+m;  s[1]="AUDCHF"+m;  s[2]="AUDJPY"+m;  s[3]="AUDNZD"+m;  s[4]="AUDUSD"+m;
      s[5]="CADJPY"+m;  s[6]="CHFJPY"+m;  s[7]="EURAUD"+m;  s[8]="EURCAD"+m;  s[9]="EURCHF"+m;
      s[10]="EURGBP"+m; s[11]="EURJPY"+m;  s[12]="EURUSD"+m; s[13]="GBPAUD"+m; 
      s[14]="GBPCAD"+m; s[15]="GBPCHF"+m; s[16]="GBPJPY"+m;  s[17]="GBPUSD"+m;
      s[18]="NZDCHF"+m; s[19]="NZDJPY"+m; s[20]="NZDUSD"+m; s[21]="USDCAD"+m; s[22]="USDCHF"+m;
      s[23]="USDJPY"+m;
      
      if ( CorrelationTimeFrame == 1 ) T = "M1";
      if ( CorrelationTimeFrame == 5 ) T = "M5";
      if ( CorrelationTimeFrame == 15 ) T = "M15";
      if ( CorrelationTimeFrame == 30 ) T = "M30";
      if ( CorrelationTimeFrame == 60 ) T = "H1";
      if ( CorrelationTimeFrame == 240 ) T = "H4";
      if ( CorrelationTimeFrame == 1440 ) T = "D1";
      if ( CorrelationTimeFrame == 10080 ) T = "W1";
      if ( CorrelationTimeFrame == 43200 ) T = "MN"; 
      
       
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
  {
      Comment("");
      DeleteObject("Corr");
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {
 
      string name_pos,name_neg,tempstrp,tempstrn;
      double tempvalue,tempstoch;
      int cnt = ArraySize(temp_p),pos=0,neg=0;
      for(int ii=0;ii<cnt;ii++)
         {
            temp_p[ii] = "";
            temp_n[ii] = "";
            pc[ii] = "";
            nc[ii] = "";
         }
      
   //if( cor_once != iTime(Symbol(),CorrelationTimeFrame,0) )
      //{         
       //cor_once = iTime(Symbol(),CorrelationTimeFrame,0);
       int count = ArraySize(s);
       for(int i=0;i<count;i++)
         {
            for(int n=0;n<count;n++)
               {
                  tempvalue = 100*cp(s[i],s[n],CorrelationTimeFrame,CorrelationPeriods);
                  if ( tempvalue < -100 ) 
                     tempvalue = 0;  //Currency pair not in list from broker 
                  tempstoch = stochdiff(s[i],s[n], StochTimeFrame, K, D, S); 
                  
                  c[i][n]= tempvalue;
                                    
                  if( c[i][n] >= PositiveAbove && c[i][n] < 99.99 )
                     {
                        temp_p[pos]= StringSubstr(s[i],0,6)+" | "+StringSubstr(s[n],0,6)+ "  "+DoubleToStr(spread(s[i],s[n]),0)+"   Cor: "+DoubleToStr(c[i][n],0)
                        +"   Sto:  "+DoubleToStr(tempstoch,0);
                        pos++;
                     }
                  if( c[i][n] <= NegativeBelow )
                     {
                        temp_n[neg]= StringSubstr(s[i],0,6)+" | "+StringSubstr(s[n],0,6)+"  "+DoubleToStr(spread(s[i],s[n]),0)+"   Cor: "+DoubleToStr(c[i][n],0)
                        +"   StoDiff:  "+DoubleToStr(tempstoch,0);
                        neg++;
                     }       
               }// end for n  
                         
         }//end for i
       //ArrayResize(temp_p,pos);
       int pc_cnt=0;
       for(i=0;i<pos;i++)
         {
            tempstrp = StringSubstr(temp_p[i],9,6)+" | "+StringSubstr(temp_p[i],0,6);
            for(int b=0;b<pos;b++)
               {
                 if ( StringSubstr(temp_p[b],0,15) == tempstrp )
                  {
                     temp_p[b] = "";
                  }  
               }
            if ( temp_p[i] != "" )
               {
                  pc[pc_cnt] = temp_p[i];
                  pc_cnt++;
               }                         
         }
       
       //ArrayResize(temp_n,neg);   
       int nc_cnt = 0;
       for(i=0;i<neg;i++)
         {
            tempstrn = StringSubstr(temp_n[i],9,6)+" | "+StringSubstr(temp_n[i],0,6);
            for(b=0;b<neg;b++)
               {
                 if ( StringSubstr(temp_n[b],0,15) == tempstrn )
                  {
                     temp_n[b] = "";
                  }  
               }
            if ( temp_n[i] != "" )
               {
                  nc[nc_cnt] = temp_n[i];
                  nc_cnt++;
               }                         
         }
       
       
         
       DeleteObject("Corr");  
       //ArrayResize(pc,pc_cnt);
       
       int  xspace=X_Spacing,yspace=Y_Spacing,xx=0,yy=0;  
       for( i=0;i<pc_cnt;i++ )
         {
            ObjectCreate("CorrPos"+DoubleToStr(i,0),OBJ_LABEL,0,0,0);
            ObjectSet("CorrPos"+DoubleToStr(i,0),OBJPROP_XDISTANCE,xx*xspace);
            ObjectSet("CorrPos"+DoubleToStr(i,0),OBJPROP_YDISTANCE,yy*yspace);
            if(MathAbs(StrToDouble(getNth(pc[i],13))) < 80) ObjectSetText("CorrPos"+DoubleToStr(i,0), pc[i], FontSize, "Arial", PositiveColor);
            else {
               ObjectSetText("CorrPos"+DoubleToStr(i,0), pc[i], FontSize, "Arial", HighlightColor);
                  string pair1 = getNth(pc[i],0);
                  string pair2 = getNth(pc[i],2);
                  int pos1 = getPos(s, pair1);
                  int pos2 = getPos(s, pair2);
               if(pos1 != -1 && pos2 != -1 && lastAlert[pos1][pos2] < TimeCurrent()/60) {
                  Alert("Diff>80 " + pair1 + " " + pair2);
                  lastAlert[pos1][pos2] = TimeCurrent()/60;
               }
            }
            if ( SortByColumns )
               {
                  yy++;
                  if ( yy==Rows)
                     {
                        yy = 0;
                        xx++;
                     }  
               }
            else
               {   
                  xx++;
                  if ( xx==Columns ) 
                     {
                        xx = 0;
                        yy++;
                     }
               }               
         } // end for i
        
       //ArrayResize(nc,nc_cnt);
       if (SortByColumns )
         {
            yy=0;xx++; 
         }
       else
         {   
            xx=0;yy++;yy++;
         }     
       for( i=0;i<nc_cnt;i++ )
         {
            ObjectCreate("CorrNeg"+DoubleToStr(i,0),OBJ_LABEL,0,0,0);
            ObjectSet("CorrNeg"+DoubleToStr(i,0),OBJPROP_XDISTANCE,xx*xspace);
            ObjectSet("CorrNeg"+DoubleToStr(i,0),OBJPROP_YDISTANCE,yy*yspace);
            if(MathAbs(StrToDouble(getNth(nc[i],13))) < 80) ObjectSetText("CorrNeg"+DoubleToStr(i,0), nc[i], FontSize, "Arial", NegativeColor);
            else { 
               ObjectSetText("CorrNeg"+DoubleToStr(i,0), nc[i], FontSize, "Arial", HighlightColor); 
               pair1 = getNth(nc[i],0);
               pair2 = getNth(nc[i],2);
               pos1 = getPos(s, pair1);
               pos2 = getPos(s, pair2);
               if(pos1 != -1 && pos2 != -1 && lastAlert[pos1][pos2] < TimeCurrent()/60) {
                  Alert("Diff>80 " + pair1 + " " + pair2);
                  lastAlert[pos1][pos2] = TimeCurrent()/60;
               }
            }
            if ( SortByColumns )
               {
                  yy++;
                  if ( yy==Rows) 
                     {
                        yy = 0;
                        xx++;
                     }
               }
            else
               {
                  xx++;
                  if ( xx==Columns ) 
                     {
                        xx = 0;
                        yy++;
                     }
               }               
         } // end for i
         
       title = "Correlation Table "+T+"@ "+DoubleToStr(CorrelationPeriods,0)+" Periods > "+DoubleToStr(PositiveAbove,1)+"% And < "+DoubleToStr(NegativeBelow,1)+"%"; 
       ObjectCreate("CorrTitle",OBJ_LABEL,0,0,0);
       ObjectSet("CorrTitle",OBJPROP_XDISTANCE,225);
       ObjectSet("CorrTitle",OBJPROP_YDISTANCE,575);
       ObjectSetText("corrTitle",title,16,"Arial",TitleColor);  
        
      //}//end if cor_once
                         

      return(0);
  }
//+------------------------------------------------------------------+
//******************************************************************************
double   cp(string Symbol1,string Symbol2,int TimeFrame, int periods)
{
	//Comment( Symbol1,"  ",Symbol2,"  ",TimeFrame,"  ",periods);
	datetime closeTime1	= iTime(Symbol1,TimeFrame,0),
				closeTime2	= iTime(Symbol2,TimeFrame,0),
				closeTime	= MathMin(closeTime1,closeTime2);
	int		shift1		= iBarShift(Symbol1,TimeFrame,closeTime),
				shift2		= iBarShift(Symbol2,TimeFrame,closeTime);
	double	Co,
	         close1[],
				close2[];

	ArrayCopySeries(close1,MODE_CLOSE,Symbol1,TimeFrame);
	ArrayCopySeries(close2,MODE_CLOSE,Symbol2,TimeFrame);

	int bars = MathMin(ArraySize(close1)-shift1,ArraySize(close2)-shift2);
	if ( periods > 0 )
	     bars = periods;
   Co = Correlation(close1,close2,shift1,shift2,bars);
   
   return(Co);
}



//+------------------------------------------------------------------+
//| Correlation Coefficient R														|
//+------------------------------------------------------------------+
double Correlation(double x[], double y[], int x_shift = 0, int y_shift = 0, int count = -1)
{
	int n = MathMin(ArraySize(x)-x_shift,ArraySize(y)-y_shift);
	if(n>count && count>0)
		n=count;
	if(n<2)
		return(-2);

	double	sum_sq_x,
				sum_sq_y,
				sum_coproduct,
				mean_x = x[x_shift],
				mean_y = y[y_shift];

	for(int i = 0; i < n; i++)
	{
		double	sweep = i / (i+1.0),
					delta_x = x[i+x_shift] - mean_x,
					delta_y = y[i+y_shift] - mean_y;

		sum_sq_x += delta_x*delta_x * sweep;
		sum_sq_y += delta_y*delta_y * sweep;
    	sum_coproduct += delta_x*delta_y * sweep;
    	mean_x += delta_x / (i+1.0);
    	mean_y += delta_y / (i+1.0);
	}

	double	pop_sd_x = MathSqrt(sum_sq_x/n),
				pop_sd_y = MathSqrt(sum_sq_y/n),
				cov_x_y = sum_coproduct / n;

	if(pop_sd_x*pop_sd_y != 0.0)
		return(cov_x_y / (pop_sd_x*pop_sd_y));

	return(-3);
}

//*******************************************************************************
void DeleteObject(string char4)
   {
      string name;      
      int obj = ObjectsTotal();
      for ( int n=obj;n >= 0 ;n--)
         {
            name = ObjectName(n);
            char4 = StringSubstr(name,0,4);
            if ( char4 == "Corr" )
               ObjectDelete(name);   
         }
      return;
   }           

//********************************************************************************
double stochdiff(string symbol1,string symbol2, int timeframe, int k, int d, int s)
   {
      double diff,sto1,sto2;
      sto1 = iStochastic(symbol1,timeframe,k,d,s,0,0,0,0);
      sto2 = iStochastic(symbol2,timeframe,k,d,s,0,0,0,0);
      diff = sto1-sto2; 
      
      return(diff);
   } 
   
 double spread(string symbol1,string symbol2){
 
    /* if(symbol1=="AUDCHF" && symbol2=="USDCHF" )
     Print(" audchf spread "+MarketInfo(symbol1, MODE_SPREAD) +" spread "+MarketInfo(symbol2, MODE_SPREAD) +" point1 "+MarketInfo(symbol1, MODE_POINT)+" point2 "+MarketInfo(symbol2, MODE_POINT)
     );
     
     if(symbol1=="USDCHF" && symbol2=="USDJPY" )
     Print(" USDCHF spread "+MarketInfo(symbol1, MODE_SPREAD) +" spread "+MarketInfo(symbol2, MODE_SPREAD) +" point1 "+MarketInfo(symbol1, MODE_POINT)+" point2 "+MarketInfo(symbol2, MODE_POINT)
     );
 */
    return(getSpreadBySymbol(symbol1)+getSpreadBySymbol(symbol2));
 
 }
 
 double getSpreadBySymbol(string symbol){
 
 double spread;
 double point = MarketInfo(symbol, MODE_POINT);  
   
   if (point == 0.00001) // Calculate the spread in pips for symbols quoted to 5 decimal places
{
spread = ((MarketInfo(symbol, MODE_ASK) - MarketInfo(symbol, MODE_BID)) / (point*10)); // Current Spread price for this CurrencyPair in pip form.
}

if (point == 0.0001) // Calculate the spread in pips for symbols quoted to 4 decimal places
{
spread = ((MarketInfo(symbol, MODE_ASK) - MarketInfo(symbol, MODE_BID)) / (point)); // Current Spread price for this CurrencyPair in pip form.
}

if (point == 0.001) // Calculate the spread in pips for symbols quoted to 3 decimal places
{
spread = ((MarketInfo(symbol, MODE_ASK) - MarketInfo(symbol, MODE_BID)) / (point*10)); // Current Spread price for this CurrencyPair in pip form.
}

if (point == 0.01) // Calculate the spread in pips for symbols quoted to 2 decimal places
{
spread = ((MarketInfo(symbol, MODE_ASK) - MarketInfo(symbol, MODE_BID)) / (point)); // Current Spread price for this CurrencyPair in pip form.
}
//Print("symbol "+symbol + " spread " +spread);
return(spread);
}       

string getNth(string input, int index)
{
string sep = " ";
int count=0;
int oldpos=0;
int pos=StringFind(input,sep,0);
while(pos>=0&&count<=index)
{
if(count==index)
   if(pos==oldpos)
      return("");
   else
      return(StringSubstr(input,oldpos,pos-oldpos));
   oldpos=pos+StringLen(sep);
   pos=StringFind(input,sep,oldpos);
   count++;
}
if(count==index)
   return(StringSubstr(input,oldpos));

return("");
}

int getPos(string s[], string pair)
{
for(int i = 0; i < ArraySize(s); i++)
   if(s[i] == pair) return(i);
return(-1);
}