Overall Statistics |
Total Trades 264 Average Win 0.36% Average Loss -0.50% Compounding Annual Return -0.906% Drawdown 24.500% Expectancy -0.041 Net Profit -1.344% Sharpe Ratio -0.002 Probabilistic Sharpe Ratio 11.118% Loss Rate 45% Win Rate 55% Profit-Loss Ratio 0.73 Alpha -0.075 Beta 0.378 Annual Standard Deviation 0.133 Annual Variance 0.018 Information Ratio -1.036 Tracking Error 0.192 Treynor Ratio -0.001 Total Fees $2592.89 |
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(2019,1,1) #Set Start Date self.SetCash(1000000) #Set Strategy Cash # Find more symbols here: http://quantconnect.com/data self.AddEquity("SPY") 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 self.additional = [ 'QQQ', 'IWM', 'IJH', 'IJR', 'AGG', 'LQD', 'PSP' ] self.stocks = self.stocks + self.additional self.stocks = [self.AddEquity(x, Resolution.Minute).Symbol 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[1], reverse=True) # Select the top half of best performing symbols symbols = [] for sym in range(int(len(sort) / 2)): symbols.append(str(sort[sym][0].ID)) # 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)