Overall Statistics Total Trades 1322 Average Win 0.28% Average Loss -0.47% Compounding Annual Return 10.867% Drawdown 27.100% Expectancy 0.355 Net Profit 237.945% Sharpe Ratio 0.857 Loss Rate 15% Win Rate 85% Profit-Loss Ratio 0.60 Alpha 0.065 Beta 0.49 Annual Standard Deviation 0.13 Annual Variance 0.017 Information Ratio 0.118 Tracking Error 0.133 Treynor Ratio 0.228 Total Fees \$13859.87
```import pandas as pd
import numpy as np
import scipy.optimize
import talib

### <summary>
### Basic template algorithm simply initializes the date range and cash. This is a skeleton
### framework you can use for designing an algorithm.
### </summary>
class BasicTemplateAlgorithm(QCAlgorithm):

def Initialize(self):

self.SetStartDate(2007,1,1)  #Set Start Date
self.SetCash(1000000)           #Set Strategy Cash
# Find more symbols here: http://quantconnect.com/data
self.SetBenchmark('SPY')

self.stocks = [ 'SPY',  # S&P 500
'EZU',  # MSCI EMU
'EWJ',  # Asia Pacifc ex-Japan
'EEM',  # Emerging Markets
'VNQ',  # US REITs
'RWX',  # International REITs
'IEF',  # US 10 Year Treasury
'TLT',  # US 30 Year Treasury
'DBC',  # Commodities
'GLD']  # Gold

'IWM',
'IJH',
'IJR',
'AGG',
'LQD',
'PSP'
]

for x in self.stocks:

self.Schedule.On(self.DateRules.MonthEnd("SPY"), self.TimeRules.BeforeMarketClose("SPY", 15), Action(self.allocate))

self.Portfolio.MarginCallModel = MarginCallModel.Null

self.momentum_lookback = 126
self.correlation_lookback = 126
self.volatility_lookback = 21

self.leverage = 1

def calculate_portfolio_var(self, w, V):
w = np.matrix(w)
return (w*V*w.T)[0,0]

def allocate(self):

# Find the recent returns generated by each symbol
hist = self.History(self.stocks, 200, Resolution.Daily).unstack(level=0).close
assets = []
for x in self.stocks:
ret = ((hist[x][-1]/hist[x][-self.momentum_lookback])) - 1
assets.append([x, ret])

sort = sorted(assets, key=lambda x: x, reverse=True)

# Select the top half of best performing symbols
symbols = []
for sym in range(int(len(sort) / 2)):
symbols.append(sort[sym])

# Create a weighted covariance matrix using the previous
# 126 days for correlation and 21 days for volatility
hist = hist[symbols].pct_change()[1:]
vol = hist[-self.volatility_lookback:].std().values
vol = vol.reshape(1, len(symbols)) * vol.reshape(len(symbols), 1)
corr = hist[-self.correlation_lookback:].corr()
covar_matrix = np.matrix(vol * corr)

# Create an equally weighted portfolio as the initial allocation to optimise
w0 = []
for w in symbols:
w0.append(1 / len(symbols))

# Find the Minimum Variance Portfolio
cons = ({'type': 'eq', 'fun': lambda x:  np.sum(x) - 1.0})
res = scipy.optimize.minimize(self.calculate_portfolio_var, w0, args=covar_matrix, method='SLSQP', constraints=cons)

allocate = pd.Series(res.x, index=corr.index)

# Liquidate any holdings that are currently invested and do not form part of the new
# monthly portfolio to ensure we don't exceed buying power on rebalance
for stock in self.stocks:
if stock not in symbols and self.Securities[stock].Invested:
self.Liquidate(stock)

# Purchase new Minimum Variance Portfolio
for stock in allocate.index.tolist():
self.SetHoldings(stock, allocate.tolist()[allocate.index.tolist().index(stock)] * self.leverage)```