Overall Statistics
using MathNet.Numerics.LinearAlgebra;
using MathNet.Numerics.LinearRegression;
using MathNet.Numerics.Statistics;
using QuantConnect.Data;
using QuantConnect.Indicators;
using System;
using System.Collections.Generic;
using System.Linq;

namespace QuantConnect.Algorithm.CSharp
{
    /// <summary>
    /// This algorithm uses Math.NET Numerics library, specifically Linear Algebra object (Vector and Matrix) and operations, in order to solve a portfolio optimization problem.
    /// </summary>
    public class MultiCorrelation : QCAlgorithm
    {
        private string[] _symbols = new string[]
        {
        	// Using Meb Faber's GTAA paper assets:
            "SPY",   // 
    		"AIG",   // 
    		"BAC"    //
    		// Find more symbols here: http://quantconnect.com/data
        };
        private const double _targetReturn = 0.1;
        private const double _riskFreeRate = 0.01;
        private double _lagrangeMultiplier;
        private double _portfolioRisk;
        private Vector<double> _p;
        private List<SymbolData> SymbolDataList;
        
        /// <summary>
        /// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
        /// </summary>
        public override void Initialize()
        {
            SetCash(100000);           //Set Strategy Cash
            SetStartDate(2013, 1, 1);  //Set Start Date
            SetEndDate(DateTime.Now.AddDays(-1));   //Set End Date

            SymbolDataList = new List<SymbolData>();

            foreach (var symbol in _symbols)
            {
                AddEquity(symbol, Resolution.Daily);
                SymbolDataList.Add(new SymbolData(symbol, History(symbol, 200, Resolution.Daily)));
            }

            var X = Matrix<double>.Build.
                DenseOfColumnArrays(SymbolDataList.Where(x => !x.Symbol.Equals("SPY")).Select(x => x.History));
            
            var y = Vector<double>.Build.
                DenseOfArray(SymbolDataList.Where(x => x.Symbol.Equals("SPY")).FirstOrDefault().History);

            _p = MultipleRegression.NormalEquations(X, y);

        }

        /// <summary>
        /// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
        /// </summary>
        /// <param name="data">Slice object keyed by symbol containing the stock data</param>
        public override void OnData(Slice data)
        {
            foreach (var symbolData in SymbolDataList)
            {
                if (data.ContainsKey(symbolData.Symbol))
                {
                    symbolData.Update(data[symbolData.Symbol]);
                }
            }

            var y = (double)data["SPY"].Close;
            var x = _p[0] * (double)data["AIG"].Close + _p[1] * (double)data["BAC"].Close;

            if (x > y)
            {
                SetHoldings("AIG", .5);
                SetHoldings("BAC", .5);
            }
            else
            {
                SetHoldings("AIG", -.5);
                SetHoldings("BAC", -.5);
            }

        }

        /// <summary>
        /// Symbol Data class to store security data (Return, Risk, Weight)
        /// </summary>
        class SymbolData
        {
            private RollingWindow<double> _rollingHistory;
            public Symbol Symbol { get; private set; }
            public double[] History
            {
                get
                {
                    return _rollingHistory.Select(x => x).ToArray();
                }
            }

            public SymbolData(Symbol symbol, IEnumerable<BaseData> history)
            {
                Symbol = symbol;
                _rollingHistory = new RollingWindow<double>(200);

                foreach (var data in history)
                {
                    Update(data);
                }
            }

            public void Update(BaseData data)
            {
                if (data == null)
                {
                    return;
                }
                else
                {
                    _rollingHistory.Add((double)data.Value);
                }
            }
        }
    }
}