in the code below my data is in: datetime(index of the table) symbol 	open 	high 	low 	close 	volume
rewrite the code 
import pandas as pd
import numpy as np
from math import ceil, pow
from datetime import datetime

# -------------------------
# Helper Functions
# -------------------------

def round_up(number, decimals):
    """
    Mimics the RoundUp function from Pine Script.
    Rounds up a number to a specified number of decimal places.
    """
    factor = pow(10, decimals)
    return ceil(number * factor) / factor

def calc_rr(entry_price, sl_price, take_price):
    """
    Calculates the Risk-Reward ratio.
    """
    if entry_price > sl_price:
        return (take_price - entry_price) / (entry_price - sl_price)
    else:
        return (entry_price - take_price) / (sl_price - entry_price)

def create_trend_line(highs, lows, sensitivity, fib):
    """
    Generates a trend line based on the highest and lowest prices over a given sensitivity and Fibonacci level.
    """
    high_line = highs.rolling(window=int(sensitivity), min_periods=1).max()
    low_line = lows.rolling(window=int(sensitivity), min_periods=1).min()
    channel_range = high_line - low_line
    return high_line - channel_range * fib

# -------------------------
# Data Classes
# -------------------------

class StrategySettings:
    def __init__(self, sensitivity=0, risk_percent=1, break_even_target="1",
                 tp1_percent=0, tp1_percent_fix=0, tp2_percent=0, tp2_percent_fix=0,
                 tp3_percent=0, tp3_percent_fix=0, tp4_percent=0, tp4_percent_fix=0,
                 fixed_stop=False, sl_percent=0.0):
        self.sensitivity = sensitivity
        self.risk_percent = risk_percent
        self.break_even_target = break_even_target
        self.tp1_percent = tp1_percent
        self.tp1_percent_fix = tp1_percent_fix
        self.tp2_percent = tp2_percent
        self.tp2_percent_fix = tp2_percent_fix
        self.tp3_percent = tp3_percent
        self.tp3_percent_fix = tp3_percent_fix
        self.tp4_percent = tp4_percent
        self.tp4_percent_fix = tp4_percent_fix
        self.fixed_stop = fixed_stop
        self.sl_percent = sl_percent

class Trade:
    def __init__(self, side, entry_price, sl_price, tp_prices, tp_percent_fix, risk_percent):
        self.start_bar_index = 0
        self.side = side  # "LONG" or "SHORT"
        self.market_order_comission = 0.0  # Placeholder
        self.limit_order_comission = 0.0   # Placeholder
        self.entry_price = entry_price
        self.entry_hit = False
        self.sl_price = sl_price
        self.tp_prices = tp_prices  # Dictionary: {'TP1': price, 'TP2': price, ...}
        self.tp_percent_fix = tp_percent_fix  # Dictionary: {'TP1': fix_percent, ...}
        self.break_even_price = 0.0
        self.sl_hit = False
        self.tp_hit = {tp: False for tp in tp_prices}  # e.g., {'TP1': False, 'TP2': False, ...}
        self.position_size_left = 100.0
        self.risk_percent = risk_percent
        self.is_closed = False
        self.close_price = 0.0
        self.can_break_even = False
        self.force_closed = False
        self.profit = 0.0
        self.risk_reward = 0.0

    def update_profit(self, rr, percent_fix):
        self.profit += rr * percent_fix / 100 * self.risk_percent

# -------------------------
# Strategy Selector
# -------------------------

def selector(strategy_name):
    """
    Selects and returns StrategySettings based on the strategy name.
    """
    if strategy_name == "MANUAL":
        return StrategySettings(
            sensitivity=18,
            risk_percent=1,
            break_even_target="1",
            tp1_percent=1,
            tp1_percent_fix=40,
            tp2_percent=2,
            tp2_percent_fix=30,
            tp3_percent=3,
            tp3_percent_fix=20,
            tp4_percent=4,
            tp4_percent_fix=10,
            fixed_stop=False,
            sl_percent=0.0
        )
    elif strategy_name == "UNIVERSAL 15m":
        return StrategySettings(
            sensitivity=20,
            risk_percent=1,
            break_even_target="1",
            tp1_percent=1,
            tp1_percent_fix=40,
            tp2_percent=2,
            tp2_percent_fix=30,
            tp3_percent=3,
            tp3_percent_fix=20,
            tp4_percent=4,
            tp4_percent_fix=10,
            fixed_stop=False,
            sl_percent=0.0
        )
    elif strategy_name == "SOL 5m":
        return StrategySettings(
            sensitivity=20,
            risk_percent=1,
            break_even_target="1",
            tp1_percent=1,
            tp1_percent_fix=40,
            tp2_percent=2,
            tp2_percent_fix=30,
            tp3_percent=3,
            tp3_percent_fix=20,
            tp4_percent=4,
            tp4_percent_fix=10,
            fixed_stop=False,
            sl_percent=0.0
        )
    else:
        # Default settings or raise an error
        return StrategySettings()

# -------------------------
# Main Strategy Class
# -------------------------

class TradingStrategy:
    def __init__(self, data, strategy_name="MANUAL", start_date=datetime.min, initial_deposit=1000):
        """
        Initializes the trading strategy.

        :param data: pandas DataFrame with columns ['Open', 'High', 'Low', 'Close', 'Volume']
        :param strategy_name: Name of the strategy to use
        :param start_date: datetime object representing when to start the strategy
        :param initial_deposit: Starting deposit amount
        """
        self.data = data.copy().reset_index(drop=True)
        self.start_date = start_date
        self.initial_deposit = initial_deposit
        self.deposit = initial_deposit

        # Initialize performance metrics
        self.total_profit = 0.0
        self.trade_count = 0
        self.profit_trades = 0
        self.loss_trades = 0
        self.win_streak = 0
        self.loss_streak = 0
        self.current_win_streak = 0
        self.current_loss_streak = 0
        self.first_trade_date = None

        # Initialize strategy settings
        self.strategy_settings = selector(strategy_name)
        self.apply_strategy_settings()

        # Initialize trade information
        self.trade = None

        # Prepare trend lines
        self.prepare_trend_lines()

    def apply_strategy_settings(self):
        """
        Applies the strategy settings by adjusting sensitivity, take profit percentages, and stop loss.
        """
        s = self.strategy_settings
        s.sensitivity *= 10
        s.tp1_percent /= 100
        s.tp2_percent /= 100
        s.tp3_percent /= 100
        s.tp4_percent /= 100
        s.tp1_percent_fix /= 100
        s.tp2_percent_fix /= 100
        s.tp3_percent_fix /= 100
        s.tp4_percent_fix /= 100
        s.sl_percent /= 100

    def prepare_trend_lines(self):
        """
        Calculates trend lines based on sensitivity and Fibonacci levels.
        """
        s = self.strategy_settings
        self.data['high_line'] = create_trend_line(self.data['High'], self.data['Low'], s.sensitivity, 0.5)  # Fib 0.5
        self.data['fib_236'] = create_trend_line(self.data['High'], self.data['Low'], s.sensitivity, 0.236)
        self.data['fib_382'] = create_trend_line(self.data['High'], self.data['Low'], s.sensitivity, 0.382)
        self.data['fib_618'] = create_trend_line(self.data['High'], self.data['Low'], s.sensitivity, 0.618)
        self.data['fib_786'] = create_trend_line(self.data['High'], self.data['Low'], s.sensitivity, 0.786)
        self.data['imba_trend_line'] = self.data['high_line'] - (self.data['high_line'] - self.data['low_line']) * 0.5

    def can_long_short(self, index):
        """
        Determines if a long or short position can be initiated at the given index.

        :param index: Current index in the DataFrame
        :return: Tuple (can_long, can_short)
        """
        current_close = self.data.at[index, 'Close']
        imba_trend_line = self.data.at[index, 'imba_trend_line']
        fib_236 = self.data.at[index, 'fib_236']
        fib_786 = self.data.at[index, 'fib_786']

        can_long = (current_close >= imba_trend_line) and (current_close >= fib_236) and not getattr(self, 'is_long_trend', False)
        can_short = (current_close <= imba_trend_line) and (current_close <= fib_786) and not getattr(self, 'is_short_trend', False)

        return can_long, can_short

    def run_strategy(self):
        """
        Executes the trading strategy over the dataset.
        """
        for index, row in self.data.iterrows():
            current_time = row['Date'] if 'Date' in row else None  # Assuming 'Date' column exists

            # Check if the current time is after the start date
            if current_time and current_time < self.start_date:
                continue  # Skip until start date is reached

            if self.trade and not self.trade.is_closed:
                self.manage_trade(index, row)
            else:
                can_long, can_short = self.can_long_short(index)
                if can_long or can_short:
                    self.enter_trade(index, row, "LONG" if can_long else "SHORT")

    def enter_trade(self, index, row, side):
        """
        Enters a new trade based on the side (LONG or SHORT).

        :param index: Current index in the DataFrame
        :param row: Current row data
        :param side: "LONG" or "SHORT"
        """
        entry_price = row['Close']
        s = self.strategy_settings

        if side == "LONG":
            if s.fixed_stop:
                sl_price = round_up(entry_price * (1 - s.sl_percent), 2)
            else:
                sl_price = round_up(row['fib_786'] * (1 - s.sl_percent), 2)
            tp_prices = {
                'TP1': round_up(entry_price * (1 + s.tp1_percent), 2),
                'TP2': round_up(entry_price * (1 + s.tp2_percent), 2),
                'TP3': round_up(entry_price * (1 + s.tp3_percent), 2),
                'TP4': round_up(entry_price * (1 + s.tp4_percent), 2)
            }
            break_even_price = self.get_break_even_price(s.break_even_target, tp_prices)
        else:  # SHORT
            if s.fixed_stop:
                sl_price = round_up(entry_price * (1 + s.sl_percent), 2)
            else:
                sl_price = round_up(row['fib_236'] * (1 + s.sl_percent), 2)
            tp_prices = {
                'TP1': round_up(entry_price * (1 - s.tp1_percent), 2),
                'TP2': round_up(entry_price * (1 - s.tp2_percent), 2),
                'TP3': round_up(entry_price * (1 - s.tp3_percent), 2),
                'TP4': round_up(entry_price * (1 - s.tp4_percent), 2)
            }
            break_even_price = self.get_break_even_price(s.break_even_target, tp_prices)

        # Initialize a new trade
        self.trade = Trade(
            side=side,
            entry_price=entry_price,
            sl_price=sl_price,
            tp_prices=tp_prices,
            tp_percent_fix={
                'TP1': s.tp1_percent_fix,
                'TP2': s.tp2_percent_fix,
                'TP3': s.tp3_percent_fix,
                'TP4': s.tp4_percent_fix
            },
            risk_percent=s.risk_percent
        )
        self.trade.break_even_price = break_even_price
        self.trade.start_bar_index = index

        # Set the first trade date if it's the first trade
        if self.trade_count == 0:
            self.first_trade_date = row['Date'] if 'Date' in row else None

    def get_break_even_price(self, target, tp_prices):
        """
        Determines the break-even price based on the target.

        :param target: Break-even target as a string ("1", "2", "3", "WITHOUT")
        :param tp_prices: Dictionary of take-profit prices
        :return: Break-even price
        """
        if target == "1":
            return tp_prices['TP1']
        elif target == "2":
            return tp_prices['TP2']
        elif target == "3":
            return tp_prices['TP3']
        elif target == "WITHOUT":
            return tp_prices['TP4']
        else:
            return tp_prices['TP1']  # Default fallback

    def manage_trade(self, index, row):
        """
        Manages an open trade by checking take-profit and stop-loss conditions.

        :param index: Current index in the DataFrame
        :param row: Current row data
        """
        if not self.trade:
            return  # No active trade to manage

        trade = self.trade
        s = self.strategy_settings
        current_high = row['High']
        current_low = row['Low']
        current_close = row['Close']
        open_price = row['Open']

        if trade.side == "LONG":
            # Check if entry is hit (already true when trade is created)
            # Check each TP
            for tp in ['TP1', 'TP2', 'TP3', 'TP4']:
                if not trade.tp_hit[tp] and current_high >= trade.tp_prices[tp]:
                    trade.tp_hit[tp] = True
                    rr = calc_rr(trade.entry_price, trade.sl_price, trade.tp_prices[tp])
                    trade.update_profit(rr, trade.tp_percent_fix[tp] * 100)
                    self.deposit += (rr * trade.tp_percent_fix[tp] / 100) * self.deposit

            # Check for break-even
            if current_high >= trade.break_even_price and not trade.can_break_even:
                trade.can_break_even = True

            # Break-even logic
            if trade.can_break_even:
                if current_low <= trade.entry_price and current_close < open_price and index != trade.start_bar_index:
                    trade.is_closed = True
                    trade.close_price = trade.entry_price
                    trade.profit += 0  # No profit added for break-even hit

            # Check stop-loss
            if current_low <= trade.sl_price and not trade.can_break_even and index != trade.start_bar_index:
                trade.sl_hit = True
                trade.is_closed = True
                trade.profit += -s.risk_percent * trade.position_size_left / 100
                self.deposit += (trade.profit / 100) * self.deposit

        else:  # SHORT
            # Check if entry is hit (already true when trade is created)
            # Check each TP
            for tp in ['TP1', 'TP2', 'TP3', 'TP4']:
                if not trade.tp_hit[tp] and current_low <= trade.tp_prices[tp]:
                    trade.tp_hit[tp] = True
                    rr = calc_rr(trade.entry_price, trade.sl_price, trade.tp_prices[tp])
                    trade.update_profit(rr, trade.tp_percent_fix[tp] * 100)
                    self.deposit += (rr * trade.tp_percent_fix[tp] / 100) * self.deposit

            # Check for break-even
            if current_low <= trade.break_even_price and not trade.can_break_even:
                trade.can_break_even = True

            # Break-even logic
            if trade.can_break_even:
                if current_high >= trade.entry_price and current_close > open_price and index != trade.start_bar_index:
                    trade.is_closed = True
                    trade.close_price = trade.entry_price
                    trade.profit += 0  # No profit added for break-even hit

            # Check stop-loss
            if current_high >= trade.sl_price and not trade.can_break_even and index != trade.start_bar_index:
                trade.sl_hit = True
                trade.is_closed = True
                trade.profit += -s.risk_percent * trade.position_size_left / 100
                self.deposit += (trade.profit / 100) * self.deposit

        # Update trade status
        if trade.is_closed:
            self.update_performance(trade)
            self.trade = None  # Reset trade

    def update_performance(self, trade):
        """
        Updates performance metrics based on the closed trade.

        :param trade: Trade object that has been closed
        """
        self.trade_count += 1
        self.total_profit += trade.profit

        if trade.profit >= 0:
            self.profit_trades += 1
            self.current_win_streak += 1
            self.current_loss_streak = 0
            self.win_streak = max(self.win_streak, self.current_win_streak)
        else:
            self.loss_trades += 1
            self.current_loss_streak += 1
            self.current_win_streak = 0
            self.loss_streak = max(self.loss_streak, self.current_loss_streak)

    def get_performance(self):
        """
        Returns a dictionary of performance metrics.

        :return: Dictionary containing performance metrics
        """
        win_rate = (self.profit_trades / self.trade_count * 100) if self.trade_count > 0 else 0.0
        return {
            'Total Trades': self.trade_count,
            'Profit Trades': self.profit_trades,
            'Loss Trades': self.loss_trades,
            'Win Rate (%)': round(win_rate, 2),
            'Total Profit (%)': round(self.total_profit, 2),
            'Current Deposit': round(self.deposit, 2),
            'Win Streak': self.win_streak,
            'Loss Streak': self.loss_streak
        }

# -------------------------
# Usage Example
# -------------------------

if __name__ == "__main__":
    # Example: Load your data into a pandas DataFrame
    # The DataFrame should have columns: ['Date', 'Open', 'High', 'Low', 'Close', 'Volume']
    # Here, we'll create a sample DataFrame for demonstration purposes

    np.random.seed(42)  # For reproducible results

    dates = pd.date_range(start='2023-01-01', periods=100, freq='D')
    price = 100
    data = []
    for date in dates:
        open_price = price + np.random.uniform(-1, 1)
        high_price = open_price + np.random.uniform(0, 2)
        low_price = open_price - np.random.uniform(0, 2)
        close_price = low_price + np.random.uniform(0, high_price - low_price)
        volume = np.random.randint(1000, 10000)
        data.append([date, open_price, high_price, low_price, close_price, volume])
        price = close_price  # Update price for the next day

    df = pd.DataFrame(data, columns=['Date', 'Open', 'High', 'Low', 'Close', 'Volume'])

    # Initialize the strategy
    strategy = TradingStrategy(
        data=df,
        strategy_name="MANUAL",  # Change as needed: "MANUAL", "UNIVERSAL 15m", "SOL 5m", etc.
        start_date=datetime(2023, 6, 1),
        initial_deposit=1000
    )

    # Run the strategy
    strategy.run_strategy()

    # Get performance metrics
    performance = strategy.get_performance()
    print("Performance Metrics:")
    for key, value in performance.items():
        print(f"{key}: {value}")