h2: .05
Enter the value for h3: 3
Enter the value for threshold: 3
Enter the value for sl: 1
Enter the value for tp: 1
Data fetched for QQQ
C:\Users\atom\AppData\Local\Programs\Python\Python39\lib\site-packages\backtesting\backtesting.py:1054: FutureWarning: Index.is_numeric is deprecated. Use pandas.api.types.is_any_real_numeric_dtype instead
  (data.index.is_numeric() and
e:\quant work\naseer\phase3\script.py:652: UserWarning: Data index is not sorted in ascending order. Sorting.
  bt = Backtest(input_data_1min, MyStrategy1, cash=10000)
e:\quant work\naseer\phase3\script.py:652: UserWarning: Data index is not datetime. Assuming simple periods, but `pd.DateTimeIndex` is advised.
  bt = Backtest(input_data_1min, MyStrategy1, cash=10000)
Data fetched for QQQ
Data fetched and aggregated for QQQ
Data fetched for QQQ
                    date       Open       High        Low      Close  volume
0    2024-09-12 14:32:00  473.16000  473.51999  473.16000  473.42999   72225
1    2024-09-12 14:34:00  473.40009  473.82001  473.39999  473.79999   65642
2    2024-09-12 14:36:00  473.78000  474.04001  473.78000  473.87000  160376
3    2024-09-12 14:38:00  473.85001  473.95001  473.72000  473.82999  100377
4    2024-09-12 14:40:00  473.84000  473.92001  473.78000  473.80820   69760
                 ...        ...        ...        ...        ...     ...
2498 2024-10-01 13:18:00  478.26000  478.37000  478.16000  478.19000    1664
2499 2024-10-01 13:20:00  478.34000  478.70000  478.33500  478.62000    1791
2500 2024-10-01 13:22:00  478.37000  478.38000  478.27000  478.38000     753
2501 2024-10-01 13:24:00  478.23500  478.44000  478.11000  478.27000    5611
2502 2024-10-01 13:26:00  478.30000  478.48000  478.29000  478.34000    3973

[2503 rows x 6 columns]
data_feeder_2min.df
Traceback (most recent call last):

  File ~\AppData\Local\Programs\Python\Python39\lib\site-packages\spyder_kernels\py3compat.py:356 in compat_exec
    exec(code, globals, locals)

  File e:\quant work\naseer\phase3\script.py:653
    stats = bt.run()

  File ~\AppData\Local\Programs\Python\Python39\lib\site-packages\backtesting\backtesting.py:1139 in run
    strategy.init()

  File e:\quant work\naseer\phase3\script.py:580 in init
    self.signals_buy = self.I(lambda: buy_signals)

  File ~\AppData\Local\Programs\Python\Python39\lib\site-packages\backtesting\backtesting.py:143 in I
    raise ValueError(

ValueError: Indicators must return (optionally a tuple of) numpy.arrays of same length as `data` (data shape: (2501,); indicator "λ"shape: (2503,), returned value: [False False False ... False False False]) 
import pandas as pd
import numpy as np
from twelvedata import TDClient

from backtesting import Backtest, Strategy
# Global variables
d1v = 0.2
d2v = 0.2
d3v = 0.2

# Oscillator values for SSG strategy optimization
osc1_sellv = 100
osc2_sellv = 80

osc1_buyv = 100
osc2_buyv = 80

# Parameters for the HPAT strategy
h1v = 6
h2v = 0.05
h3v = 4
thresholdv = 2

# Take input from the user for the global variables
d1v = float(input("Enter the value for d1: "))
d2v = float(input("Enter the value for d2: "))
d3v = float(input("Enter the value for d3: "))

osc1_sellv = int(input("Enter the value for osc1_sell: "))
osc2_sellv = int(input("Enter the value for osc2_sell: "))

osc1_buyv = int(input("Enter the value for osc1_buy: "))
osc2_buyv = int(input("Enter the value for osc2_buy: "))

h1v = int(input("Enter the value for h1: "))
h2v = float(input("Enter the value for h2: "))
h3v = int(input("Enter the value for h3: "))
thresholdv = int(input("Enter the value for threshold: "))

slv = float(input("Enter the value for sl: "))
tpv = float(input("Enter the value for tp: "))


class DataFeeder:
    def __init__(self, ticker, api_key, timeframe):
        self.ticker = ticker
        self.api_key = api_key
        self.timeframe = timeframe
        self.td = TDClient(apikey=self.api_key)
        try:
            self.df = self.fetch_ticker()
            print(f"Data fetched for {self.ticker}")
        except Exception as e:
            print("nope", e)

    def fetch_ticker(self):
        ts = self.td.time_series(
            symbol=self.ticker,
            interval=self.timeframe,
            outputsize=2501,
            timezone="America/New_York",
        )
        df = ts.as_pandas()
        df = df.reset_index()
        df.rename(columns={'datetime': 'date',
                           'open' : 'Open' ,
                           'close' : 'Close',
                           'high' : 'High' , 
                           'low' : 'Low'
                           }, inplace=True)
        
        # Sort the DataFrame by date in ascending order
        df['date'] = pd.to_datetime(df['date'])  # Ensure date column is in datetime format
        df.sort_values(by='date', inplace=True)  # Sort by date
        
        return df
    


class DataFeeder2:
    def __init__(self, ticker, api_key, timeframe='2min'):
        if timeframe != '2min':
            raise ValueError("This class only supports a 2-minute timeframe.")
        
        self.ticker = ticker
        self.api_key = api_key
        self.timeframe = '1min'  # Use 1-minute intervals to fetch data
        self.td = TDClient(apikey=self.api_key)
        
        try:
            self.df = self.fetch_and_aggregate_data()
            print(f"Data fetched and aggregated for {self.ticker}")
        except Exception as e:
            print("Data fetching failed:", e)

    def fetch_and_aggregate_data(self):
        # Fetch 1-minute interval data
        ts = self.td.time_series(
            symbol=self.ticker,
            interval=self.timeframe,
            outputsize=5000,
            timezone="America/New_York",
        )
        df = ts.as_pandas().reset_index()
        df.rename(columns={'datetime': 'date'}, inplace=True)
        
        # Aggregate the data into 2-minute intervals
        df['date'] = pd.to_datetime(df['date'])
        df.set_index('date', inplace=True)
        df_agg = df.resample('2T').agg({
            'open': 'first',
            'high': 'max',
            'low': 'min',
            'close': 'last',
            'volume': 'sum'
        }).dropna().reset_index()
        df_agg.rename(columns={'datetime': 'date',
                           'open' : 'Open' ,
                           'close' : 'Close',
                           'high' : 'High' , 
                           'low' : 'Low'
                           }, inplace=True)

        return df_agg
class Indicators:
    def __init__(self, df):
        self.df = df

    def calculate_sma(self, periods):
        for period in periods:
            self.df[f'SMA_{period}'] = self.df['Close'].astype(float).rolling(window=period).mean()
            self.df[f'SMA_{period}'].fillna(method='bfill', inplace=True)

    def calculate_stochastic(self, periodK=12, smoothK=3, periodD=1, periodD1=4):
        # Calculate lowest low and highest high over periodK
        self.df['lowest_low'] = self.df['Low'].rolling(window=periodK).min()
        self.df['highest_high'] = self.df['High'].rolling(window=periodK).max()
        
        # Calculate %K
        self.df['%K'] = 100 * (self.df['Close'] - self.df['lowest_low']) / (self.df['highest_high'] - self.df['lowest_low'])
        
        # Smooth %K with an SMA over smoothK
        self.df['%K_smooth'] = self.df['%K'].rolling(window=smoothK).mean()
        
        # Calculate %D as the SMA of %K_smooth over periodD
        self.df['%D'] = self.df['%K_smooth'].rolling(window=periodD).mean()
        
        # Calculate %D1 as the SMA of %K_smooth over periodD1
        self.df['%D1'] = self.df['%K_smooth'].rolling(window=periodD1).mean()
        
        # Calculate Double Slow K Denominator (highest - lowest over periodK)
        self.df['DoubleSlowKDen'] = self.df['%K_smooth'].rolling(window=periodK).apply(lambda x: x.max() - x.min(), raw=True)
        
        # Calculate Double Slow D Denominator (highest - lowest over periodK)
        self.df['DoubleSlowDDen'] = self.df['%D'].rolling(window=periodK).apply(lambda x: x.max() - x.min(), raw=True)
        
        # Calculate Double Slow K
        self.df['DoubleSlowK'] = 100 * (self.df['%K_smooth'] - self.df['%K_smooth'].rolling(window=periodK).min()) / self.df['DoubleSlowKDen']
        
        # Calculate Double Slow D
        self.df['%FastD'] = self.df['%D'] 
        
        self.df['DoubleSlowD'] = 100 * (self.df['%D'] - self.df['%D'].rolling(window=periodK).min()) / self.df['DoubleSlowDDen']
        self.df.fillna(method='bfill', inplace=True) 
       
        



    
    
class indchecks(Indicators):
    def __init__(self , df):
        super().__init__(df)
        self.calculate_sma([21, 50, 200])
        self.calculate_stochastic()
        
    def fastdisgreater(self , lvl , i):
        if self.df['%FastD'][i] > lvl:
            return True
        else:
            return False
    def fastdislesser(self , lvl, i):
        if self.df['%FastD'][i] < lvl:
            return True
        else:
            return False
    def doublekislesser(self , lvl, i):
        if self.df['DoubleSlowK'][i] < lvl:
            return True
        else:
            return False
    def doublekisgreater(self , lvl, i):
        if self.df['DoubleSlowK'][i] > lvl:
            return True
        else:
            return False
        
    def fastdisincreasing(self , lookback , current):
        if self.df['%FastD'][lookback]  <  self.df['%FastD'][current]:
            return True
        else:
            return False
    def fastdisdecreasing(self , lookback , current):
        if self.df['%FastD'][lookback]  >  self.df['%FastD'][current]:
            return True
        else:
            return False
    def doublekisdecreasing(self , lookback , current):
        if self.df['DoubleSlowK'][lookback]  >  self.df['DoubleSlowK'][current]:
            return True
        else:
            return False
    def doublekisincreasing(self , lookback , current):
        if self.df['DoubleSlowK'][lookback]  <  self.df['DoubleSlowK'][current]:
            return True
        else:
            return False
        
        
class MAB(indchecks):
    def __init__(self, df , val1 = 0.2 ,val2 = 0.2 , val3=0.2):
        super().__init__(df) 
        self.bearishBounce1 = pd.DataFrame(index=self.df.index)
        self.bearishBounce2 = pd.DataFrame(index=self.df.index)
        self.bearishBounce3 = pd.DataFrame(index=self.df.index)
        self.bullishBounce1 = pd.DataFrame(index=self.df.index)
        self.bullishBounce2 = pd.DataFrame(index=self.df.index)
        self.bullishBounce3 = pd.DataFrame(index=self.df.index)
        self.dis1 = val1
        self.dis2 = val2
        self.dis3 = val3
                
    def MABrun(self) :
       
       
        
        for i in range( 1 , len(self.df)-1):
            self.bearishBounce1.loc[ i , 'bearishBounce1'] = (self.df['Open'][i] <= self.df['Close'][i]) and (self.df['Close'][i]<=  self.df['SMA_21'][i]) and (self.df['High'][i] >= (self.df['SMA_21'][i] - self.dis1)) and (self.df['Close'][i] <= self.df['SMA_21'][i]) and (self.df['High'][i-1] >= (self.df['SMA_21'][i] - self.dis1))and (self.df['High'][i-1] <= self.df['SMA_21'][i]) and (self.df['High'][i] <= self.df['SMA_21'][i])
            self.bullishBounce1.loc[ i , 'bullishBounce1'] = (self.df['Open'][i] >= self.df['Close'][i]) and (self.df['Close'][i] >= self.df['SMA_21'][i]) and (self.df['Low'][i] <= (self.df['SMA_21'][i] + self.dis1)) and (self.df['Close'][i] >= self.df['SMA_21'][i]) and (self.df['Low'][i-1] <= (self.df['SMA_21'][i] + self.dis1)) and (self.df['Low'][i-1] >= self.df['SMA_21'][i]) and (self.df['Low'][i] >= self.df['SMA_21'][i])
            
            
            self.bearishBounce2.loc[ i , 'bearishBounce2'] = (self.df['Open'][i] <= self.df['Close'][i]) and (self.df['Close'][i] <=  self.df['SMA_50'][i]) and (self.df['High'][i] >= (self.df['SMA_50'][i] - self.dis2)) and (self.df['Close'][i] <= self.df['SMA_50'][i]) and (self.df['High'][i-1] >= (self.df['SMA_50'][i] - self.dis2))and (self.df['High'][i-1] <= self.df['SMA_50'][i]) and (self.df['High'][i] <= self.df['SMA_50'][i])
            self.bullishBounce2.loc[ i , 'bullishBounce2'] = (self.df['Open'][i] >= self.df['Close'][i]) and (self.df['Close'][i] >= self.df['SMA_50'][i]) and (self.df['Low'][i] <= (self.df['SMA_50'][i] + self.dis2)) and (self.df['Close'][i] >= self.df['SMA_50'][i] )and (self.df['Low'][i-1] <= (self.df['SMA_50'][i] + self.dis2))and (self.df['Low'][i-1] >= self.df['SMA_50'][i]) and (self.df['Low'][i] >= self.df['SMA_50'][i])
            
            
            self.bearishBounce3.loc[ i , 'bearishBounce3'] = (self.df['Open'][i] <= self.df['Close'][i]) and (self.df['Close'][i] <=  self.df['SMA_200'][i]) and (self.df['High'][i] >= (self.df['SMA_200'][i] - self.dis3)) and (self.df['Close'][i] <= self.df['SMA_200'][i]) and (self.df['High'][i-1] >= (self.df['SMA_200'][i] - self.dis3))and (self.df['High'][i-1] <= self.df['SMA_200'][i]) and (self.df['High'][i] <= self.df['SMA_200'][i])
            self.bullishBounce3.loc[ i , 'bullishBounce3'] = (self.df['Open'][i] >= self.df['Close'][i]) and (self.df['Close'][i] >= self.df['SMA_200'][i]) and (self.df['Low'][i] <= (self.df['SMA_200'][i] + self.dis3)) and (self.df['Close'][i] >= self.df['SMA_200'][i] )and (self.df['Low'][i-1] <= (self.df['SMA_200'][i] + self.dis3))and (self.df['Low'][i-1] >= self.df['SMA_200'][i]) and (self.df['Low'][i] >= self.df['SMA_200'][i])
            
            
            
      
    
    def run(self):
        self.MABrun()
        self.df['MAB'] = 0 
        for i  in range( 3 , len(self.df)-1 ):
            
            if (self.fastdisgreater(80, i ) or self.doublekisgreater(80, i ) 
            and (self.fastdisdecreasing(i-2 , i) or self.doublekisdecreasing(i-2 , i) ) 
            and  self.bearishBounce1.loc[ i , 'bearishBounce1'] == True  or self.bearishBounce2.loc[ i , 'bearishBounce2'] == True or self.bearishBounce3.loc[ i , 'bearishBounce3'] == True) :
                
                self.df.loc[i, 'MAB'] = -1 
                
                #short signal
            if (self.fastdislesser(20, i ) or self.doublekislesser(20, i )
            and (self.fastdisincreasing(i-2 , i) or self.doublekisincreasing(i-2 , i) )
            and self.bullishBounce1.loc[ i , 'bullishBounce1'] == True or  self.bullishBounce2.loc[ i , 'bullishBounce2'] == True  or  self.bullishBounce3.loc[ i , 'bullishBounce3'] == True ):
                
                self.df.loc[i , 'MAB' ] = 1 
                #long signal
                
        
 
    
 
    
 
    
 
    
 
    
 
    
class SSG(indchecks):
    def __init__(self, df , l1 ,l2,l1l, l2l):
        super().__init__(df) 
        self.l1  =l1
        self.l2 = l2
        self.l1l = l1l
        self.l2l = l2l
    
    def run(self):
        self.df['SSG'] = 0 
        strategy_signals = pd.DataFrame(index=self.df.index)
        strategy_signals['SSG_Signal'] = 0  

        for i in range(3, len(self.df)-1):
            # doublek top out , stay there and fast d is < l1
            #levels check
            if self.df['DoubleSlowK'][i] ==  self.l2 and self.df['DoubleSlowK'][i-1] ==  self.l2 and  self.df['%FastD'][i] <  self.l1 : 
                  #fasd increasing and then reverse direction(this is first aprt)
                  if self.df['%FastD'][i] < self.df['%FastD'][i-1] and  ( self.df['%FastD'][i-1] > self.df['%FastD'][i-2]  ):
                      self.df.loc[i,'SSG' ] = -1  
           
            
            if self.df['DoubleSlowK'][i] ==  self.l2l and self.df['DoubleSlowK'][i-1] ==  self.l2 and  self.df['%FastD'][i] > self.l1l : 
                  #fasd increasing and then reverse direction(this is first aprt)
                  if self.df['%FastD'][i] > self.df['%FastD'][i-1] and  ( self.df['%FastD'][i-1] < self.df['%FastD'][i-2] ):
                      self.df.loc[i,'SSG' ]  = 1  
                

        
        
        
        
        
        
        
        
class HPAT(indchecks):
    def __init__(self, df , window = 6 , thresholdval = 0.05 , window2 = 4):
        super().__init__(df) 
        self.window_double  = window
        self.threshold = thresholdval
        self.window_leg = window2
        
    def detect_double_top_bottom( self):
        roll_window = self.window_double
        # Define a threshold to check for the range of pattern
        range_threshold = self.threshold
    
        # Create a rolling window for High and Low
        self.df['high_roll_max'] = self.df['High'].rolling(window= self.window_double ).max()
        self.df['low_roll_min'] = self.df['Low'].rolling(window= self.window_double ).min()
    
        # Create a boolean mask for Double Top pattern
        mask_double_top = (
            (self.df['high_roll_max'] >= self.df['High'].shift(1)) &
            (self.df['high_roll_max'] >= self.df['High'].shift(-1)) &
            (self.df['High'] < self.df['High'].shift(1)) &
            (self.df['High'] < self.df['High'].shift(-1)) &
            ((self.df['High'].shift(1) - self.df['Low'].shift(1)) <= range_threshold * (self.df['High'].shift(1) + self.df['Low'].shift(1))/2) &
            ((self.df['High'].shift(-1) - self.df['Low'].shift(-1)) <= range_threshold * (self.df['High'].shift(-1) + self.df['Low'].shift(-1))/2)
        )
    
        # Create a boolean mask for Double Bottom pattern
        mask_double_bottom = (
            (self.df['low_roll_min'] <= self.df['Low'].shift(1)) &
            (self.df['low_roll_min'] <= self.df['Low'].shift(-1)) &
            (self.df['Low'] > self.df['Low'].shift(1)) &
            (self.df['Low'] > self.df['Low'].shift(-1)) &
            ((self.df['High'].shift(1) - self.df['Low'].shift(1)) <= range_threshold * (self.df['High'].shift(1) + self.df['Low'].shift(1))/2) &
            ((self.df['High'].shift(-1) - self.df['Low'].shift(-1)) <= range_threshold * (self.df['High'].shift(-1) + self.df['Low'].shift(-1))/2)
        )
    
        # Create a new column for Double Top and Double Bottom pattern and populate it using the boolean masks
        self.df['double_pattern'] = None
        self.df.loc[mask_double_top, 'double_pattern'] = 'Double Top'
        self.df.loc[mask_double_bottom, 'double_pattern'] = 'Double Bottom'
    
        # Further detection of "H" pattern after a Double Top
        self.df['h_pattern'] = None
        self.df['inverted_h_pattern'] = None
    
        for i in range(len(self.df)-1):
            if self.df['double_pattern'].iloc[i] == 'Double Bottom':
                for j in range(self.window_leg):
                    if i - j - 1 < 0:
                        break  
                    if self.df['Low'].iloc[i - j - 1] > self.df['Low'].iloc[i - j]:
                        lastvallow = self.df['Low'].iloc[i - j ]
                        flaglow = True
                    else:
                        lastvallow = self.df['Low'].iloc[i - j ]
                        flaglow = False
                if flaglow == True and lastvallow <= self.df['Low'].iloc[i] :
                        self.df.loc[i, 'h_pattern'] = 'H Pattern'
    
    
            elif self.df['double_pattern'].iloc[i] == 'Double Top':
                for j in range(self.window_leg):
                    if i - j - 1 < 0:
                        break
                    if self.df['High'].iloc[i - j - 1] < self.df['High'].iloc[i - j]:
                        lastvalhigh = self.df['High'].iloc[i - j ]
                        flaghigh = True
                    else:
                        lastvalhigh = self.df['High'].iloc[i - j ]
                        flaghigh = False
                if flaghigh == True and lastvalhigh >= self.df['High'].iloc[i] :
                        self.df.loc[i, 'inverted_h_pattern'] = 'Inverted H Pattern'
    #left most leg (last value of the lower low )should not be lower that the right one (latest value from double top )
    
        #print(self.df[ self.df['h_pattern'] == 'H Pattern'])
        #print(self.df[ self.df['inverted_h_pattern'] == 'Inverted H Pattern'])
        return self.df
            
            
            
        
    def run(self):
        self.df['HPAT'] = 0 
        self.detect_double_top_bottom();
        for i in range(2 , len(self.df)-2) :
            
            if ( self.fastdisgreater(80, i ) or self.doublekisgreater(80, i )
            and (self.fastdisdecreasing(i-2, i) or self.doublekisdecreasing(i-2, i) )
            and self.df['inverted_h_pattern'][i] == True ):
                
            #short signal
                self.df.loc[i,'HPAT'] = -1 
            
            if ( self.fastdislesser(20, i ) or self.doublekislesser(20, i )
            and (self.fastdisincreasing(i-2, i) or self.doublekisincreasing(i-2, i) )
            and self.df['h_pattern'][i] == True ) :
                self.df.loc[i,'HPAT'] = 1 
            #long signal
        
        
        
 
class Trip5(indchecks):
    def __init__(self, df):
        super().__init__(df)
        
    def Trip5(self):
        # Create a new DataFrame to store the strategy signals
        strategy_signals = pd.DataFrame(index=self.df.index)
        strategy_signals['Trip5_Signal'] = 0  # 1 for long, -1 for short, 0 for no signal
        self.df['Trip5'] = 0
        # Iterate over the DataFrame rows
        for i in range(3, len(self.df)):
            # Factor 3: Highs and Lows Comparison
            if self.check_highs_before_pattern(i):
                if self.check_horizontal_highs(i):
                    if self.check_three_bars_highs(i):
                        if self.oscillator_condition(i, direction='short'):
                            strategy_signals['Trip5_Signal'][i] = -1 
                            self.df.loc[i,'Trip5'] = -1 
            elif self.check_lows_before_pattern(i):
                if self.check_horizontal_lows(i):
                    if self.check_three_bars_lows(i):
                        if self.oscillator_condition(i, direction='long'):
                            strategy_signals['Trip5_Signal'][i] = 1  # Long signal
                            self.df.loc[i,'Trip5'] = 1 
        return strategy_signals

    def check_highs_before_pattern(self, i):
        """
        Checks if the highs of each price bar before the pattern are higher than the previous one.
        """
        return (self.df['High'][i] > self.df['High'][i-1] or self.df['High'][i] > self.df['High'][i-2])

    def check_lows_before_pattern(self, i):
        """
        Checks if the lows of each price bar before the pattern are lower than the previous one.
        """
        return (self.df['Low'][i] < self.df['Low'][i-1] or self.df['Low'][i] < self.df['Low'][i-2])

    def check_horizontal_highs(self, i):
        """
        Checks if at least 3 price bars on the 5-minute chart have highs within $0.10 of each other.
        """
        return (abs(self.df['High'][i] - self.df['High'][i-1]) <= 0.10 and
                abs(self.df['High'][i-1] - self.df['High'][i-2]) <= 0.10 and
                abs(self.df['High'][i-2] - self.df['High'][i-3]) <= 0.10)

    def check_horizontal_lows(self, i):
        """
        Checks if at least 3 price bars on the 5-minute chart have lows within $0.10 of each other.
        """
        return (abs(self.df['Low'][i] - self.df['Low'][i-1]) <= 0.10 and
                abs(self.df['Low'][i-1] - self.df['Low'][i-2]) <= 0.10 and
                abs(self.df['Low'][i-2] - self.df['Low'][i-3]) <= 0.10)

    def check_three_bars_highs(self, i):
        """
        Checks if the first bar where the high price is not higher than the previous bar is the first of the 3 required bars.
        """
        return (self.df['High'][i-2] > self.df['High'][i-3] and
                self.df['High'][i-1] > self.df['High'][i-2] and
                self.df['High'][i] < self.df['High'][i-1])

    def check_three_bars_lows(self, i):
        """
        Checks if the first bar where the low price is not lower than the previous bar is the first of the 3 required bars.
        """
        return (self.df['Low'][i-2] < self.df['Low'][i-3] and
                self.df['Low'][i-1] < self.df['Low'][i-2] and
                self.df['Low'][i] > self.df['Low'][i-1])

    def oscillator_condition(self, i, direction):
        """
        Checks if the oscillator is >80 (short) or <20 (long)
        """
        if direction == 'short':
            return ((self.df['%FastD'][i] > 80 or self.df['%FastD'][i-1] > 80 or self.df['%FastD'][i-2] > 80)
        or (self.df['DoubleSlowK'][i] > 80 or self.df['DoubleSlowK'][i-1] > 80 or self.df['DoubleSlowK'][i-2] > 80))
        elif direction == 'long':
            return ( (self.df['%FastD'][i] < 20 or self.df['%FastD'][i-1] < 20 or self.df['%FastD'][i-2] < 20)
or (self.df['DoubleSlowK'][i] < 20 or self.df['DoubleSlowK'][i-1] < 20 or self.df['DoubleSlowK'][i-2] < 20) )
    def run(self):
        # Calculate the indicators
     

        # Apply the new strategy
        strategy_signals = self.Trip5()

        return strategy_signals


class MyStrategy1(Strategy ):
    d1 = d1v
    d2 = d2v
    d3 = d3v

    # Oscillator values for SSG strategy optimization
    osc1_sell = osc1_sellv
    osc2_sell = osc2_sellv
    
    osc1_buy = osc1_buyv
    osc2_buy = osc1_buyv
    
    # Parameters for the HPAT strategy
    h1 = h1v
    h2 = h2v
    h3 = h3v
    threshold = thresholdv

    def init(self):
       

        # Fetch and aggregate data for different timeframes
        data_feeder_1min = DataFeeder('QQQ', '64e5d79c83ed4ff49b32db1b1a60627d', '1min')
        data_feeder_2min = DataFeeder2('QQQ', '64e5d79c83ed4ff49b32db1b1a60627d')
        data_feeder_5min = DataFeeder('QQQ', '64e5d79c83ed4ff49b32db1b1a60627d', '5min')
        ind = indchecks(data_feeder_1min.df ) 
       

        # Run each strategy for each timeframe
        self.m1 = MAB(data_feeder_1min.df, self.d1, self.d2, self.d3)
        self.m1.run()
        print(data_feeder_2min.df)
        print("data_feeder_2min.df")
        self.m2 = MAB(data_feeder_2min.df, self.d1, self.d2, self.d3)
        self.m2.run()
        self.m5 = MAB(data_feeder_5min.df, self.d1, self.d2, self.d3)
        self.m5.run()

        self.s1 = SSG(data_feeder_1min.df, self.osc1_sell, self.osc2_sell, self.osc1_buy, self.osc2_buy)
        self.s1.run()
        self.s2 = SSG(data_feeder_2min.df, self.osc1_sell, self.osc2_sell, self.osc1_buy, self.osc2_buy)
        self.s2.run()
        self.s5 = SSG(data_feeder_5min.df, self.osc1_sell, self.osc2_sell, self.osc1_buy, self.osc2_buy)
        self.s5.run()

        self.h1 = HPAT(data_feeder_1min.df ,  self.h1,self.h2,self.h3)
        self.h1.run()
        self.h2 = HPAT(data_feeder_2min.df)
        self.h2.run()
        self.h5 = HPAT(data_feeder_5min.df)
        self.h5.run()
        
        self.trip5 = Trip5(data_feeder_5min.df)
        self.trip5.run()

        # Combine signals from different timeframes
        combined_signals_MAB = self.combine_signals(data_feeder_1min.df['MAB'], data_feeder_2min.df['MAB'], data_feeder_5min.df['MAB'])
        combined_signals_SSG = self.combine_signals(data_feeder_1min.df['SSG'], data_feeder_2min.df['SSG'], data_feeder_5min.df['SSG'])
        combined_signals_HPAT =self.combine_signals(data_feeder_1min.df['HPAT'], data_feeder_2min.df['HPAT'], data_feeder_5min.df['HPAT'])
        combined_signals_Trip5 =data_feeder_5min.df['Trip5']
        # Calculate buy and sell signals
        buy_signals, sell_signals = self.calculate_signals(combined_signals_MAB,combined_signals_SSG,combined_signals_HPAT,combined_signals_Trip5, self.threshold)
        

        # Combine buy and sell signals from different timeframes
        self.signals_buy = self.I(lambda: buy_signals)
        self.signals_sell = self.I(lambda: sell_signals)
        pd.set_option("display.max_rows"  , None)
        pd.set_option("display.max_columns"  , None)
        test = pd.concat([ combined_signals_MAB,  combined_signals_SSG , combined_signals_HPAT, combined_signals_Trip5 , buy_signals, sell_signals] ,axis=1)
        print(test)
        test.to_excel('signals.xlsx', index=True)

    def combine_signals(self, mab_signal, mab2_signal, mab5_signal):
        # Ensure inputs are pandas Series or DataFrames with compatible indices
        # #if isinstance(mab_signal, pd.DataFrame):
        # mab_signal_df = mab_signal.iloc[:, 0]  # Convert to Series if it's a single-column DataFrame
        # #if isinstance(mab2_signal, pd.DataFrame):
        # mab2_signal2_df = mab2_signal.iloc[:, 0]  # Convert to Series if it's a single-column DataFrame
        # #if isinstance(mab5_signal, pd.DataFrame):
        # mab5_signal5_df = mab5_signal.iloc[:, 0]  # Convert to Series if it's a single-column DataFrame
       
        # Combine the signals into a DataFrame
        combined_signal = pd.DataFrame({
            '1_Signal': mab_signal,
            '2_Signal': mab2_signal,
            '5_Signal': mab5_signal,
           
        })

        return combined_signal

    # def calculate_signals(self, combined_signals_MAB,combined_signals_SSG,combined_signals_HPAT,combined_signals_Trip5 , threshold):
    #     #combined signal contain data for 1 2 5 min singlas for each stratey, what i want is to of any of the 3 timeframe singlas is to buy or sell or atleast (threshold) number of stratgeis then genrate a nuy or sell signla
        
    #     #add logic to see if an
    #     return buy_signals, sell_signals
    
    def calculate_signals(self, combined_signals_MAB, combined_signals_SSG, combined_signals_HPAT, combined_signals_Trip5, threshold):
        # Combine all combined signals into a single DataFrame
        combined_signals = pd.concat([combined_signals_MAB, combined_signals_SSG, combined_signals_HPAT, combined_signals_Trip5], axis=1)
        
        # Initialize buy and sell signals
        buy_signals = pd.Series(index=combined_signals.index)
        sell_signals = pd.Series(index=combined_signals.index, dtype='bool')
        
        # Iterate over each row in the combined signals DataFrame
        for index, row in combined_signals.iterrows():
            # Count the number of buy and sell signals
            buy_count = sum(row == 1)
            sell_count = sum(row == -1)
            
           
            # Check if at least threshold number of strategies generate a buy or sell signal
            if buy_count >= threshold:
                buy_signals[index] = True
            else:
              buy_signals[index] = False


            if sell_count >= threshold:
                sell_signals[index] = True
            else:
                sell_signals[index] = False
        
        return buy_signals, sell_signals

    def next(self):
        # Execute trades based on the buy and sell signals
        if self.signals_buy:
            self.buy( sl = self.data.Close[-1] -slv , tp = self.data.Close[-1] +tpv)
        elif self.signals_sell:
            self.sell(sl = self.data.Close[-1] +slv , tp = self.data.Close[-1] -tpv)


data_feeder_new = DataFeeder('QQQ', '64e5d79c83ed4ff49b32db1b1a60627d', "1min")
input_data_1min = data_feeder_new.df[['Open', 'High', 'Low', 'Close']]
bt = Backtest(input_data_1min, MyStrategy1, cash=10000)
stats = bt.run()
bt.plot()
stats_df = pd.DataFrame(stats['_trades'])

# Save the DataFrame to an Excel file
stats_df.to_excel('trades.xlsx', index=False)