Overall Statistics |
Total Orders 550 Average Win 0.70% Average Loss -0.19% Compounding Annual Return 11.758% Drawdown 24.300% Expectancy 0.959 Start Equity 10000 End Equity 16028.10 Net Profit 60.281% Sharpe Ratio 0.566 Sortino Ratio 0.385 Probabilistic Sharpe Ratio 25.147% Loss Rate 58% Win Rate 42% Profit-Loss Ratio 3.71 Alpha 0.044 Beta 0.228 Annual Standard Deviation 0.115 Annual Variance 0.013 Information Ratio -0.144 Tracking Error 0.178 Treynor Ratio 0.286 Total Fees $549.00 Estimated Strategy Capacity $5600000.00 Lowest Capacity Asset IJS RWQR2INKP0TH Portfolio Turnover 3.28% |
#region imports from AlgorithmImports import * #endregion from clr import AddReference AddReference("System") AddReference("QuantConnect.Algorithm") AddReference("QuantConnect.Common") from System import * from QuantConnect import * from QuantConnect.Algorithm import * from QuantConnect.Data import * from datetime import timedelta import numpy as np class ScheduledCAPM(QCAlgorithm): def Initialize(self): self.SetStartDate(2020,1,1) self.SetEndDate(2024,3,31) self._cash = 10000 self.SetCash(self._cash) self._tickers = ['IJR', 'IWM', 'IWF', 'IJH', 'IWD', 'ITOT', 'IVW', 'IWR', 'IWB', 'IVE', 'IWN' ,'IWP', 'IWS', 'IWO', 'IWV', 'IUSG','IBB', 'IUSV','IHI', 'IJS', 'IJJ', 'IJK', 'IYW', 'OEF'] self.symbols = [self.AddEquity(ticker).Symbol for ticker in self._tickers ] self.spy = self.AddEquity("SPY", Resolution.Daily).Symbol self.ivv = self.AddEquity("IVV", Resolution.Daily).Symbol self._bench = self.AddEquity("IVV", Resolution.Daily).Symbol self.lookback = 30 self.SetWarmup(31) self.counter = 0 self._counter=0 self.reference = self.History(self.ivv, 5, Resolution.Daily)['close'] self._initialValue = self.reference.iloc[0] self.Schedule.On(self.DateRules.MonthStart("SPY"), self.TimeRules.AfterMarketOpen(self.spy, 10), self.Rebalance) self._portfolioValue =[self._cash] self._stopLoss=float(self.GetParameter("stop_loss")) self._num_alpha=int(self.GetParameter("number_of_stocks")) self._num_beta = int(self.GetParameter("number_of_stocks_beta")) self._numStocks= self._num_alpha + self._num_beta self._weight = (1/(2*self._numStocks)) def Rebalance(self): self.counter += 1 self.Debug(f"Counter : {self.counter}") if self.IsWarmingUp: return if self.counter % 3 == 0: history = self.History( self.symbols + [self._bench], self.lookback, Resolution.Daily).close.unstack(level=0) self.symbols_alpha = self.SelectSymbols_alphas(history) self.symbols_beta = self.SelectSymbols_betas(history) for holdings in self.Portfolio.Values: symbol = holdings.Symbol if symbol not in self.symbols_alpha and symbol not in self.symbols_beta and holdings.Invested: self.Liquidate(symbol) for symbol in self.symbols_alpha: self.SetHoldings(symbol, self._weight) for symbol in self.symbols_beta: self.SetHoldings(symbol, self._weight) self.SetHoldings("SPY", 1-self._weight) def OnData(self,data): self._portfolioValue.append(self.Portfolio.TotalPortfolioValue) if self.Portfolio.TotalPortfolioValue - self._portfolioValue[self._counter] < -self._cash*self._stopLoss: self.Liquidate() self._counter += 1 def SelectSymbols_alphas(self, history): alphas = dict() _bench = history[self._bench].pct_change().dropna() for symbol in self.symbols: returns = history[symbol].pct_change().dropna() bla = np.vstack([_bench, np.ones(len(returns))]).T result = np.linalg.lstsq(bla , returns) alphas[symbol] = result[0][1] selected_alphas = sorted(alphas.items(), key=lambda x: x[1], reverse=True)[:self._numStocks-1] return [x[0] for x in selected_alphas] def SelectSymbols_betas(self, history): betas = dict() _bench = history[self._bench].pct_change().dropna() for symbol in self.symbols: returns = history[symbol].pct_change().dropna() bla = np.vstack([_bench, np.ones(len(returns))]).T result = np.linalg.lstsq(bla , returns) betas[symbol]= result[0][0] selected_betas = sorted(betas.items(), key=lambda x: x[1], reverse=True)[:self._numStocks-1] return [x[0] for x in selected_betas]