Created with Highcharts 12.1.2EquityJan 2024Jan…Feb 2024Mar 2024Apr 2024May 2024Jun 2024Jul 2024Aug 2024Sep 2024Oct 2024Nov 2024Dec 2024Jan 2025100k200k300k-20-1000240120100M02M4M49.849.8549.949.95
Overall Statistics
Total Orders
23
Average Win
6.01%
Average Loss
-4.05%
Compounding Annual Return
32.847%
Drawdown
13.400%
Expectancy
0.580
Start Equity
200000
End Equity
263565.29
Net Profit
31.783%
Sharpe Ratio
0.905
Sortino Ratio
0.506
Probabilistic Sharpe Ratio
53.438%
Loss Rate
36%
Win Rate
64%
Profit-Loss Ratio
1.48
Alpha
0.122
Beta
0.488
Annual Standard Deviation
0.206
Annual Variance
0.042
Information Ratio
0.271
Tracking Error
0.206
Treynor Ratio
0.381
Total Fees
$564.09
Estimated Strategy Capacity
$37000000.00
Lowest Capacity Asset
TYH U8JOSZGR4OKL
Portfolio Turnover
6.41%
from AlgorithmImports import *
from datetime import datetime, timedelta

class SummrBusinessTechnologySemiconductor(QCAlgorithm):
    def Initialize(self):
        self.SetStartDate(2024, 1, 1)  # Set Start Date
        self.SetCash(200000)  # Set Strategy Cash
        
        # Define symbols
        self.symbols = {
            "SOXL": "SOXL", "UPRO": "UPRO", "BIL": "BIL", "TLH": "TLH", 
            "SPY": "SPY", "UVXY": "UVXY", "VIXY": "VIXY", "SOXS": "SOXS",
            "BSV": "BSV", "SPHB": "SPHB", "SQQQ": "SQQQ", "TECL": "TECL",
            "TQQQ": "TQQQ", "SPXL": "SPXL", "QLD": "QLD", "SPXU": "SPXU",
            "EUO": "EUO", "YCS": "YCS", "CURE": "CURE", "TMV": "TMV",
            "UUP": "UUP", "TECS": "TECS", "ERX": "ERX", "EWZ": "EWZ",
            "MVV": "MVV", "USD": "USD", "DBC": "DBC", "TLT": "TLT",
            "IEF": "IEF", "SHY": "SHY", "GLD": "GLD", "UCO": "UCO",
            "TMF": "TMF", "EFA": "EFA", "EEM": "EEM", "EPI": "EPI",
            "PUI": "PUI", "AGG": "AGG", "PSQ": "PSQ"
        }
        
        # Add all symbols to the algorithm
        for symbol in self.symbols.values():
            self.AddEquity(symbol, Resolution.Daily)
        
        self.SetWarmUp(timedelta(days=360))  # Warmup period for indicators
        
        # Initialize indicators
        self.indicators = {}
        for symbol in self.symbols.values():
            self.indicators[symbol] = {
                "RSI_5": self.RSI(symbol, 5),
                "RSI_6": self.RSI(symbol, 6),
                "RSI_7": self.RSI(symbol, 7),
                "RSI_8": self.RSI(symbol, 8),
                "RSI_9": self.RSI(symbol, 9),
                "RSI_10": self.RSI(symbol, 10),
                "RSI_11": self.RSI(symbol, 11),
                "RSI_12": self.RSI(symbol, 12),
                "RSI_13": self.RSI(symbol, 13),
                "RSI_18": self.RSI(symbol, 18),
                "RSI_42": self.RSI(symbol, 42),
                "RSI_70": self.RSI(symbol, 70),
                "SMA_12": self.SMA(symbol, 12),
                "SMA_200": self.SMA(symbol, 200),
                "EMA_210": self.EMA(symbol, 210),
                "SMA_360": self.SMA(symbol, 360),
                "STD_20": self.STD(symbol, 20)
            }
        
        self.Schedule.On(self.DateRules.EveryDay(), 
                        self.TimeRules.BeforeMarketClose("SPY", 10), 
                        self.Rebalance)

    def OnData(self, data):
        pass  # Main logic handled in Rebalance

    def Rebalance(self):
        if self.IsWarmingUp: return
        
        # Clear existing positions
        self.Liquidate()
        
        # Main strategy logic
        selected_assets = self.SelectAssets()
        
        if selected_assets:
            # Equal weight distribution
            weight = 1.0 / len(selected_assets)
            for symbol in selected_assets:
                self.SetHoldings(symbol, weight)

    def SelectAssets(self):
        """Main asset selection logic"""
        # Initial condition check
        if self.indicators["SOXL"]["RSI_8"].Current.Value > self.indicators["UPRO"]["RSI_9"].Current.Value:
            return self.TechnologyFocusedSelection()
        else:
            return self.AlternativeSelection()

    def TechnologyFocusedSelection(self):
        """Technology focused selection logic"""
        if self.indicators["BIL"]["RSI_10"].Current.Value < self.indicators["TLH"]["RSI_10"].Current.Value:
            if self.indicators["SPY"]["RSI_6"].Current.Value > 75:
                return self.SelectVolatilityAssets()
            else:
                return self.SelectTechnologyAssets()
        else:
            return self.SelectDefensiveAssets()

    def SelectVolatilityAssets(self):
        """Select volatility based assets"""
        volatility_assets = ["UVXY", "VIXY"]
        return [self.SelectLowestRSI(volatility_assets, 13)]

    def SelectTechnologyAssets(self):
        """Select technology focused assets"""
        if self.indicators["SOXL"]["RSI_5"].Current.Value <= 75:
            return ["SOXL"]
        else:
            return ["SOXS"]

    def SelectDefensiveAssets(self):
        """Select defensive assets"""
        if self.indicators["SPY"]["RSI_6"].Current.Value < 27:
            if self.indicators["BSV"]["RSI_7"].Current.Value < self.indicators["SPHB"]["RSI_7"].Current.Value:
                bear_assets = ["SOXS", "SQQQ"]
                return [self.SelectLowestRSI(bear_assets, 7)]
            else:
                bull_assets = ["SOXL", "TECL"]
                return [self.SelectLowestRSI(bull_assets, 7)]
        return []

    def SelectLowestRSI(self, assets, period):
        """Helper function to select asset with lowest RSI"""
        lowest_rsi = float('inf')
        selected_asset = None
        
        for asset in assets:
            rsi_key = f"RSI_{period}" if f"RSI_{period}" in self.indicators[asset] else "RSI_10"
            current_rsi = self.indicators[asset][rsi_key].Current.Value
            if current_rsi < lowest_rsi:
                lowest_rsi = current_rsi
                selected_asset = asset
                
        return selected_asset

    def STD(self, symbol, period):
        """Standard deviation indicator"""
        # Create StandardDeviation indicator
        return StandardDeviation(period)

    def AlternativeSelection(self):
        """Alternative selection logic when SOXL RSI is not greater than UPRO RSI"""
        # Implementing the second part of the strategy
        if self.indicators["BIL"]["RSI_42"].Current.Value < self.indicators["IEF"]["RSI_70"].Current.Value:
            if self.indicators["SPY"]["RSI_7"].Current.Value > 75:
                # Overbought S&P condition
                volatility_assets = ["UVXY", "VIXY"]
                return [self.SelectLowestRSI(volatility_assets, 12)]
            else:
                # Check SOXL momentum
                if (self.Securities["SOXL"].Price > 
                    self.indicators["SOXL"]["SMA_200"].Current.Value):
                    momentum_assets = ["SOXL", "UPRO"]
                    return [self.SelectLowestMAReturn(momentum_assets, 12)]
                else:
                    hedge_assets = ["SOXS", "SQQQ"]
                    return [self.SelectLowestMAReturn(hedge_assets, 12)]
        else:
            if self.indicators["SPY"]["RSI_6"].Current.Value < 27:
                # Extremely oversold condition
                if self.indicators["BSV"]["RSI_8"].Current.Value < self.indicators["SPHB"]["RSI_8"].Current.Value:
                    bear_assets = ["SOXS", "SQQQ"]
                    return [self.SelectLowestRSI(bear_assets, 18)]
                else:
                    bull_assets = ["SOXL", "SPXL", "TECL", "TMF", "UPRO", "USD", "TQQQ"]
                    return [self.SelectLowestRSI(bull_assets, 18)]
            return []

    def SelectLowestMAReturn(self, assets, period):
        """Helper function to select asset with lowest moving average return"""
        lowest_ma = float('inf')
        selected_asset = None
        
        for asset in assets:
            current_price = self.Securities[asset].Price
            # Use SMA_200 as default if the requested period's SMA doesn't exist
            sma_key = f"SMA_{period}" if f"SMA_{period}" in self.indicators[asset] else "SMA_200"
            ma_price = self.indicators[asset][sma_key].Current.Value
            if ma_price is not None and ma_price != 0:
                ma_return = (current_price - ma_price) / ma_price
                if ma_return < lowest_ma:
                    lowest_ma = ma_return
                    selected_asset = asset
                
        return selected_asset