Overall Statistics
Total Trades
9
Average Win
0%
Average Loss
-2.22%
Compounding Annual Return
-21.609%
Drawdown
51.800%
Expectancy
-1
Net Profit
-48.126%
Sharpe Ratio
-0.548
Loss Rate
100%
Win Rate
0%
Profit-Loss Ratio
0
Alpha
0.048
Beta
-2.307
Annual Standard Deviation
0.287
Annual Variance
0.082
Information Ratio
-0.601
Tracking Error
0.41
Treynor Ratio
0.068
Total Fees
$93.51
using MathNet.Numerics.LinearAlgebra;
using MathNet.Numerics.Statistics;

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 PortfolioOptimizationNumericsAlgorithm : QCAlgorithm
    {
        private const double _targetReturn = 0.1;
        private const double _riskFreeRate = 0.01;
        private double _lagrangeMultiplier;
        private double _portfolioRisk;
        private Matrix<double> Sigma;
        private List<SymbolData> SymbolDataList;
        public Vector<double> DiscountMeanVector
        {
            get
            {
                if (SymbolDataList == null)
                {
                    return null;
                }

                return 
                    Vector<double>.Build.DenseOfArray(SymbolDataList.Select(x => (double)x.Return).ToArray()) -
                    Vector<double>.Build.Dense(SymbolDataList.Count, _riskFreeRate);
            }
        }

        /// <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()
        {
            SetStartDate(2013, 10, 07);             //Set Start Date
            SetEndDate(DateTime.Now.AddDays(-1));   //Set End Date
            SetCash(1000000);                        //Set Strategy Cash
            // Find more symbols here: http://quantconnect.com/data
            AddEquity("SPY", Resolution.Daily);
            AddEquity("AIG", Resolution.Daily);
            AddEquity("BAC", Resolution.Daily);
            AddEquity("IBM", Resolution.Daily);

            var allHistoryBars = new List<double[]>();
            SymbolDataList = new List<SymbolData>();

            foreach (var security in Securities)
            {
                var history = History(security.Key, TimeSpan.FromDays(365));
                allHistoryBars.Add(history.Select(x => (double)x.Value).ToArray());
                SymbolDataList.Add(new SymbolData(security.Key, history));
            }

            // Diagonal Matrix with each security risk (standard deviation)
            var S = Matrix<double>.Build.DenseOfDiagonalArray(SymbolDataList.Select(x => (double)x.Risk).ToArray());

            // Computes Correlation Matrix (using Math.NET Numerics Statistics)
            var R = Correlation.PearsonMatrix(allHistoryBars);

            // Computes Covariance Matrix (using Math.NET Numerics Linear Algebra)
            Sigma = S * R * S;

            ComputeLagrangeMultiplier();
            ComputeWeights();
            ComputePortfolioRisk();

            Log(string.Format("Lagrange Multiplier: {0,7:F4}", _lagrangeMultiplier));
            Log(string.Format("Portfolio Risk:      {0,7:P2} ", _portfolioRisk));
        }

        /// <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)
        {
            if (!Portfolio.Invested)
            {
                foreach (var symbolData in SymbolDataList.OrderBy(x => x.Weight))
                {
                    Log("Purchased Stock: " + symbolData);
                    SetHoldings(symbolData.Symbol, symbolData.Weight);
                }
            }
        }

        /// <summary>
        /// Computes Lagrange Multiplier
        /// </summary>
        private void ComputeLagrangeMultiplier()
        {
            var denominatorMatrix = DiscountMeanVector * Sigma.Inverse() * DiscountMeanVector.ToColumnMatrix();

            _lagrangeMultiplier = (_targetReturn - _riskFreeRate) / denominatorMatrix.ToArray().First();
        }

        /// <summary>
        /// Computes weight for each risky asset
        /// </summary>
        private void ComputeWeights()
        {
            var weights = _lagrangeMultiplier * Sigma.Inverse() * DiscountMeanVector.ToColumnMatrix();

            for (var i = 0; i < weights.RowCount; i++)
            {
                SymbolDataList[i].SetWeight(weights.ToArray()[i, 0]);
            }
        }

        /// <summary>
        /// Computes Portfolio Risk
        /// </summary>
        private void ComputePortfolioRisk()
        {
            var weights = Vector<double>.Build.DenseOfArray(SymbolDataList.Select(x => (double)x.Return).ToArray());
            var portfolioVarianceMatrix = weights * Sigma * weights.ToColumnMatrix();
            _portfolioRisk = Math.Sqrt(portfolioVarianceMatrix.ToArray().First());
        }

        /// <summary>
        /// Symbol Data class to store security data (Return, Risk, Weight)
        /// </summary>
        class SymbolData
        {
            private RateOfChange ROC = new RateOfChange(2);
            private SimpleMovingAverage SMA;
            private StandardDeviation STD;
            public Symbol Symbol { get; private set; }
            public decimal Return { get { return SMA.Current; }  }
            public decimal Risk { get { return STD.Current; } }
            public decimal Weight { get; private set; }

            public SymbolData(Symbol symbol, IEnumerable<BaseData> history)
            {
                Symbol = symbol;
                SMA = new SimpleMovingAverage(365).Of(ROC);
                STD = new StandardDeviation(365).Of(ROC);

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

            public void Update(BaseData data)
            {
                ROC.Update(data.Time, data.Value);
            }

            public void SetWeight(double value)
            {
                Weight = (decimal)value;
            }

            public override string ToString()
            {
                return string.Format("{0}: {1,10:P2}\t{2,10:P2}\t{3,10:P2}", Symbol.Value, Weight, Return, Risk);
            }
        }
    }
}