| Overall Statistics |
|
Total Trades 7224 Average Win 0.15% Average Loss -0.11% Compounding Annual Return 9.071% Drawdown 8.500% Expectancy 0.215 Net Profit 133.095% Sharpe Ratio 1.213 Loss Rate 48% Win Rate 52% Profit-Loss Ratio 1.35 Alpha 0.089 Beta -0.004 Annual Standard Deviation 0.073 Annual Variance 0.005 Information Ratio -0.032 Tracking Error 0.215 Treynor Ratio -22.726 Total Fees $8825.34 |
import statsmodels.api as sm
import numpy
MAX_LEVERAGE = 2.0
beta_samples = 252
alpha_samples = 15
volatility_samples = 5
MAX_VOLATILITY = 0.05
class BasicTemplateAlgorithm(QCAlgorithm):
def __init__(self):
pass
def Initialize(self):
self.SetCash(100000)
self.SetStartDate(2008,1,1)
#self.SetEndDate(2007,12,31)
self.SPY = self.AddEquity("SPY", Resolution.Minute).Symbol
self.QQQ = self.AddEquity("QQQ", Resolution.Minute).Symbol
self.TLT = self.AddEquity("TLT", Resolution.Minute).Symbol
#self.SetBrokerageModel(BrokerageName.InterativeBrokersBrokerage, AccountType.Margin)
self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.AfterMarketOpen("SPY", 15), Action(self.Rebalance))
def OnData(self, slice):
pass
def min_variance(self, returns):
cov = numpy.cov(returns)
vu = numpy.ones(cov.shape[0])
if (numpy.linalg.det(cov) != 0):
num = numpy.linalg.solve(cov,vu)
den = numpy.dot(vu, num)
w = num / den
return w / numpy.sum(numpy.absolute(w))
else:
return None
def Rebalance(self):
try:
self.spy_price = float(self.Securities["SPY"].Price)
if (self.spy_price == 0):
self.Log("Missing SPY price")
return
self.qqq_price = float(self.Securities["QQQ"].Price)
if (self.qqq_price == 0):
self.Log("Missing QQQ price")
return
self.tlt_price = float(self.Securities["TLT"].Price)
if (self.tlt_price == 0):
self.Log("Missing TLT price")
return
spy_prices = numpy.asarray([float(x.Price) for x in self.History("SPY",beta_samples,Resolution.Daily)] + [self.spy_price])
spy_returns = numpy.nan_to_num(spy_prices[1:] / spy_prices[:-1] - 1.0)
qqq_prices = numpy.asarray([float(x.Price) for x in self.History("QQQ",beta_samples,Resolution.Daily)] + [self.qqq_price])
qqq_returns = numpy.nan_to_num(qqq_prices[1:] / qqq_prices[:-1] - 1.0)
tlt_prices = numpy.asarray([float(x.Price) for x in self.History("TLT",beta_samples,Resolution.Daily)] + [self.tlt_price])
tlt_returns = numpy.nan_to_num(tlt_prices[1:] / tlt_prices[:-1] - 1.0)
if (len(spy_returns) == len(qqq_returns) == len(tlt_returns)):
security_returns = numpy.vstack([qqq_returns,tlt_returns])
else:
self.Log("Missing data")
return
pfolio_weights = self.min_variance(security_returns[:,-alpha_samples:])
if (pfolio_weights is None):
self.Log("Min_variance error")
return
pfolio_returns = numpy.nan_to_num((pfolio_weights[:,None]*security_returns).sum(axis=0))
pfolio_beta = numpy.nan_to_num(sm.OLS(pfolio_returns[-beta_samples:],sm.add_constant(spy_returns[-beta_samples:], prepend=True)).fit().params[1])
benchmark_split = -pfolio_beta / (1.0 + abs(pfolio_beta))
pfolio_split = 1.0 / (1.0 + abs(pfolio_beta))
pfolio_std = numpy.std(pfolio_split * pfolio_returns[-volatility_samples:] + benchmark_split * spy_returns[-volatility_samples:] )
leverage = numpy.clip(MAX_VOLATILITY / (pfolio_std * numpy.sqrt(252)),0.0,MAX_LEVERAGE)
self.SetHoldings("SPY", benchmark_split * leverage)
self.Log("SPY {0: 4.2f} % {1: 4.2f} ".format((benchmark_split * leverage) / MAX_LEVERAGE * 100.0, self.spy_price))
self.SetHoldings("QQQ", pfolio_split * pfolio_weights[0] * leverage)
self.Log("QQQ {0: 4.2f} % {1: 4.2f} ".format((pfolio_split * pfolio_weights[0] * leverage) / MAX_LEVERAGE * 100.0, self.qqq_price))
self.SetHoldings("TLT", pfolio_split * pfolio_weights[1] * leverage)
self.Log("TLT {0: 4.2f} % {1: 4.2f} ".format((pfolio_split * pfolio_weights[1] * leverage) / MAX_LEVERAGE * 100.0, self.tlt_price))
self.Log("CASH {0: 4.2f} %".format((MAX_LEVERAGE - leverage) / MAX_LEVERAGE * 100.0))
except Exception as e: pass