Overall Statistics
########################### DAILY


# from AlgorithmImports import *
# from datetime import datetime, timedelta

# class FlipCountTradingAlgorithm(QCAlgorithm):
#     def Initialize(self):
#         self.SetStartDate(2018, 1, 1)  # Set the start date for the algorithm
#         self.SetEndDate(datetime.today())  # Set the end date to today
#         #self.SetEndDate(2018,3,1)
#         self.SetCash(10000000)  # Set the initial cash for the algorithm
#         self.UniverseSettings.Resolution = Resolution.Daily  # Set the universe selection resolution to daily

#         # Add universe selection based on the constituents of SPY ETF
#         #self.AddUniverse(ETFConstituentUniverse, "SPY", self.UniverseSettings.Resolution, self.CoarseSelectionFunction, self.FineSelectionFunction)
#         #self.AddUniverseSelection(ETFConstituentsUniverseSelectionModel("SPY"))
        
#         #self.AddUniverse(self.CoarseSelectionFunction,self.FineSelectionFunction)
#         self.AddUniverse(self.FineSelectionFunction)


#         #self.add_universe(self.universe.etf("SPY"))

#         # Dictionary to store stock data including the rolling window
#         self.data = {}

#         # Define thresholds
#         self.buy_threshold = 9
#         self.sell_threshold = 9

#         # Lists to track long and short positions
#         self.long_positions = []
#         self.short_positions = []

#     # def CoarseSelectionFunction(self, coarse):
#     #     # Select all constituents of the ETF
#     #     f = [f.Symbol for f in coarse if f.market_cap > 10000000000]
#     #     return f

#     def CoarseSelectionFunction(self, coarse):
#         sorted_by_dollar_volume = sorted(coarse, key=lambda x: x.DollarVolume, reverse=True)
#         return [x.Symbol for x in sorted_by_dollar_volume[:1000]]


#     def FineSelectionFunction(self, fine):
#         # Filter fine universe to include only stocks with market cap > 10 billion
#         return [x.Symbol for x in fine if x.MarketCap > 1e10]


#     def OnSecuritiesChanged(self, changes):
#         # Remove data for securities that are no longer in the universe
#         for security in changes.RemovedSecurities:
#             if security.Symbol in self.data:
#                 del self.data[security.Symbol]

#         # Add data for new securities in the universe
#         for security in changes.AddedSecurities:
#             symbol = security.Symbol
#             # Initialize a RollingWindow for each added security to store the last 5 close prices
#             self.data[symbol] = {
#                 'price_window': RollingWindow[Decimal](5) ,
#                 'buy_count': 0,
#                 'sell_count': 0,
#                 'position_opened': False,
#                 'short_opened': False
#             }

#     def OnData(self, data):
#         for symbol, stock_data in self.data.items():
#             if data.Bars.ContainsKey(symbol):
#                 bar = data.Bars[symbol]
#                 stock_data['price_window'].Add(Decimal(bar.Close))
                
#                 if stock_data['price_window'].IsReady:
#                     current_close = stock_data['price_window'][0]
#                     past_close = stock_data['price_window'][4]

#                     if current_close < past_close:
#                         stock_data['sell_count'] += 1
#                         stock_data['buy_count'] = 0  # Reset buy count
#                     elif current_close > past_close:
#                         stock_data['buy_count'] += 1
#                         stock_data['sell_count'] = 0  # Reset sell count
#                     else:
#                         stock_data['buy_count'] = 0
#                         stock_data['sell_count'] = 0

#                     # Buy when Buy count >= Buy threshold
#                     if stock_data['buy_count'] == self.buy_threshold and not stock_data['position_opened']:
#                         self.long_positions.append(symbol)
#                         stock_data['position_opened'] = True
#                         self.Debug(f"Bought {symbol} at {current_close}")

#                     # Sell when next Sell flip happens
#                     if stock_data['sell_count'] == 1 and stock_data['position_opened']:
#                         self.long_positions.remove(symbol)
#                         self.Liquidate(symbol)
#                         stock_data['position_opened'] = False
#                         self.Debug(f"Sold {symbol} at {current_close}")

#                     # Short when Sell count >= Sell threshold
#                     if stock_data['sell_count'] == self.sell_threshold and not stock_data['short_opened']:
#                         self.short_positions.append(symbol)
#                         stock_data['short_opened'] = True
#                         self.Debug(f"Shorted {symbol} at {current_close}")

#                     # Cover when next Buy flip happens
#                     if stock_data['buy_count'] == 1 and stock_data['short_opened']:
#                         self.short_positions.remove(symbol)
#                         self.Liquidate(symbol)
#                         stock_data['short_opened'] = False
#                         self.Debug(f"Covered {symbol} at {current_close}")

#         self.Rebalance()

#     def Rebalance(self):
#         # Calculate the number of long and short positions
#         num_longs = len(self.long_positions)
#         num_shorts = len(self.short_positions)

#         # Define the maximum allocation per position
#         max_allocation = 0.05

#         if num_longs > 0:
#             long_allocation = min(max_allocation, 1.0 / num_longs)
#             for symbol in self.long_positions:
#                 current_quantity = self.Portfolio[symbol].Quantity
#                 price = self.Securities[symbol].Price
#                 if price > 0:
#                     target_quantity = round(self.Portfolio.TotalPortfolioValue * long_allocation / price)
#                     quantity_difference = target_quantity - current_quantity
#                     if quantity_difference != 0:
#                         self.MarketOrder(symbol, quantity_difference)

#         if num_shorts > 0:
#             short_allocation = -min(max_allocation, 1.0 / num_shorts)
#             for symbol in self.short_positions:
#                 current_quantity = self.Portfolio[symbol].Quantity
#                 price = self.Securities[symbol].Price
#                 if price > 0:
#                     target_quantity = round(self.Portfolio.TotalPortfolioValue * short_allocation / price)
#                     quantity_difference = target_quantity - current_quantity
#                     if quantity_difference != 0:
#                         self.MarketOrder(symbol, quantity_difference)

#     def OnEndOfAlgorithm(self):
#         self.Liquidate()
#         self.Debug("Liquidated all positions at the end of the algorithm.")

#     def LiquidateMostProfitable(self):
#         max_profit = 0
#         max_symbol = None
#         for symbol, holding in self.Portfolio.items():
#             profit = holding.UnrealizedProfit
#             if profit > max_profit:
#                 max_profit = profit
#                 max_symbol = symbol

#         if max_symbol is not None:
#             self.Liquidate(max_symbol)
#             self.Debug(f"Liquidated {max_symbol} to free up funds")



# ###################################### WEEKLY 

# from AlgorithmImports import *
# from datetime import datetime, timedelta

# class FlipCountTradingAlgorithm(QCAlgorithm):
#     def Initialize(self):
#         self.SetStartDate(2018, 1, 1)  # Set the start date for the algorithm
#         self.SetEndDate(datetime.today())  # Set the end date to today
#         self.SetCash(10000000)  # Set the initial cash for the algorithm

#         # Add universe selection based on the constituents of SPY ETF
#         self.UniverseSettings.Resolution = Resolution.Daily  # Universe selection resolution set to daily
#         self.add_universe(self.universe.etf("SPY"))
#         # Dictionary to store stock data including the rolling window
#         self.data = {}

#         # Define thresholds
#         self.buy_threshold = 9
#         self.sell_threshold = 9

#         # Lists to track long and short positions
#         self.long_positions = []
#         self.short_positions = []

#     def CoarseSelectionFunction(self, constituents):
#         # Select all constituents of the ETF
#         return [c.Symbol for c in constituents]

#     def FineSelectionFunction(self, fine):
#         # Filter fine universe to include only stocks with market cap > 10 billion
#         filtered_fine = [f for f in fine if f.MarketCap > 10e9]
#         return [f.Symbol for f in filtered_fine]

#     def OnSecuritiesChanged(self, changes):
#         # Remove data for securities that are no longer in the universe
#         for security in changes.RemovedSecurities:
#             if security.Symbol in self.data:
#                 del self.data[security.Symbol]

#         # Add data for new securities in the universe
#         for security in changes.AddedSecurities:
#             symbol = security.Symbol
#             self.data[symbol] = {
#                 'price_window': RollingWindow[Decimal](5) ,
#                 'buy_count': 0,
#                 'sell_count': 0,
#                 'position_opened': False,
#                 'short_opened': False
#             }
#             # Add consolidator for weekly data
#             consolidator = TradeBarConsolidator(timedelta(weeks=1))
#             consolidator.DataConsolidated += self.OnWeeklyData
#             self.SubscriptionManager.AddConsolidator(symbol, consolidator)

#     def OnWeeklyData(self, sender, bar):
#         symbol = bar.Symbol
#         if symbol in self.data:
#             stock_data = self.data[symbol]
#             stock_data['price_window'].Add(Decimal(bar.Close))

#             if stock_data['price_window'].IsReady:
#                 current_close = stock_data['price_window'][0]
#                 past_close = stock_data['price_window'][4]

#                 if current_close < past_close:
#                     stock_data['sell_count'] += 1
#                     stock_data['buy_count'] = 0  # Reset buy count
#                 elif current_close > past_close:
#                     stock_data['buy_count'] += 1
#                     stock_data['sell_count'] = 0  # Reset sell count
#                 else:
#                     stock_data['buy_count'] = 0
#                     stock_data['sell_count'] = 0

#                 # Buy when Buy count >= Buy threshold
#                 if stock_data['buy_count'] >= self.buy_threshold and not stock_data['position_opened']:
#                     self.long_positions.append(symbol)
#                     stock_data['position_opened'] = True
#                     self.Debug(f"Bought {symbol} at {current_close}")

#                 # Sell when next Sell flip happens
#                 if stock_data['sell_count'] == 1 and stock_data['position_opened']:
#                     self.long_positions.remove(symbol)
#                     self.Liquidate(symbol)
#                     stock_data['position_opened'] = False
#                     self.Debug(f"Sold {symbol} at {current_close}")

#                 # Short when Sell count >= Sell threshold
#                 if stock_data['sell_count'] >= self.sell_threshold and not stock_data['short_opened']:
#                     self.short_positions.append(symbol)
#                     stock_data['short_opened'] = True
#                     self.Debug(f"Shorted {symbol} at {current_close}")

#                 # Cover when next Buy flip happens
#                 if stock_data['buy_count'] == 1 and stock_data['short_opened']:
#                     self.short_positions.remove(symbol)
#                     self.Liquidate(symbol)
#                     stock_data['short_opened'] = False
#                     self.Debug(f"Covered {symbol} at {current_close}")

#         self.Rebalance()

#     def Rebalance(self):
#         # Calculate the number of long and short positions
#         num_longs = len(self.long_positions)
#         num_shorts = len(self.short_positions)

#         # Define the maximum allocation per position
#         max_allocation = 0.05

#         if num_longs > 0:
#             long_allocation = min(max_allocation, 1.0 / num_longs)
#             for symbol in self.long_positions:
#                 current_quantity = self.Portfolio[symbol].Quantity
#                 price = self.Securities[symbol].Price
#                 if price > 0:
#                     target_quantity = round(self.Portfolio.TotalPortfolioValue * long_allocation / price)
#                     quantity_difference = target_quantity - current_quantity
#                     if quantity_difference != 0:
#                         self.MarketOrder(symbol, quantity_difference)

#         if num_shorts > 0:
#             short_allocation = -min(max_allocation, 1.0 / num_shorts)
#             for symbol in self.short_positions:
#                 current_quantity = self.Portfolio[symbol].Quantity
#                 price = self.Securities[symbol].Price
#                 if price > 0:
#                     target_quantity = round(self.Portfolio.TotalPortfolioValue * short_allocation / price)
#                     quantity_difference = target_quantity - current_quantity
#                     if quantity_difference != 0:
#                         self.MarketOrder(symbol, quantity_difference)

#     def OnEndOfAlgorithm(self):
#         self.Liquidate()
#         self.Debug("Liquidated all positions at the end of the algorithm.")

#     def LiquidateMostProfitable(self):
#         max_profit = 0
#         max_symbol = None
#         for symbol, holding in self.Portfolio.items():
#             profit = holding.UnrealizedProfit
#             if profit > max_profit:
#                 max_profit = profit
#                 max_symbol = symbol

#         if max_symbol is not None:
#             self.Liquidate(max_symbol)
#             self.Debug(f"Liquidated {max_symbol} to free up funds")


###############################################################################################


# Order after flip startegy 

# from AlgorithmImports import *
# from datetime import datetime, timedelta

# class FlipCountTradingAlgorithm(QCAlgorithm):
#     def Initialize(self):
#         self.SetStartDate(2024, 1, 1)  # Set the start date for the algorithm
#         self.SetEndDate(datetime.today())  # Set the end date to today
#         self.SetCash(10000000)  # Set the initial cash for the algorithm
#         self.UniverseSettings.Resolution = Resolution.Daily  # Set the universe selection resolution to daily

#         self.add_universe(self.universe.etf("SPY"))

#         # Add universe selection based on the constituents of SPY ETF
#         #self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)

#         # Dictionary to store stock data including the rolling window
#         self.data = {}

#         # Define thresholds
#         self.buy_threshold = 9
#         self.sell_threshold = 9

#         # Lists to track long and short positions
#         self.long_positions = []
#         self.short_positions = []

#     # def CoarseSelectionFunction(self, coarse):
#     #     sorted_by_dollar_volume = sorted(coarse, key=lambda x: x.DollarVolume, reverse=True)
#     #     return [x.Symbol for x in sorted_by_dollar_volume[:500]]

#     # def FineSelectionFunction(self, fine):
#     #     # Filter fine universe to include only stocks with market cap > 10 billion
#     #     return [x.Symbol for x in fine if x.MarketCap > 1e10]

#     def OnSecuritiesChanged(self, changes):
#         # Remove data for securities that are no longer in the universe
#         for security in changes.RemovedSecurities:
#             if security.Symbol in self.data:
#                 del self.data[security.Symbol]

#         # Add data for new securities in the universe
#         for security in changes.AddedSecurities:
#             symbol = security.Symbol
#             # Initialize a RollingWindow for each added security to store the last 5 close prices
#             self.data[symbol] = {
#                 'price_window': RollingWindow[Decimal](5) ,
#                 'buy_count': 0,
#                 'sell_count': 0,
#                 'position_opened': False,
#                 'short_opened': False,
#                 'prev_buy_threshold_crossed': False,
#                 'prev_sell_threshold_crossed': False
#             }

#     def OnData(self, data):
#         for symbol, stock_data in self.data.items():
#             if data.Bars.ContainsKey(symbol):
#                 bar = data.Bars[symbol]
#                 stock_data['price_window'].Add(Decimal(bar.Close))
                
#                 if stock_data['price_window'].IsReady:
#                     current_close = stock_data['price_window'][0]
#                     past_close = stock_data['price_window'][4]

#                     if current_close < past_close:
#                         stock_data['sell_count'] += 1
#                         stock_data['buy_count'] = 0  # Reset buy count
#                     elif current_close > past_close:
#                         stock_data['buy_count'] += 1
#                         stock_data['sell_count'] = 0  # Reset sell count
#                     else:
#                         stock_data['buy_count'] = 0
#                         stock_data['sell_count'] = 0


                    
#                     # Update threshold crossing flags
#                     if stock_data['buy_count'] >= self.buy_threshold:
#                         stock_data['prev_buy_threshold_crossed'] = True
#                         stock_data['prev_sell_threshold_crossed'] = False

#                     if stock_data['sell_count'] >= self.sell_threshold:
#                         stock_data['prev_sell_threshold_crossed'] = True
#                         stock_data['prev_buy_threshold_crossed'] = False

#                     # If buy threshold was crossed and now there's a sell signal, sell
#                     if stock_data['prev_buy_threshold_crossed'] and stock_data['sell_count'] == 1:
#                         if stock_data['position_opened']:
#                             self.long_positions.remove(symbol)
#                             self.Liquidate(symbol)
#                             stock_data['position_opened'] = False
#                             self.Debug(f"Sold {symbol} at {current_close}")
                        

#                         else :
#                             self.short_positions.append(symbol)
#                             stock_data['short_opened']=True
#                             self.Debug(f"Shorted {symbol} at {current_close}")

#                         stock_data['prev_buy_threshold_crossed'] = False
                        


#                     # If sell threshold was crossed and now there's a buy signal, cover (buy back)
#                     if stock_data['prev_sell_threshold_crossed'] and stock_data['buy_count'] == 1:
#                         if stock_data['short_opened']:
#                             self.short_positions.remove(symbol)
#                             self.Liquidate(symbol)
#                             stock_data['short_opened'] = False
#                             self.Debug(f"Covered {symbol} at {current_close}")


#                         else :
#                             self.long_positions.append(symbol)
#                             stock_data['position_opened']=True
#                             self.Debug(f"Bought {symbol} at {current_close}")


#                         stock_data['prev_sell_threshold_crossed'] = False


# #                     # Buy when Buy count >= Buy threshold
# #                     if stock_data['buy_count'] == self.buy_threshold and not stock_data['position_opened']:
# #                         self.long_positions.append(symbol)
# #                         stock_data['position_opened'] = True
# #                         self.Debug(f"Bought {symbol} at {current_close}")

# #                     # Sell when next Sell flip happens
# #                     if stock_data['sell_count'] == 1 and stock_data['position_opened']:
# #                         self.long_positions.remove(symbol)
# #                         self.Liquidate(symbol)
# #                         stock_data['position_opened'] = False
# #                         self.Debug(f"Sold {symbol} at {current_close}")

# #                     # Short when Sell count >= Sell threshold
# #                     if stock_data['sell_count'] == self.sell_threshold and not stock_data['short_opened']:
# #                         self.short_positions.append(symbol)
# #                         stock_data['short_opened'] = True
# #                         self.Debug(f"Shorted {symbol} at {current_close}")

# #                     # Cover when next Buy flip happens
# #                     if stock_data['buy_count'] == 1 and stock_data['short_opened']:
# #                         self.short_positions.remove(symbol)
# #                         self.Liquidate(symbol)
# #                         stock_data['short_opened'] = False
# #                         self.Debug(f"Covered {symbol} at {current_close}")

                    

#         self.Rebalance()

#     def Rebalance(self):
#         # Calculate the number of long and short positions
#         num_longs = len(self.long_positions)
#         num_shorts = len(self.short_positions)

#         # Define the maximum allocation per position
#         max_allocation = 0.05

#         if num_longs > 0:
#             long_allocation = min(max_allocation, 1.0 / num_longs)
#             for symbol in self.long_positions:
#                 current_quantity = self.Portfolio[symbol].Quantity
#                 price = self.Securities[symbol].Price
#                 if price > 0:
#                     target_quantity = round(self.Portfolio.TotalPortfolioValue * long_allocation / price)
#                     quantity_difference = target_quantity - current_quantity
#                     if quantity_difference != 0:
#                         self.MarketOrder(symbol, quantity_difference)

#         if num_shorts > 0:
#             short_allocation = -min(max_allocation, 1.0 / num_shorts)
#             for symbol in self.short_positions:
#                 current_quantity = self.Portfolio[symbol].Quantity
#                 price = self.Securities[symbol].Price
#                 if price > 0:
#                     target_quantity = round(self.Portfolio.TotalPortfolioValue * short_allocation / price)
#                     quantity_difference = target_quantity - current_quantity
#                     if quantity_difference != 0:
#                         self.MarketOrder(symbol, quantity_difference)

#     def OnEndOfAlgorithm(self):
#         self.Liquidate()
#         self.Debug("Liquidated all positions at the end of the algorithm.")

#     def LiquidateMostProfitable(self):
#         max_profit = 0
#         max_symbol = None
#         for symbol, holding in self.Portfolio.items():
#             profit = holding.UnrealizedProfit
#             if profit > max_profit:
#                 max_profit = profit
#                 max_symbol = symbol

#         if max_symbol is not None:
#             self.Liquidate(max_symbol)
#             self.Debug(f"Liquidated {max_symbol} to free up funds")


#################################################################################################


# Testtttt  Order after flip startegy 

from AlgorithmImports import *
from datetime import datetime, timedelta

class FlipCountTradingAlgorithm(QCAlgorithm):
    def Initialize(self):
        self.SetStartDate(2020, 1, 1)  # Set the start date for the algorithm
        self.SetEndDate(datetime.today())  # Set the end date to today
        self.SetCash(10000000)  # Set the initial cash for the algorithm
        self.UniverseSettings.Resolution = Resolution.Daily  # Set the universe selection resolution to daily

        #self.add_universe(self.universe.etf("SPY"))

        # Add specific securities to the universe
        # self.AddEquity("GOOGL", Resolution.Daily)
        # self.AddEquity("AAPL", Resolution.Daily)


        # Add universe selection based on the constituents of SPY ETF
        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)

        # Dictionary to store stock data including the rolling window
        self.data = {}

        # Define thresholds
        self.buy_threshold = 9
        self.sell_threshold = 9

        # Lists to track long and short positions
        self.long_positions = []
        self.short_positions = []

    def CoarseSelectionFunction(self, coarse):
        sorted_by_dollar_volume = sorted(coarse, key=lambda x: x.DollarVolume, reverse=True)
        return [x.Symbol for x in sorted_by_dollar_volume[:500]]

    def FineSelectionFunction(self, fine):
        # Filter fine universe to include only stocks with market cap > 10 billion
        return [x.Symbol for x in fine if x.MarketCap > 1e10]

    def OnSecuritiesChanged(self, changes):
        # Remove data for securities that are no longer in the universe
        for security in changes.RemovedSecurities:
            if security.Symbol in self.data:
                del self.data[security.Symbol]

        # Add data for new securities in the universe
        for security in changes.AddedSecurities:
            symbol = security.Symbol
            # Initialize a RollingWindow for each added security to store the last 5 close prices
            self.data[symbol] = {
                'price_window': RollingWindow[Decimal](5) ,
                'buy_count': 0,
                'sell_count': 0,
                'position_opened': False,
                'short_opened': False,
                'prev_buy_threshold_crossed': False,
                'prev_sell_threshold_crossed': False
            }

    def OnData(self, data):
        for symbol, stock_data in self.data.items():
            if data.Bars.ContainsKey(symbol):
                bar = data.Bars[symbol]
                stock_data['price_window'].Add(Decimal(bar.Close))
                
                if stock_data['price_window'].IsReady:
                    current_close = stock_data['price_window'][0]
                    past_close = stock_data['price_window'][4]

                    if current_close < past_close:
                        stock_data['sell_count'] += 1
                        stock_data['buy_count'] = 0  # Reset buy count
                    elif current_close > past_close:
                        stock_data['buy_count'] += 1
                        stock_data['sell_count'] = 0  # Reset sell count
                    else:
                        stock_data['buy_count'] = 0
                        stock_data['sell_count'] = 0


                    
                    # Update threshold crossing flags
                    if stock_data['buy_count'] >= self.buy_threshold:
                        stock_data['prev_buy_threshold_crossed'] = True
                        stock_data['prev_sell_threshold_crossed'] = False

                    if stock_data['sell_count'] >= self.sell_threshold:
                        stock_data['prev_sell_threshold_crossed'] = True
                        stock_data['prev_buy_threshold_crossed'] = False

                    # If buy threshold was crossed and now there's a sell signal, sell
                    if stock_data['prev_buy_threshold_crossed'] and stock_data['sell_count'] == 1:
                        if stock_data['position_opened']:
                            self.long_positions.remove(symbol)
                            #self.Liquidate(symbol)
                            self.short_positions.append(symbol)
                            stock_data['short_opened']=True
                            stock_data['position_opened'] = False
                            self.Debug(f"Sold {symbol} at {current_close}")
                            self.Debug(f"Shorted {symbol} at {current_close}")
                        

                        else :
                            self.short_positions.append(symbol)
                            stock_data['short_opened']=True
                            self.Debug(f"Shorted {symbol} at {current_close}")

                        stock_data['prev_buy_threshold_crossed'] = False
                        


                    # If sell threshold was crossed and now there's a buy signal, cover (buy back)
                    if stock_data['prev_sell_threshold_crossed'] and stock_data['buy_count'] == 1:
                        if stock_data['short_opened']:
                            self.short_positions.remove(symbol)
                            #self.Liquidate(symbol)
                            self.long_positions.append(symbol)
                            stock_data['position_opened']=True
                            stock_data['short_opened'] = False
                            self.Debug(f"Covered {symbol} at {current_close}")
                            self.Debug(f"Bought {symbol} at {current_close}")


                        else :
                            self.long_positions.append(symbol)
                            stock_data['position_opened']=True
                            self.Debug(f"Bought {symbol} at {current_close}")


                        stock_data['prev_sell_threshold_crossed'] = False


#                     # Buy when Buy count >= Buy threshold
#                     if stock_data['buy_count'] == self.buy_threshold and not stock_data['position_opened']:
#                         self.long_positions.append(symbol)
#                         stock_data['position_opened'] = True
#                         self.Debug(f"Bought {symbol} at {current_close}")

#                     # Sell when next Sell flip happens
#                     if stock_data['sell_count'] == 1 and stock_data['position_opened']:
#                         self.long_positions.remove(symbol)
#                         self.Liquidate(symbol)
#                         stock_data['position_opened'] = False
#                         self.Debug(f"Sold {symbol} at {current_close}")

#                     # Short when Sell count >= Sell threshold
#                     if stock_data['sell_count'] == self.sell_threshold and not stock_data['short_opened']:
#                         self.short_positions.append(symbol)
#                         stock_data['short_opened'] = True
#                         self.Debug(f"Shorted {symbol} at {current_close}")

#                     # Cover when next Buy flip happens
#                     if stock_data['buy_count'] == 1 and stock_data['short_opened']:
#                         self.short_positions.remove(symbol)
#                         self.Liquidate(symbol)
#                         stock_data['short_opened'] = False
#                         self.Debug(f"Covered {symbol} at {current_close}")

                    

        self.Rebalance()

    def Rebalance(self):
        # Calculate the number of long and short positions
        num_longs = len(self.long_positions)
        num_shorts = len(self.short_positions)

        # Define the maximum allocation per position
        max_allocation = 0.05

        if num_longs > 0:
            long_allocation = min(max_allocation, 1.0 / num_longs)
            for symbol in self.long_positions:
                current_quantity = self.Portfolio[symbol].Quantity
                price = self.Securities[symbol].Price
                if price > 0:
                    target_quantity = round(self.Portfolio.TotalPortfolioValue * long_allocation / price)
                    quantity_difference = target_quantity - current_quantity
                    if quantity_difference != 0:
                        self.MarketOrder(symbol, quantity_difference)

        if num_shorts > 0:
            short_allocation = -min(max_allocation, 1.0 / num_shorts)
            for symbol in self.short_positions:
                current_quantity = self.Portfolio[symbol].Quantity
                price = self.Securities[symbol].Price
                if price > 0:
                    target_quantity = round(self.Portfolio.TotalPortfolioValue * short_allocation / price)
                    quantity_difference = target_quantity - current_quantity
                    if quantity_difference != 0:
                        self.MarketOrder(symbol, quantity_difference)

    def OnEndOfAlgorithm(self):
        self.Liquidate()
        self.Debug("Liquidated all positions at the end of the algorithm.")

    def LiquidateMostProfitable(self):
        max_profit = 0
        max_symbol = None
        for symbol, holding in self.Portfolio.items():
            profit = holding.UnrealizedProfit
            if profit > max_profit:
                max_profit = profit
                max_symbol = symbol

        if max_symbol is not None:
            self.Liquidate(max_symbol)
            self.Debug(f"Liquidated {max_symbol} to free up funds")