from AlgorithmImports import *
from QuantConnect import *
from QuantConnect.Algorithm import QCAlgorithm
from QuantConnect.Indicators.CandlestickPatterns import Engulfing
from datetime import timedelta

class Watchlist(QCAlgorithm):
    def Initialize(self):
        self.SetStartDate(2023, 5, 17)  # Start Date
        self.SetEndDate(2023, 5, 27)  # End Date
        self.SetCash(100000)  # Set Strategy Cash
        self.UniverseSettings.Resolution = Resolution.Minute
        self.AddUniverse(self.CoarseFilter)
        self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Cash)
        self.previous_day_data = {}
        self.SetWarmUp(2, Resolution.Daily)
        self.previousBar = None
        self.filtered_symbols = set()
        self.patterns = {}
        self.engulfingNOW = set()
        self.consolidatorToSymbol = {}


    def CoarseFilter(self, coarse):
        CoarseFilterResult = sorted(
            [x for x in coarse if x.Price < 30 and x.MarketCap < 1.5e9], 
            key=lambda x: x.DollarVolume, 
            reverse=True)[:50]
        return [x.Symbol for x in CoarseFilterResult]




    def OnSecuritiesChanged(self, changes):
        for security in changes.AddedSecurities:
            symbol = security.Symbol
           

            if symbol not in self.patterns:
                engulfing = Engulfing() # create new instance of the method
                self.patterns[symbol] = engulfing # if pattern occurs, add to class definition 
                consolidator = QuoteBarConsolidator(1)
                consolidator.DataConsolidated += self.consolidation_handler
                self.consolidatorToSymbol[consolidator] = symbol
                self.SubscriptionManager.AddConsolidator(symbol, consolidator)
                self.RegisterIndicator(symbol, engulfing, consolidator)

        # stocks are added if there was an engulfing pattern present at all




    def consolidation_handler(self, sender, consolidated):
        symbol = self.consolidatorToSymbol.get(sender, None)
        pattern_value = self.patterns[symbol].Current.Value
        
        if self.patterns[symbol].IsReady:  
            if self.patterns[symbol].Current.Value != 0:
                self.engulfingNOW.add(symbol)
                self.Log(f"{symbol} Engulfing value: {pattern_value}")





    def OnData(self, data):
        for symbol in self.engulfingNOW:
            if symbol in data and data[symbol] is not None:                 
                history_daily = self.History(symbol, 15, Resolution.Daily)
                history_minute = self.History(symbol, 2, Resolution.Minute)
                if not history_daily.empty and 'volume' in history_daily.columns and \
                   not history_minute.empty and 'close' in history_minute.columns:
                    volume_ratio = history_daily['volume'].iloc[-1] / history_daily['volume'].iloc[-2]
                    percent_change = (history_minute['close'].iloc[-1] - history_minute['close'].iloc[-2]) / history_minute['close'].iloc[-2] * 100
                    
                    # Execute trade logic based on volume and price change criteria
                    if volume_ratio >= 5 and percent_change >= 20:
                        self.filtered_symbols.add(symbol)
        for symbol in self.filtered_symbols:
            self.TradeLogic(symbol)






    def TradeLogic(self, symbol):
        if not self.Portfolio[symbol].Invested:
            self.SetHoldings(symbol, 0.1)
            self.Log(f"Buying {symbol.Value} based on conditions.")
        else:
            self.Log(f"Already invested in {symbol.Value}, skipping.")
                
        holding = self.Portfolio[symbol]
        if holding.Invested:
            current_price = self.Securities[symbol].Price
            stop_loss_price = holding.AveragePrice * 0.95
            trailing_stop_price = holding.AveragePrice * 0.9

        if current_price < stop_loss_price or current_price < trailing_stop_price:
            self.Liquidate(symbol)
            self.Debug(f"Liquidated {symbol.Value} due to stop loss or trailing stop criteria.")