Overall Statistics Total Trades278Average Win0.55%Average Loss-0.23%Compounding Annual Return56.572%Drawdown8.900%Expectancy0.913Net Profit37.281%Sharpe Ratio2.337Loss Rate43%Win Rate57%Profit-Loss Ratio2.35Alpha0.386Beta-0.053Annual Standard Deviation0.162Annual Variance0.026Information Ratio1.426Tracking Error0.176Treynor Ratio-7.151Total Fees\$394.37
```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 rollingData = new Queue<decimal>();
int count = 0;
foreach (var v in array)
{
count++;
rollingData.Enqueue(v);
if (count > period)
{
rollingData.Dequeue();
}
}
}

public static double[] RollingMax(this double[] array, int period)
{
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();
}
}
}

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 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();
}
}
}

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;
}
}
}```
```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;
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>();

stocks.Enqueue(ref_etf);

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++;
}

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;
ii++;
}

PrintArray(allHistoryBars);

weights = AaOptimizer.OptimiseWeights(allHistoryBars, retNorm);

}

{
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("#########################################");
}

}
}```