#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
#include <sstream>   // file I/O
#include <fstream>   // file I/O
#include <Eigen/Core>

using namespace std;

int main(int, char *[])
{
   ifstream fp_in("DJprices.csv");
   if (fp_in.fail())
   {
       cout << "Input file opening failed.\n";
       exit(1);
   }
   
   int m;
   int n;
   int const lineNum=124;
   int const columnNum=31;
   string prices[columnNum][lineNum];
   string line;
   int pos;

    //copy everything on the "DJprices.csv" file onto the prices[columnNum][lineNum].
   for (n = 0; n < lineNum; n++)
   {
	getline(fp_in, line, '\n' );
	for (m=0; m < columnNum; m++)
	{
      pos=line.find(",", 0);
      prices[m][n] = line.substr(0,pos);
      line.erase(0, pos+1);
	}
   }

   fp_in.close();//close the input file "DJprices.csv"
		
	double prices_in_double[columnNum-1][lineNum-1];
    //convert the prices part from string to double
	for (n = 0; n < lineNum-1; n++)
	{
	    for (m = 0; m < columnNum-1; m++)
            {
		       prices_in_double[m][n] = atof(prices[m+1][n+1].c_str());
                  //the prices_in_double therefore only contains prices
                  //it does not contain dates or names
            }
	}
        
    string returns[columnNum][lineNum];//Find the returns for each company.
    for (n=0; n < lineNum; n++)
    {
      returns[0][n] = prices[0][n];
    }//copy the dates into returns

    for(m=0; m < columnNum; m++)
    {
      returns[m][0] = prices[m][0];
    }//copy the names of companies into returns
    
	for (m = 1; m < columnNum; m++)
    {
       returns[m][1] = " ";
       //the returns for the first given date is always NULL for each company.
       for (n = 2; n < lineNum; n++)
       {
         double i;
         i = (prices_in_double[m-1][n-1] - prices_in_double[m-1][n-2])
             / prices_in_double[m-1][n-2];
         //the returns for each date is based on the difference between
         //the current price and previous price divided by the previous.
         ostringstream strs;
         strs << i;
         returns[m][n] = strs.str();
         //convert the returns into string and store them into returns[m][n]
       }
    }

   //print the returns[m][n] onto the CSV file
   ofstream detail_output("DJreturns.csv");

   ofstream detail_output2("DJbook.csv");
        
   for(n=0; n<lineNum; n++)
   {
       for(m=0; m<columnNum-1; m++)
       {
          detail_output << returns[m][n] << ",";
       }
       detail_output << returns[columnNum-1][n] << "\n";
   }
   
//Find the highest return for company "IBM"
//   int const companyLoc = returns[columnNum][0].find("IBM");
//   cout << companyLoc << endl;
   double returns_in_double[lineNum];//store returns in double for the column under IBM
   returns_in_double[0] = 0;
   returns_in_double[1] = 0;
   double max = 0.0;
   for (n=2; n<lineNum; n++)
   {
       returns_in_double[n] = atof(returns[13][n].c_str());
	   if (returns_in_double[n] > max)
       {
           max = returns_in_double[n];
       }
   }//find the maximum of the returns of IBM
       
   int dateLoc = 2;
   while (returns_in_double[dateLoc] < max)
   {
	   dateLoc++;
   }
   string date1 = returns[0][dateLoc];//find the date with the highest return of IBM

   cout << "The highest return for IBM is " << max << endl;
   detail_output << " " << "," << "IBM" << "," << "\n";
   detail_output << date1 << "," << max << "," << "\n";
   detail_output << "\n";
   
//Find the lowest return for company "XOM"
//int const companyLoct = returns[columnNum][0].find("XOM");
   double min = 10.0;
   double returns_in_double2[lineNum];//store returns for column under XOM
   returns_in_double2[0] = 0;
   returns_in_double2[1] = 0;

   for (n=2; n<lineNum; n++)
   {
	   returns_in_double2[n] = atof(returns[30][n].c_str());
       if (returns_in_double2[n] < min)
       {
           min = returns_in_double2[n];
       }
   }//fine the minimum of the returns of XOM

   int dateLoct = 2;
   while (returns_in_double2[dateLoct] > min)
   {
      dateLoct++;
   }
   string date2 = returns[0][dateLoct];//find the date with the lowest return for XOM

   cout << endl;
   cout << "The lowest return for XOM is " << min << endl;
   detail_output << " " << "," << "XOM" << "," << "\n";
   detail_output << date2 << "," << min << "," << "\n";
   detail_output << "\n";

//Find and write out the daily value of the portfolio if containing 10 shares of each security.
   
   string portfolio[2][lineNum];
   //copy the first column(dates) from the original sheet to the portfolio sheet
   for(n=0; n<lineNum; n++)
   {
   portfolio[0][n] = prices[0][n];
   }
   portfolio[1][0] = "Value";//mark the head of second column with "Value".
   for(n=1; n<lineNum; n++)
   {
	   //calculate the value of the portfolio on each date
       double val;
       double sum= 0.0;
       for(m=1; m < columnNum; m++)
       {
           sum += prices_in_double[m-1][n-1];//start from prices_in_double[0][0]
       }
       val = 10 * sum;
	   //Convert the values from double to string in the next three steps
	   //and store the string of value into the second column of portfolio 
	   ostringstream strs;
       strs << val;
       portfolio[1][n] = strs.str();
   }

   //write the portfolio values on each date onto the "DJbook.csv" file.
   for(n=0;n<lineNum;n++)
   {
      detail_output2 << portfolio[0][n] << "," << portfolio[1][n] << "," << "\n";
   }

   //close the output file "DJbook.csv".
   detail_output2.close();
   
   ofstream detail_output3("djia_cov.csv");//create and open a new file "djia_cov.csv" 
   Eigen::MatrixXf X(lineNum-2, columnNum-1);
   for (int j = 0; j < columnNum-1; n++)
   {
	   for (int i=0; i < lineNum-2; m++)
		   X(i,j) = atof(returns[j+1][i+2].c_str());
   }
   cout << "Matrix X is: \n"
	   << X << endl;
   Eigen::MatrixXf Xtrans = X.transpose();
   Eigen::MatrixXf One(30, 1);
   One.setOnes();
   Eigen::MatrixXf OneTrans;
   OneTrans = One.transpose();
   Eigen::MatrixXf Identity(30, 30);
   Identity.setIdentity();

   Eigen::MatrixXf CovMat;
   int T = lineNum-2;
   //using the formula S=1/T*X(I-1/T*11')X'
   CovMat = (1/T)* X * (Identity - (1/T) * One * OneTrans) * Xtrans;

   //store the coefficients of the covariance matrix into a string array
   string CovMatrix[columnNum-1][lineNum-2];
   ostringstream strss;

   for (m = 0; m < columnNum-1; m++)
   {   for (n = 0; n < lineNum-2; n++)
           
           strss << CovMat(n, m);
           CovMatrix[m][n] = strss.str();
           //convert the coefficient into strings.
   }//copy the covariance efficients into CovMatrix

   //write the CovMatrix onto the file "djia_cov.csv"
   for (n=0; n < lineNum-2; n++)
   {
	   for (m=0; m < columnNum-2; m++)
	   {
          detail_output3 << CovMatrix[m][n] << ",";
	   }
       detail_output3 << CovMatrix[columnNum-2][n] << "," << "\n";
   }
   
   //Calculate the mean vector of the return matrix
   //according to the formula m = (1/T)X1
   Eigen::VectorXf MeanV(columnNum-1);
   Eigen::VectorXf ComfOne(columnNum-1);
   ComfOne.setOnes();
   MeanV = (1/lineNum-2) * X * ComfOne;
   
   //print out the mean vector onto the file "djia_cov.csv"
   detail_output3 << "\nMean Vector:" << "\n";
   for (int i=0; i < lineNum-2; i++)
       detail_output3 << MeanV[i] << "," << "\n";

   
   //running regression between the prices and the historial prices of each company
   //using the method of OLS: beta = (X'X)^(-1)X'y , X(regressor) being the
   //S&P returns vector, y(regressand) being the vector of price of each company
   //First, set up Xsp as the regressor as a vector of returns of the S&P.
   
   ifstream sp_in("sp_prices.csv");
   if (sp_in.fail())
   {
       cout << "Input file sp_prices opening failed.\n";
       exit(1);
   }
   
   string SP[125];//an array that we use to store the SP prices
   string sp_line;
   int paus;

    //copy everything on the "sp_prices.csv" file onto the SPreturns[2][125].
   getline(sp_in, sp_line, '\n' );//we don't need the first row since it's "date" and "prices"
   getline(sp_in, sp_line, '\n' );//we don't need the price on 1/4/2010
   for (n = 0; n < 123; n++)
   {
	 getline(sp_in, sp_line, '\n' );//we need the prices starting from 1/5/2010
     paus=sp_line.find(",", 0);
     sp_line.erase(0, paus+1);//we don't need the first column of every row since it's the date
	 SP[n] = sp_line.substr();//store the price of each date into SP
   }
   
   double SPprices[123];
   for(int i = 0; i < 123; i++)
	   SPprices[i] = atof(SP[i].c_str());//convert S&P prices from string to double
   double SPreturns[122];
   for(int i=0; i < 122; i++)//calculate the returns of S&P prices
	   SPreturns[i] = (SPprices[i+1] - SPprices[i]) / SPprices[i];

   Eigen::VectorXf Xsp(122);//there are only 122 valid prices in total

   for(int i=0; i < 122; i++)
   {
	   Xsp(i) = SPreturns[i];
	   //convert string to double and store the SPprices to second column
   }

   //find the transpose of Xsp
   Eigen::VectorXf XspTrans(122) ;
   XspTrans = Xsp.transpose();
   //set up IBMreturn,the regressand as a vector of the historical prices of IBM
   Eigen::VectorXf IBMreturns(122);
   for(int i=0; i<122; i++)
	   IBMreturns[i] = returns_in_double[i];
   //set up XOMreturn,the regressand as a vector of the historical prices of XOM
   Eigen::VectorXf XOMreturns(122);
   for(int i=0; i<122; i++)
	   XOMreturns[i] = returns_in_double2[i];

   //find the inverse of X'X, which is the product of Xsp and XspTrans here.
   double inverse;
   double product;
   product = Xsp.dot(XspTrans);
   inverse = 1/product;

   //apply the formula to find beta for IBM
   double IBMbeta;
   IBMbeta = inverse * (XspTrans.dot(IBMreturns));
   cout << "Beta for IBM is " << IBMbeta << endl;

   //apply the formula to find beta for XOM
   double XOMbeta;
   XOMbeta = inverse * (XspTrans.dot(XOMreturns));
   cout << "Beta for XOM is " << XOMbeta << endl;

   //To find the alpha for the two companies
   //according to the formula of y = beta*X + alpha + Epsilon, alpha stands for
   //the intercept of the regression trend line, we can compute alpha as 
   //alpha = mean of regressands - beta*mean of regressors
   double IBMalpha;
   double XOMalpha;
   double SPmean, IBMmean, XOMmean;
   double sum1, sum2, sum3 = 0;
   for (int n=0; n < lineNum; n++)
	   sum1 += returns_in_double[n];
   IBMmean = sum1/(lineNum-2);
   for (int n = 0; n < lineNum; n++)
	   sum2 += returns_in_double2[n];
   XOMmean = sum2/(lineNum-2);
   for (int n=0; n < 122; n++)
	   sum3 += SPreturns[n];
   SPmean = sum3/122;
   
   IBMalpha = IBMmean - IBMbeta * SPmean;
   XOMalpha = XOMmean - XOMbeta * SPmean;
   cout << "Alpha for IBM is " << IBMalpha << ". Alpha for XOM is " << XOMalpha << endl;


   //print the results into the file "djia_sp_lm.csv"
   ofstream detail_output4("djia_sp_lm.csv");
   detail_output4 << "Symbol" << "," << "Beta" << "," << "Alpha" << "\n";
   detail_output4 << "IBM" << "," << IBMbeta << "," << IBMalpha << "\n";
   detail_output4 << "XOM" << "," << XOMbeta << "," << XOMalpha << "\n";
   detail_output4 << endl;

   detail_output4.close();
   
   return 0;

}
