Overall Statistics
Total Trades
147
Average Win
3.21%
Average Loss
-1.82%
Compounding Annual Return
42.241%
Drawdown
14.200%
Expectancy
0.794
Net Profit
187.791%
Sharpe Ratio
1.858
Loss Rate
35%
Win Rate
65%
Profit-Loss Ratio
1.77
Alpha
0.291
Beta
0.139
Annual Standard Deviation
0.162
Annual Variance
0.026
Information Ratio
1.173
Tracking Error
0.192
Treynor Ratio
2.163
Total Fees
$267.83
import numpy as np
import pandas as pd
from scipy.optimize import minimize
import statsmodels.formula.api as sm

class mean_variance(QCAlgorithm):
	def __init__(self):
		self.symbols = ["SPY","MMM", "AXP", "AAPL", "BA", "CAT", "CVX", "CSCO","KO",
            "DIS","DD","XOM","GE","GS","HD","IBM","INTC","JPM","MCD",
            "MRK","MSFT","NKE","PFE","PG","TRV","UTX","UNH","VZ","WMT"]
		self.num = 21*12*3
		self.reb_feq = 60
		self.count = 0
		
	
	def get_history(self,symbol):
		prices = []
		dates = []
		for i in self.history:
			bar = i[symbol]
			prices.append(np.log(float(bar.Close)))
			dates.append(bar.EndTime)
		symbol.df = pd.DataFrame({'log_price':prices},index = dates)
		symbol.df['log_return'] = symbol.df['log_price'].diff()
		symbol.df = symbol.df.dropna()

	def regression(self):
		for i in self.symbols:
			df = pd.DataFrame({'%s'%str(i):i.df['log_return'], 'SPY':self.spy.df['log_return']})
			i.model = sm.ols(formula = '%s ~ SPY'%str(i), data = df).fit()
			i.intercept = i.model.params[0]
			i.beta = i.model.params[1]
			i.one_month = sum(i.df['log_return'].tail(self.reb_feq))
			


	def Initialize(self):
		self.SetStartDate(2014,1,1)
		self.SetEndDate(2017,1,1)
		self.SetCash(50000)
		
		for i in range(len(self.symbols)):
			equity = self.AddEquity(self.symbols[i],Resolution.Daily).Symbol
			self.symbols[i] = equity
		
		self.history = self.History(self.num, Resolution.Daily)
		for i in self.symbols:
			self.get_history(i)
			i.leng = i.df.shape[0]
			i.mean = np.mean(i.df['log_return'])
			i.std = np.std(i.df['log_return'])
			i.price_list = []
			i.dates_list = []
			
		self.spy = self.symbols[0]
		
		self.regression()


	def OnData(self,data):
		# if not self.Securities[self.symbols[0]].Exchange.ExchangeOpen: 
		#     return
		    
		if self.count == 0:
			# calculate alpha#
			for i in self.symbols:
				i.alpha = i.one_month - i.intercept - i.beta*self.spy.one_month
			
			
			# self.long_list = [x for x in self.symbols]
				
			self.long_list = [x for x in self.symbols if x.alpha < 0]
			self.long_list.sort(key = lambda x: x.alpha)
			self.long_list = self.long_list[:5]
			self.short_list = [x for x in self.symbols if x.alpha > 0]
			self.short_list.sort(key = lambda x: x.alpha, reverse = True)
			self.short_list = self.short_list[:5]
			#portfolio optimization#
			# self.ticker_list = [str(x) for x in self.long_list]
			# self.mean_list = [x.mean for x in self.long_list]
			# self.cov_matrix = np.cov([x.df['log_return'] for x in self.long_list])
			# self.port = optimizer(self.ticker_list,self.mean_list,self.cov_matrix)
			# self.port.optimize()
			# self.Log(str(self.port.opt_df))
			# self.Log(str([str(x) for x in self.long_list]))
			# self.Log(str([str(x) for x in self.short_list]))
			for i in self.long_list:
				self.SetHoldings(i,1.0/len(self.long_list))
				# self.SetHoldings(i,self.port.opt_df.ix[str(i)])
			for i in self.short_list:
				self.SetHoldings(i,-1/len(self.short_list))

			self.count += 1
			return
		
		if self.count < self.reb_feq:
			for i in self.symbols:
				try:
					i.price_list.append(np.log(float(data[i].Close)))
					i.dates_list.append(data[i].EndTime)
				except:
					self.Log(str(i))
				
			self.count += 1
			return
				
		if self.count == self.reb_feq:
			for i in self.symbols:
				try:
					i.price_list.append(np.log(float(data[i].Close)))
					i.dates_list.append(data[i].EndTime)
					df = pd.DataFrame({'log_price':i.price_list},index = i.dates_list)
					df = df.diff().dropna()
					df = pd.concat([i.df,df]).tail(self.num)
				except:
					pass
			
			self.regression()
			self.Liquidate()
			self.count = 0
			return
			
			
			
class optimizer(object):
	def __init__(self,ticker_list, mean_list,cov_matrix):
		self.tickers = ticker_list
		self.mean_list = mean_list
		self.cov_matrix = cov_matrix
		
	def optimize(self):
		leng = len(self.tickers)
		def target(x, sigma, mean):
			sr_inv = (np.sqrt(np.dot(np.dot(x.T,sigma),x)*252))/((x.dot(mean))*252)
			return sr_inv
		
		x = np.ones(leng)/leng
		mean = self.mean_list
		sigma = self.cov_matrix
		c = ({'type':'eq','fun':lambda x: sum(x) - 1},
		     {'type':'ineq','fun':lambda x: 2 - sum([abs(i) for i in x])})
		bounds = [(-1,1) for i in range(leng)]
		res = minimize(target, x, args = (sigma,mean),method = 'SLSQP',constraints = c,bounds = bounds)
		self.opt_weight = res.x
		self.exp_return = np.dot(self.mean_list,res.x)*252
		self.std = np.sqrt(np.dot(np.dot(res.x.T,sigma),res.x)*252)
		self.opt_df = pd.DataFrame({'weight':res.x},index = self.tickers)
		self.opt_df.index = self.opt_df.index.map(str)
		
	def update(self,ticker_list, mean_list,cov_matrix):
		self.tickers = ticker_list
		self.mean_list = mean_list
		self.cov_matrix = cov_matrix
		self.optimize()