Overall Statistics |
Total Trades 4676 Average Win 0.65% Average Loss -0.32% Compounding Annual Return 1.450% Drawdown 24.300% Expectancy 0.051 Net Profit 41.554% Sharpe Ratio -0.133 Sortino Ratio -0.135 Probabilistic Sharpe Ratio 0.000% Loss Rate 66% Win Rate 34% Profit-Loss Ratio 2.06 Alpha -0.005 Beta -0.094 Annual Standard Deviation 0.067 Annual Variance 0.004 Information Ratio -0.267 Tracking Error 0.187 Treynor Ratio 0.095 Total Fees $0.00 Estimated Strategy Capacity $1100000.00 Lowest Capacity Asset DBC TFVSB03UY0DH Portfolio Turnover 9.41% |
#region imports from AlgorithmImports import * #endregion class SectorMomentum(QCAlgorithm): def Initialize(self): self.SetStartDate(2000, 1, 1) self.SetCash(100000) # daily ROC data self.data: Dict[str, RateOfChange] = {} self.roc_period: int = 6 * 21 self.SetWarmUp(self.roc_period, Resolution.Daily) self.selected_symbol_count: int = 3 # long symbol count self.no_trading_fees: bool = True self.long_universe: List[str] = [ "SPY", # SPDR S&P 500 ETF Trust (large cap US stocks) "EEM", # iShares MSCI Emerging Markets ETF (emerging market stocks) "EFA", # iShares MSCI EAFE ETF (EAFE stocks) "VNQ", # Vanguard Real Estate Index Fund ETF (real estate, REITs) "AGG", # iShares Core U.S. Aggregate Bond ETF (fixed income ETF) "GLD", # SPDR Gold Shares (GLD) (gold) "DBC", # Invesco DB Commodity Index Tracking Fund (broad commodity index) "IWM", # iShares Russell 2000 ETF (small cap US stocks) ] # NOTE long and short universe are the same for now, might be different in the future self.short_universe: List[str] = self.long_universe.copy() # self.short_symbols:List[str] = [ # "VNQ", # Vanguard Real Estate Index Fund # "XLK", # Technology Select Sector SPDR Fund # "XLE", # Energy Select Sector SPDR Fund # "XLV", # Health Care Select Sector SPDR Fund # "XLF", # Financial Select Sector SPDR Fund # "XLI", # Industrials Select Sector SPDR Fund # "XLB", # Materials Select Sector SPDR Fund # "XLY", # Consumer Discretionary Select Sector SPDR Fund # "XLP", # Consumer Staples Select Sector SPDR Fund # "XLU" # Utilities Select Sector SPDR Fund # ] for ticker in set(self.long_universe + self.short_universe): data: Equity = self.AddEquity(ticker, Resolution.Daily) if ticker in self.long_universe: data.SetLeverage(5) if self.no_trading_fees: data.SetFeeModel(CustomFeeModel()) self.data[ticker] = self.ROC(ticker, self.roc_period, Resolution.Daily) self.data[self.long_universe[0]].Updated += self.OnROCUpdated self.recent_month: int = -1 self.rebalance_flag: bool = False def OnROCUpdated(self, sender, updated) -> None: # set rebalance flag if self.recent_month != self.Time.month: self.recent_month = self.Time.month self.rebalance_flag = True def OnData(self, data: Slice) -> None: if self.IsWarmingUp: return # rebalance once a month if self.rebalance_flag: self.rebalance_flag = False # sort long universe by momentum sorted_by_momentum:List = sorted( [x for x in self.data.items() if x[1].IsReady and \ x[0] in self.long_universe and \ x[0] in data and data[x[0]]], \ key = lambda x: x[1].Current.Value, reverse = True ) if len(sorted_by_momentum) < self.selected_symbol_count: self.Liquidate() return long: List[str] = [x[0] for x in sorted_by_momentum[:self.selected_symbol_count]] # trade execution self.Liquidate() for ticker in long: quantity: int = self.Portfolio.TotalPortfolioValue // len(long) // data[ticker].Close self.MarketOrder(ticker, quantity) # short EW selected ETF short_universe: List[str] = [x for x in self.short_universe if x in data and data[x]] for ticker in short_universe: quantity: int = self.Portfolio.TotalPortfolioValue // len(short_universe) // data[ticker].Close self.MarketOrder(ticker, -quantity) # Custom fee model class CustomFeeModel(FeeModel): def GetOrderFee(self, parameters): fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.0 return OrderFee(CashAmount(fee, "USD"))