Overall Statistics
Total Orders
409
Average Win
0.75%
Average Loss
-0.48%
Compounding Annual Return
40.373%
Drawdown
50.700%
Expectancy
1.253
Start Equity
100000
End Equity
571287.91
Net Profit
471.288%
Sharpe Ratio
1.013
Sortino Ratio
1.262
Probabilistic Sharpe Ratio
49.628%
Loss Rate
12%
Win Rate
88%
Profit-Loss Ratio
1.56
Alpha
0.148
Beta
1.609
Annual Standard Deviation
0.272
Annual Variance
0.074
Information Ratio
1.132
Tracking Error
0.173
Treynor Ratio
0.171
Total Fees
$421.39
Estimated Strategy Capacity
$0
Lowest Capacity Asset
NVDA RHM8UTD8DT2D
Portfolio Turnover
0.26%
Drawdown Recovery
514
#region imports
from AlgorithmImports import *
#endregion

class AIBasketStrategy(QCAlgorithm):

    def Initialize(self):
        # 1. Setup: Last 5 Years
        self.SetStartDate(2020, 11, 10)  
        self.SetEndDate(2026, 1, 1)    
        self.SetCash(100000) 

        # 2. Define the "AI Basket"
        # We manually select the leaders to ensure purity of the theme
        self.tickers = [
            "NVDA", # GPU King
            "AMD",  # GPU Challenger
            "TSM",  # The Foundry (makes the chips)
            "AVGO", # Broadcom (Custom AI chips & Networking)
            "MSFT", # OpenAI / Cloud
            "GOOGL",# Gemini / DeepMind
            "META", # LLaMA / Meta AI
            "PLTR"  # AI Data Foundry
        ]
        
        self.symbols = []
        for ticker in self.tickers:
            # Add equity and set resolution to Daily (sufficient for rebalancing)
            symbol = self.AddEquity(ticker, Resolution.Daily).Symbol
            self.symbols.append(symbol)

        # 3. Schedule Rebalancing (First trading day of every month)
        # This keeps the portfolio strictly equal-weighted
        self.Schedule.On(
            self.DateRules.MonthStart("NVDA"),
            self.TimeRules.AfterMarketOpen("NVDA", 30),
            self.Rebalance
        )
        
        # 4. Realistic Settings
        self.SetSecurityInitializer(lambda x: x.SetFeeModel(ConstantFeeModel(1.0)))
        self.SetBenchmark("SPY") # Compare against S&P 500

    def Rebalance(self):
        # Calculate target weight (100% / 8 stocks = 12.5% each)
        # We check if stock has data to avoid errors (e.g. if one was delisted or halted)
        valid_symbols = [s for s in self.symbols if self.Securities[s].Price > 0]
        
        if len(valid_symbols) == 0: return
        
        weight = 1.0 / len(valid_symbols)
        
        # Execute Trades
        for symbol in valid_symbols:
            self.SetHoldings(symbol, weight)
            
    def OnData(self, data):
        # We don't need trade logic here because the Scheduler handles it.
        pass