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