Overall Statistics |
Total Orders 663 Average Win 0.82% Average Loss -0.46% Compounding Annual Return 21.126% Drawdown 33.000% Expectancy 0.539 Start Equity 10000 End Equity 21890.02 Net Profit 118.900% Sharpe Ratio 0.679 Sortino Ratio 0.71 Probabilistic Sharpe Ratio 24.637% Loss Rate 44% Win Rate 56% Profit-Loss Ratio 1.77 Alpha 0.081 Beta 0.847 Annual Standard Deviation 0.22 Annual Variance 0.048 Information Ratio 0.438 Tracking Error 0.155 Treynor Ratio 0.176 Total Fees $480.00 Estimated Strategy Capacity $620000.00 Lowest Capacity Asset IAU T5QHGBE8K3TX Portfolio Turnover 3.76% |
#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,1,31) self._cash = 10000 self.SetCash(self._cash) self._tickers = ['AGG', 'IWM', 'IAU', 'COMT', 'USMV', 'DGRO', 'QUAL', 'DVY', 'MTUM', 'VLUE', 'EFAV', 'EEMV', 'IDV', 'IQLT', 'IYW', 'IGF', 'IYH'] 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.spy self.lookback = 30 self.SetWarmup(31) self.counter = 0 self.reference = self.History(self.ivv, 5, Resolution.Daily)['close'] self._initialValue = self.reference.iloc[0] self.Schedule.On(self.DateRules.Every(DayOfWeek.Monday), self.TimeRules.AfterMarketOpen(self.spy, 10), self.Rebalance) self._portfolioValue = [self._cash] self._drawdown = -0.03 self.reference = self.History(self.spy, 10, Resolution.Daily)['close'] self._initialValue = self.reference.iloc[0] 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, 0.1) for symbol in self.symbols_beta: if symbol in self.symbols_alpha: self.SetHoldings(symbol, 0.2) else: self.SetHoldings(symbol, 0.1) self.SetHoldings("SPY", 1.0) def OnData(self,data): self._portfolioValue.append(self.Portfolio.TotalPortfolioValue) if (self._portfolioValue[-1]-self._portfolioValue[-2])/self._portfolioValue[-1] < self._drawdown: self.Liquidate() self.Plot("Relative Performance", "_bench", self._cash*self.Securities["SPY"].Close/self._initialValue) self.Plot("Relative Performance", "Total Portfolio Value", self.Portfolio.TotalPortfolioValue) 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)[:5] 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)[:5] return [x[0] for x in selected_betas]