add this profit management to my script. dont add any gui right now just focus on the buisness logic 1. Integration with Interactive Brokers (IB) platform is essential. Do you want to use the TWS
API or the Gateway?
The App should be able to establish a connection with both, but not simultaneously. For example, I
would start with a connection with TWS, because it allows me to monitor what the App is doing.
Once I trust the App works well, I would transition to Gateway, as it is more lightweight.
2. App must facilitate basic trade entry functions (stock and futures). Does this include the
ability to view current market prices, or is the functionality solely for entering trade orders?
No need to view current market prices. The App needs market prices to establish parameters for
trade entry and management.
3. Ability to select from multiple accounts in IB. Should the app be designed to connect to a
single TWS user account, assuming that this account has multiple sub-accounts? Or should it
have the ability to connect to multiple different users?
The App needs to be able to connect to only one IB User Account, but be able to select which
Individual account to trade. For example, cash account, margin account, RSP account.
4. Use PyQt for GUI development. Is PyQt a fixed requirement for the GUI?
No, I’m open to using other tech stacks. We can discuss this in the first week. However, if we cannot
agree on an alternative, then the requirement is PyQT.
5. Order Import Methods. Will the orders only be imported through a CSV file, or do you need
the additional ability to enter orders one by one through the GUI interface?
The primary method of use will be through daily import of CSV file, but also require the ability to add
and edit through GUI.
6. Default settings that are applied to all trades. How do you want to adjust the default settings
to individual trades?
I’m open to discussing this further, but my initial vision is that after importing trades via the CSV file,
I can then click on each individual trade and make adjustments to the default settings for the
individual trade. Once I completed this, I would click a button on the App for it to connect with the
IB API and establish Order Ticket for each trade.
7. Manual adjustments. Can you describe what manual adjustments you would like to make in
the App?
For the Active Orders tab, I would like to make manual adjustments as described in Questions #5
and #6. For the Active Trades tab, I would like to make manual adjustments of Take Profit (TP), Stop
Loss (SL), full or partial exit, and the amount of shares to exit in partial exit trades.
8. Partial Take Profit trades. Can you describe the steps the App needs to make in more detail?
Let’s say I’m long the SPX with 12 shares with a 50% take profit at $5,800 and a SL at $5,760. Once
$5,800 is hit 6 shares are sold. The App calculates a new TP level, same math as before but
targeting 2R (1:2) and sets a new TP order in IB for the full amount of remaining shares (e.g. 6
shares). The SL is the same as before and will be manually adjusted at the end of the day by me. I
might also manually change the TP to be a partial exit. Once I make the manual adjustments of
Active Order in the App, I would click a button in the App to update all TP and SL Orders. If I’ve
selected a partial exit, the next time the TP level is hit, the App would automatically create a new TP
order, but now for 3R (1:3), and so forth.  CHANGE THE PROFIT MAGANEMENT HERE # trading_bot.py

import pandas as pd
from ib_insync import *
import time
import csv
from datetime import datetime

# Initialize the IB connection
ib = IB()
ib.connect('127.0.0.1', 4002, clientId=1)  # Adjust the port and clientId if necessary

# Read the CSV file
def read_daily_entries(csv_file):
    entries_df = pd.read_csv(csv_file)

    # Convert percentage strings to float
    entries_df['ManualStopLossAdjustment'] = entries_df['ManualStopLossAdjustment'].str.rstrip('%').astype('float') / 100.0
    entries_df['EntryPriceRangePercentage1'] = entries_df['EntryPriceRangePercentage1'].str.rstrip('%').astype('float') / 100.0
    entries_df['EntryPriceRangePercentage2'] = entries_df['EntryPriceRangePercentage2'].str.rstrip('%').astype('float') / 100.0
    entries_df['TakeProfitSharePercentage'] = entries_df['TakeProfitSharePercentage'].str.rstrip('%').astype('float') / 100.0

    return entries_df

# Get previous day's high or low
def get_previous_day_price(symbol, price_type):
    # Adjust the contract according to the instrument (e.g., use Index, Stock, Future)
    contract = Index(symbol, 'CBOE')  # Update this as needed
    ib.qualifyContracts(contract)

    # Request historical data
    bars = ib.reqHistoricalData(
        contract,
        endDateTime='',
        durationStr='2 D',
        barSizeSetting='1 day',
        whatToShow='TRADES',
        useRTH=True,
        formatDate=1
    )

    if len(bars) >= 2:
        prev_day_bar = bars[-2]
        if price_type == 'high':
            return prev_day_bar.high
        elif price_type == 'low':
            return prev_day_bar.low
    else:
        return None

# Place conditional orders
def place_order(row):
    symbol = row['Ticker']
    position_type = row['PositionType']
    entry_price1 = row['EntryPrice1']
    quantity = int(row['Quantity'])
    account = str(row['IBAccount'])
    entry_type_hours = row['EntryTypeHours']
    entry_tif = row['EntryTimeInForce']

    # Create contract
    contract = Index(symbol, 'CBOE')
    ib.qualifyContracts(contract)

    # Determine action
    if position_type.lower() == 'long':
        action = 'BUY'
    else:
        action = 'SELL'

    # Determine whether to allow trading outside RTH
    if entry_type_hours.lower() == 'rth':
        # Regular Trading Hours only
        outside_rth = False
    else:
        # Include Extended Trading Hours
        outside_rth = True

    # Create limit order with conditional entry price
    entry_order = LimitOrder(action, quantity, entry_price1, account=account, tif=entry_tif, outsideRth=outside_rth)
    trade = ib.placeOrder(contract, entry_order)

    print(f"Placed {position_type} order for {symbol}: {quantity} contracts at ${entry_price1:.2f}, Outside RTH: {outside_rth}")

    return trade, contract

# Profit management
def profit_management(trade, contract, row):
    # Wait for order to fill
    while trade.orderStatus.status != 'Filled':
        ib.sleep(1)

    filled_price = trade.orderStatus.avgFillPrice
    quantity = trade.orderStatus.filled
    position_type = row['PositionType']
    take_profit_exit = row['TakeProfitSharePercentage']
    manual_stop_loss_adj = row['ManualStopLossAdjustment']
    risk_per_unit = row['RiskPerUnit']
    account = str(row['IBAccount'])
    stop_loss_hours = row['StopLossHours']
    take_profit_hours = row['TakeProfitHours']

    print(f"Order filled at ${filled_price:.2f} for {quantity} contracts.")

    # Calculate risk and stop loss price
    if position_type.lower() == 'long':
        initial_stop_loss = float(row['InitialStopLoss'])
        risk = filled_price - initial_stop_loss
        stop_loss_price = filled_price - (manual_stop_loss_adj * risk)
        stop_action = 'SELL'
        tp_action = 'SELL'
    else:
        initial_stop_loss = float(row['InitialStopLoss'])
        risk = initial_stop_loss - filled_price
        stop_loss_price = filled_price + (manual_stop_loss_adj * risk)
        stop_action = 'BUY'
        tp_action = 'BUY'

    # Determine whether to allow trading outside RTH for Stop Loss
    if stop_loss_hours.lower() == 'rth':
        sl_outside_rth = False
    else:
        sl_outside_rth = True

    # Create Stop Loss Order
    sl_order = StopOrder(stop_action, quantity, stop_loss_price, account=account, outsideRth=sl_outside_rth)
    ib.placeOrder(contract, sl_order)

    print(f"Placed Stop Loss order at ${stop_loss_price:.2f}, Outside RTH: {sl_outside_rth}")

    # Take Profit logic
    take_profit_quantity = int(quantity * take_profit_exit)
    if position_type.lower() == 'long':
        take_profit_price = filled_price + risk
    else:
        take_profit_price = filled_price - risk

    # Determine whether to allow trading outside RTH for Take Profit
    if take_profit_hours.lower() == 'rth':
        tp_outside_rth = False
    else:
        tp_outside_rth = True

    tp_order = LimitOrder(tp_action, take_profit_quantity, take_profit_price, account=account, outsideRth=tp_outside_rth)
    ib.placeOrder(contract, tp_order)

    print(f"Placed Take Profit order at ${take_profit_price:.2f} for {take_profit_quantity} contracts, Outside RTH: {tp_outside_rth}")

    # Monitor for TP or SL hit
    monitor_trade(contract, position_type, filled_price, stop_loss_price, take_profit_price, quantity, take_profit_quantity, account)

# Monitoring the trade
def monitor_trade(contract, position_type, entry_price, stop_loss_price, take_profit_price, total_quantity, tp_quantity, account):
    position_closed = False
    while not position_closed:
        ib.sleep(5)
        market_data = ib.reqMktData(contract, '', False, False)
        ib.sleep(1)  # Allow time for market data to be received
        market_price = market_data.last

        if market_price is None:
            continue

        if position_type.lower() == 'long':
            if market_price <= stop_loss_price:
                print(f"Stop Loss hit at ${market_price:.2f}. Closing position.")
                close_position(contract, 'SELL', total_quantity, account)
                position_closed = True
            elif market_price >= take_profit_price:
                print(f"Take Profit target reached at ${market_price:.2f}.")
                # Create trailing stop for remaining position
                remaining_quantity = total_quantity - tp_quantity
                if remaining_quantity > 0:
                    create_trailing_stop(contract, 'SELL', remaining_quantity, account)
                position_closed = True
        else:
            if market_price >= stop_loss_price:
                print(f"Stop Loss hit at ${market_price:.2f}. Closing position.")
                close_position(contract, 'BUY', total_quantity, account)
                position_closed = True
            elif market_price <= take_profit_price:
                print(f"Take Profit target reached at ${market_price:.2f}.")
                # Create trailing stop for remaining position
                remaining_quantity = total_quantity - tp_quantity
                if remaining_quantity > 0:
                    create_trailing_stop(contract, 'BUY', remaining_quantity, account)
                position_closed = True

# Create trailing stop for remaining position
def create_trailing_stop(contract, action, quantity, account):
    # Implement logic for manual adjustment or trailing stop
    print(f"Creating trailing stop for {quantity} contracts.")
    # For simplicity, use a trailing amount (e.g., $10)
    trailing_amount = 10.0
    ts_order = TrailStopOrder(action, quantity, trailingAmount=trailing_amount, account=account)
    ib.placeOrder(contract, ts_order)

    print(f"Placed trailing stop order with trailing amount ${trailing_amount:.2f}.")

# Close position
def close_position(contract, action, quantity, account):
    close_order = MarketOrder(action, quantity, account=account)
    ib.placeOrder(contract, close_order)

# Record trade
def record_trade(symbol, entry_price, exit_price, quantity, entry_date, exit_date, profit_loss, commissions):
    trade_record = {
        'Symbol': symbol,
        'EntryPrice': entry_price,
        'ExitPrice': exit_price,
        'Quantity': quantity,
        'EntryDate': entry_date,
        'ExitDate': exit_date,
        'ProfitLoss': profit_loss,
        'Commissions': commissions
    }

    # Append to CSV
    with open('trade_records.csv', 'a', newline='') as csvfile:
        fieldnames = ['Symbol', 'EntryPrice', 'ExitPrice', 'Quantity', 'EntryDate', 'ExitDate', 'ProfitLoss', 'Commissions']
        writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
        writer.writerow(trade_record)

    print(f"Recorded trade for {symbol}.")

# Main function
def main():
    # Read the CSV file
    entries_df = read_daily_entries('daily_entries.csv')

    # Process each entry
    for index, row in entries_df.iterrows():
        symbol = row['Ticker'] #4
        position_type = row['PositionType'] #5
        initial_stop_loss = float(row['InitialStopLoss']) #6
        risk_amount = float(row['RiskAmount'])#1
        entry_percentage1 = float(row['EntryPriceRangePercentage1']) #2
        entry_percentage2 = float(row['EntryPriceRangePercentage2']) #3
        take_profit_share_percentage = row['TakeProfitSharePercentage'] #7
        manual_stop_loss_adj = row['ManualStopLossAdjustment'] #8
        ib_account = str(row['IBAccount'])
        entry_time_in_force = row['EntryTimeInForce']
        entry_type_hours = row['EntryTypeHours']
        stop_loss_hours = row['StopLossHours']
        take_profit_hours = row['TakeProfitHours']

        # Get previous day's high or low
        if position_type.lower() == 'long':
            prev_price = get_previous_day_price(symbol, 'high') #9
        else:
            prev_price = get_previous_day_price(symbol, 'low') #9

        if prev_price is None:
            print(f"Couldn't retrieve previous day's price for {symbol}.")
            continue

        # Calculate risk per unit
        if position_type.lower() == 'long':
            risk_per_unit = prev_price - initial_stop_loss #[10]
            entry_price1 = (entry_percentage1 * risk_per_unit) + prev_price #11
            entry_price2 = (entry_percentage2 * risk_per_unit) + prev_price #12
        else:
            risk_per_unit = initial_stop_loss - prev_price
            entry_price1 = prev_price - (entry_percentage1 * risk_per_unit)
            entry_price2 = prev_price - (entry_percentage2 * risk_per_unit)

        # Calculate quantity
        quantity = int(risk_amount / risk_per_unit) #13

        # Update the DataFrame
        entries_df.at[index, 'RiskPerUnit'] =  
        entries_df.at[index, 'EntryPrice1'] = entry_price1
        entries_df.at[index, 'EntryPrice2'] = entry_price2
        entries_df.at[index, 'Quantity'] = quantity
        entries_df.at[index, 'TakeProfitSharePercentage'] = take_profit_share_percentage
        entries_df.at[index, 'ManualStopLossAdjustment'] = manual_stop_loss_adj
        entries_df.at[index, 'IBAccount'] = ib_account
        entries_df.at[index, 'EntryTypeHours'] = entry_type_hours
        entries_df.at[index, 'StopLossHours'] = stop_loss_hours
        entries_df.at[index, 'TakeProfitHours'] = take_profit_hours

        # Place order and manage trade
        trade, contract = place_order(entries_df.loc[index])
        profit_management(trade, contract, entries_df.loc[index])

    ib.disconnect()

if __name__ == "__main__":
    main()