Overall Statistics
Total Trades
278
Average Win
0.55%
Average Loss
-0.23%
Compounding Annual Return
56.572%
Drawdown
8.900%
Expectancy
0.913
Net Profit
37.281%
Sharpe Ratio
2.337
Loss Rate
43%
Win Rate
57%
Profit-Loss Ratio
2.35
Alpha
0.386
Beta
-0.053
Annual Standard Deviation
0.162
Annual Variance
0.026
Information Ratio
1.426
Tracking Error
0.176
Treynor Ratio
-7.151
Total Fees
$394.37
using System;
using System.Collections.Generic;
using System.Linq;
using QuantConnect.Data;
using QuantConnect.Orders;


namespace QuantConnect.Algorithm.CSharp
{
    class AaEtfOpti : QCAlgorithm
    {
    	// ##### ALGO PARAM ############
    	private int allocationFrequency = 3;
    	// ##### END ALGO PARAM ############
    	
    	
        private Queue<Symbol> stocks;
		private bool allocationTime = false;
        private int allocate = 0;
        private double[] weights;
        
        public override void Initialize()
        {
            SetStartDate(2017, 1, 1);
            SetEndDate(2017, 9, 15);
            
            SetCash(25000);

            stocks = new Queue<Symbol>();

            var ref_etf = AddEquity("UPRO", Resolution.Minute).Symbol;
            stocks.Enqueue(ref_etf);
            stocks.Enqueue(AddEquity("UGLD", Resolution.Minute).Symbol);
            stocks.Enqueue(AddEquity("TMF", Resolution.Minute).Symbol);
            //stocks.Enqueue(AddEquity("XIV", Resolution.Minute).Symbol);
            
            int c = stocks.Count;
            weights = new double[c];
            

            Schedule.On(DateRules.EveryDay(ref_etf), TimeRules.AfterMarketOpen(ref_etf, 60), () =>
            {
                allocationTime = true;
            });

        }

         public override void OnData(Slice data)
        {
            if (allocate % allocationFrequency == 0 && allocationTime)
            {
                Allocate(data);
                allocate = 0;
                allocationTime = false;
            }
        }

        

        private void Allocate(Slice data)
        {
        	// I tend to convert everythign to double because a lot of the matrix existing manip/functions, 
        	// only work on doubles and precision should have very little impact on that 
            var priceData = new List<double[]>();
            
            int lookbackPeriod = allocationFrequency * 3;
			var resolution = Resolution.Daily;
            int dataCount = lookbackPeriod;
            
            //will hold returns.mean/return.std for all stocks
            var retNorm = new double[stocks.Count];
            //constructing price matrix stocks.count x lookbackPeriod
            var allHistoryBars = new double[stocks.Count(), lookbackPeriod+1];
            
            int ii = 0;
            foreach (var security in stocks)
            {
                var history = History(security, lookbackPeriod, resolution);
                //the tmp array dupe the price for the current security because in matrix 
                // I have no way that I know of of accessign columns
                var tmp = new double[history.Count()+1];
                //fill the price matrix    
                int jj = 0;
                foreach(var h in history)
                {
                	tmp[jj] = (double)h.Close;
                	jj++;
                }
                
                //Add current bar to history
                var p = (double)history.Last().Value;
                if (data.Bars.Keys.Contains(security))//just in case, it happened
                {
                	p = (double)data.Bars[security].Close;
                }
                allHistoryBars[ii, jj] = p;
                tmp[jj] = p;
                var pctChanges = tmp.PctChange();
                for (int j = 0; j < pctChanges.Length; j++)
                	allHistoryBars[ii, j] = pctChanges[j];
                Log("RetNorm " + string.Join(", ", tmp));
                //StdDev is a custom extension on decimal and double
				var secRetNorm = tmp.Average() /tmp.StdDev();
				retNorm[ii] = secRetNorm;
                priceData.Add(tmp);
                ii++;
            }
            
            PrintArray(allHistoryBars);
            
            weights = AaOptimizer.OptimiseWeights(allHistoryBars, retNorm);
            
			Trade(data);
        }


        private void Trade(Slice data)
        {
            Log("Trade");
            if (Transactions.GetOpenOrders().Count > 0)
            {
                return;
            }
            Log("Trade weights: " + string.Join(",", weights));
            for (int i = 0; i < stocks.Count; i++)
            {
                SetHoldings(stocks.ElementAt(i), weights[i]);
            }
        }


        public override void OnEndOfDay()
        {
            allocate++;
        }
        
        private void PrintArray(double[,] arr)
        {
        	Log("########### print matrix to optimize");
            int rowLength = arr.GetLength(0);
            int colLength = arr.GetLength(1);
            Log(string.Join(",", stocks));
            for (int j = 0; j < colLength; j++)
            {
                string msg = "";
                for (int i = 0; i < rowLength; i++)
                {
                    msg += " " + string.Format("{0} ", arr[i, j].ToString("0.000000"));
                }
                Log(msg);
            }
            Log("#########################################");
        }
        
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Accord.Math;
using Accord.Math.Optimization;
using Accord.Statistics;


namespace QuantConnect.Algorithm.CSharp
{
    public static class AaOptimizer
    {
        
		public static double[] MergeVector(double [] a, double [] b)
		{
			return a.Concatenate(b);
		}
		
        
        public static double[] OptimiseWeights(double[,] allHistoryBars, double [] retNorm)
        {
            var covMatrix = allHistoryBars.Transpose().Covariance();
            
            var maxRet = 0.9 * retNorm.Max();
            
			Func<double[], double> retNormFunc = (x) => x.Dot(retNorm) - maxRet;
			
            // The scoring function
            var f = new NonlinearObjectiveFunction(covMatrix.GetLength(0), x => x.DotAndDot(covMatrix, x));
            // Under the following constraints
            var constraints = new[]
            {
                //the sum of all weights is equal to 1 (ish)
                //using Enumerable sum because of Accord.Math extension redefinition
                //https://stackoverflow.com/questions/32380592/why-am-i-required-to-reference-system-numerics-with-this-simple-linq-expression
                new NonlinearConstraint(covMatrix.GetLength(0), x => -Math.Pow(Enumerable.Sum(x) - 1, 2) >= -1e-6),
				new NonlinearConstraint(covMatrix.GetLength(0), x =>  retNormFunc(x) >= 0),
                //the values are bounded between 0 and 1
                new NonlinearConstraint(covMatrix.GetLength(0), x => x.Min() >= 0),
                new NonlinearConstraint(covMatrix.GetLength(0), x => -x.Max() >= -1),
            };


            var algo = new Cobyla(f, constraints);
            // Optimize it
            //TODO handle !success
            bool success = algo.Minimize();
            double minimum = algo.Value;
            double[] weights = algo.Solution;

            
            return weights;
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;


namespace QuantConnect.Algorithm.CSharp
{
    public static class AaComputationExtensions
    {
        public static decimal[] RollingMax(this decimal[] array, int period)
        {
        	if (period == 0)
        		return (decimal[])array.Clone();
        	var answer = new decimal[array.Length];
            var rollingData = new Queue<decimal>();
            int count = 0;
            foreach (var v in array)
            {
                count++;
                rollingData.Enqueue(v);
                if (count > period)
                {
                    rollingData.Dequeue();
                }
                answer[count - 1] = rollingData.Max();
            }
            return answer;
        }
	
	 	public static double[] RollingMax(this double[] array, int period)
        {
            var answer = new double[array.Length];
            var rollingData = new Queue<double>();
            //for (int i = 0; i < array.Length; i++)
            int count = 0;
            foreach (var v in array)
            {
                count++;
                rollingData.Enqueue(v);
                if (count > period)
                {
                    rollingData.Dequeue();
                }
                answer[count - 1] = rollingData.Max();
            }
            return answer;
        }
        
        public static double StdDev(this IEnumerable<double> values)
        {
            double ret = 0;
            if (values.Any())
            {
                //Compute the Average      
                double avg = values.Average();
                //Perform the Sum of (value-avg)_2_2      
                double sum = values.Sum(d => Math.Pow(d - avg, 2));
                //Put it all together      
                ret = Math.Sqrt((sum) / (values.Count() - 1));
            }
            return ret;
        }

        public static decimal StdDev(this IEnumerable<decimal> values)
        {
            double ret = 0;
            if (values.Any())
            {
                //Compute the Average      
                decimal avg = values.Average();
                //Perform the Sum of (value-avg)_2_2      
                decimal sum2 = values.Sum(d => (decimal)Math.Pow((double)(d - avg), 2));
                decimal sum = values.Sum(d => (d - avg) * (d - avg));
                //Put it all together      
                ret = Math.Sqrt((double)(sum) / (values.Count() - 1));
            }
            return (decimal)ret;
        }

        public static decimal[] RollingStd(this IEnumerable<decimal> array, int period)
        {
            return array.ToArray().RollingStd(period);
        }

        public static decimal[] LastN(this decimal[] array, int count)
        {
            if (count > array.Length)
                return null;
            var lastN = new decimal[count];
            Array.Copy(array, array.Length - count, lastN, 0, count);
            return lastN;
        }
        
        public static double[] LastN(this double[] array, int count)
        {
            if (count > array.Length)
                return null;
            var lastN = new double[count];
            Array.Copy(array, array.Length - count, lastN, 0, count);
            return lastN;
        }
        
        public static decimal[] RollingStd(this decimal[] array, int period)
        {
            var answer = new decimal[array.Length];
            var rollingData = new Queue<decimal>();
            //for (int i = 0; i < array.Length; i++)
            int count = 0;
            foreach (var v in array)
            {
                count++;
                rollingData.Enqueue(v);
                if (count >= period)
                {
                    rollingData.Dequeue();
                    answer[count - 1] = rollingData.StdDev();
                }
            }
            return answer;
        }

        public static double[] PctChange(this double[] array, int period = 1)
        {
            var result = new double[array.Length];
            var prevs = new Queue<double>();
            int count = 0;
            foreach (var v in array)
            {
                if (count >= period)
                {
                    result[count] = v / prevs.ElementAt(0) - 1;
                    prevs.Dequeue();
                }
                else
                {
                    result[count] = 0;
                }
                prevs.Enqueue(v);
                count++;
            }
            return result;
        }
    }
}