Overall Statistics |
Total Trades 2949 Average Win 0.42% Average Loss -0.38% Compounding Annual Return 25.801% Drawdown 29.800% Expectancy 0.415 Net Profit 892.790% Sharpe Ratio 0.994 Sortino Ratio 1.031 Probabilistic Sharpe Ratio 50.305% Loss Rate 33% Win Rate 67% Profit-Loss Ratio 1.11 Alpha 0.099 Beta 0.973 Annual Standard Deviation 0.173 Annual Variance 0.03 Information Ratio 0.973 Tracking Error 0.1 Treynor Ratio 0.177 Total Fees $2963.23 Estimated Strategy Capacity $86000000.00 Lowest Capacity Asset PX R735QTJ8XC9X Portfolio Turnover 4.54% |
from AlgorithmImports import * class MomentumAndSMAStrategy(QCAlgorithm): def Initialize(self): self.SetStartDate(2014, 1, 1) # Start Date self.SetEndDate(2024, 1, 1) # End Date self.SetCash(10000) # Set Strategy Cash self.tickers = ["MSFT", "AAPL", "NVDA", "AMZN", "GOOG", "GOOGL", "META", "BRK/A", "BRK/B", "LLY", "AVGO", "TSLA", "JPM", "V", "WMT", "UNH", "MA", "XOM", "JNJ", "HD", "PG", "COST", "AMD", "MRK", "ABBV", "ORCL", "CRM", "CVX", "BAC", "NFLX", "KO", "ADBE", "PEP", "TMO", "LIN", "MCD", "ABT", "DIS"] self.symbols = [Symbol.Create(ticker, SecurityType.Equity, Market.USA) for ticker in self.tickers] self.AddEquity("SPY", Resolution.Daily) # Benchmark for symbol in self.symbols: self.AddEquity(symbol.Value, Resolution.Daily) self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", 10), self.RankStocks) self.Schedule.On(self.DateRules.Every(DayOfWeek.Monday), self.TimeRules.BeforeMarketClose("SPY", 10), self.Rebalance) self.ranked_symbols = [] def RankStocks(self): scores = {} for symbol in self.symbols: history = self.History(symbol, 210, Resolution.Daily) # Fetching enough data for 200-day SMA if history.empty or len(history) < 210: self.Log(f"Not enough data for {symbol.Value} to rank") continue # Calculate Indicators close = history['close'] momentum = (close.iloc[-1] / close.iloc[-90]) - 1 rsi = self.RSI(symbol, 14, MovingAverageType.Wilders, Resolution.Daily, Field.Close).Current.Value sma50 = self.SMA(symbol, 50, Resolution.Daily, Field.Close).Current.Value sma200 = self.SMA(symbol, 200, Resolution.Daily, Field.Close).Current.Value # Example scoring formula score = momentum + rsi/100 + (sma50 + sma200)/2 scores[symbol] = score # Sort symbols by score in descending order and keep the top 10 self.ranked_symbols = sorted(scores, key=scores.get, reverse=True)[:10] def Rebalance(self): if len(self.ranked_symbols) == 0: self.Log("No ranked symbols to rebalance") return # Calculate portfolio target size for each position target_size = 1.0 / len(self.ranked_symbols) # Sell symbols not in the top 10 anymore current_holdings = [s.Symbol for s in self.Portfolio.Values if s.Invested and s.Symbol not in self.ranked_symbols] for symbol in current_holdings: self.Liquidate(symbol) # Buy or adjust positions for the top 10 stocks for symbol in self.ranked_symbols: self.SetHoldings(symbol, target_size) def OnData(self, data): # If you don't need to do anything on each data slice, you can leave this empty pass