Paper trading Code checking

Hi, Please check my code for paper trading on live straddle chart.

import pdb
import time
import datetime
import traceback
from Dhan_Tradehull import Tradehull
import pandas as pd
from pprint import pprint
import talib
import pandas_ta as ta
import xlwings as xw
import pytz

# Initialize client and connection
client_code = "11"
token_id = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJpc3MiOiJkaGFuIiwicGFydG5lcklkIjoiIiwiZXhwIjoxNzM5MDk5MTc3LCJ0b2tlbkNvbnN1bWVyVHlwZSI6IlNFTEYiLCJ3ZWJob29rVXJsIjoiIiwiZGhhbkNsaWVudElkIjoiMXcTTEwMDg4OTA1NSJ9.bX2eeT5ZMHh689KIp_3dUzRzbohivQvgAkrbjZonf2tTq6c4soTcMqnlP6gR4wOIVY1ctBSu_tL4_T51kcFyTA"
tsl = Tradehull(client_code, token_id)


ce_name, pe_name, strike_price = tsl.ATM_Strike_Selection(Underlying='SENSEX', Expiry=0)
last_candle_time = datetime.datetime.now()
last_candle_time = last_candle_time.replace(hour=9, minute=15, second=0, microsecond=0)

ce_data = tsl.get_historical_data(tradingsymbol=ce_name, exchange='BFO', timeframe="1")
pe_data = tsl.get_historical_data(tradingsymbol=pe_name, exchange='BFO', timeframe="1")

print(ce_name)
print(pe_name)

single_order = {'Option name': None,'entry_strike': None, 'date': None, 'entry_time': None, 'ce_entry_price': None, 'pe_entry_price': None, 'buy_sell': None, 'qty': None, 'sl': None, 'exit_time': None, 'exit_price': None, 'pnl': None, 'remark': None, 'traded': None}
orderbook = {}
completed_orders = {'Option name': None,'entry_strike': None, 'date': None, 'entry_time': None, 'ce_entry_price': None, 'pe_entry_price': None, 'buy_sell': None, 'qty': None, 'sl': None, 'exit_time': None, 'exit_price': None, 'pnl': None, 'remark': None, 'traded': None}
watchlist = ['SENSEX']
all_dataframes = []
completed_orders = []
reentry          = "yes" #"yes/no"
completed_orders = []
# Initialize merged_df outside the if block
merged_df = None
# Initialize Supertrend outside the if block
Supertrend = None

# bot_token        = "8059847390:AAECSnQK-yOaGJ-clJchb1cx8CDhx2VQq-M"
# receiver_chat_id = "1918451082"
book = xw.Book("Straddle.xlsx")
Straddle_chart = book.sheets['Straddle Chart']
config_sheet = book.sheets['Config']
running_orders_sheet = book.sheets['Running Orders']
completed_orders_sheet = book.sheets['Completed Orders']

for name in watchlist:
    orderbook[name] = single_order.copy()

while True:
    loop_start_time = time.time()  # Record start time of loop
    print("Starting while loop\n\n")
    
    current_time = datetime.datetime.now().time()

    # Market timing checks
    if current_time < datetime.time(8, 15):
        print(f"Wait for market to start", current_time)
        time.sleep(60)
        continue
    if current_time > datetime.time(23, 30):
        order_details = tsl.cancel_all_orders()
        print(f"Market over Closing all trades!! Bye Bye See you Tomorrow", current_time)
        break



    for name in watchlist:
        # ------------------------------------- GET DATA -------------------------------------
        # Create DataFrame with explicit index to avoid ValueError
        orderbook_df = pd.DataFrame([orderbook[name]], index=[name])  # Changed from .from_dict() to list with single dict
        
        # Clear and write to Excel with error handling
        try:
            # Create DataFrame from orderbook with explicit index
            orderbook_df = pd.DataFrame.from_dict(orderbook, orient='index')
            running_orders_sheet.range('A1').value = orderbook_df

            # Create DataFrame from completed_orders with index
            if completed_orders:  # Check if there are any completed orders
                completed_orders_df = pd.DataFrame(completed_orders)
                completed_orders_df.reset_index(drop=True, inplace=True)  # Create numeric index
            else:
                completed_orders_df = pd.DataFrame(columns=single_order.keys())  # Empty DataFrame with correct columns
            completed_orders_sheet.range('A1').value = completed_orders_df

            current_time = datetime.datetime.now()
            print(f"Scanning        {name} {current_time}")
        except Exception as e:
            print(f"Error writing to Excel: {str(e)}")
            # Continue execution even if Excel write fails
            pass
        candle_is_still_running = datetime.datetime.now() < last_candle_time + datetime.timedelta(minutes=1)
        ce_name, pe_name, strike_price = tsl.ATM_Strike_Selection(Underlying='SENSEX', Expiry=0)
    if candle_is_still_running is False:
        ce_data = tsl.get_historical_data(tradingsymbol = ce_name,exchange = 'BFO',timeframe="1")
        pe_data = tsl.get_historical_data(tradingsymbol = pe_name,exchange = 'BFO',timeframe="1")
        last_candle_time        = ce_data.iloc[-1]['timestamp'].to_pydatetime().replace(tzinfo=None)        
        continue

    all_ltp_data            = tsl.get_ltp_data(names=[ce_name, pe_name])





    if candle_is_still_running:
        ce_ltp                  = all_ltp_data[ce_name]
        ce_data.iloc[-1, ce_data.columns.get_loc('close')] = ce_ltp

        pe_ltp                  = all_ltp_data[pe_name]
        pe_data.iloc[-1, pe_data.columns.get_loc('close')] = pe_ltp

        merged_df = pd.merge(ce_data[['timestamp', 'close']], pe_data[['timestamp', 'close']], on='timestamp', suffixes=('_ce', '_pe')).set_index('timestamp')
        merged_df['combined_premium'] = merged_df['close_ce'] + merged_df['close_pe']
      # Calculate OHLC for combined premium
        merged_df['combined_premium_high'] = merged_df['combined_premium'].rolling(window=1).max()
        merged_df['combined_premium_low'] = merged_df['combined_premium'].rolling(window=1).min()
        merged_df['combined_premium_open'] = merged_df['combined_premium'].shift(1)
        merged_df['combined_premium_close'] = merged_df['combined_premium']
            
        merged_df['ROC'] = talib.ROC(merged_df['combined_premium'], timeperiod=9)
            # Calculate Supertrend using pandas_ta
        Supertrend = ta.supertrend(merged_df['combined_premium_high'], merged_df['combined_premium_low'], merged_df['combined_premium_close'], 10, 2)
        merged_df = pd.concat([merged_df, Supertrend], axis=1, join='inner')
        # Remove .values from numpy float values since they don't have that attribute
        combined_premium_value = merged_df['combined_premium'].iloc[-1]
        roc_value = merged_df['ROC'].iloc[-1]
        supertrend_value = Supertrend['SUPERTd_10_2.0'].iloc[-1]
        
        data_to_write = [str(current_time), combined_premium_value, strike_price, roc_value, supertrend_value]

        print(f"ce_ltp {ce_ltp}")
        print(f"pe_ltp {pe_ltp}")
        

        last_row = 2
        while Straddle_chart.range(f'A{last_row}').value is not None:
            last_row += 1
        if last_row > 30000:  # Safety limit
            last_row = 2  # Reset to top if sheet is full
            break

        # Add strike change message if strike price changed
        if last_row > 2 and Straddle_chart.range(f'C{last_row-1}').value != strike_price:
            data_to_write.append("Strike change to " + str(strike_price))
            print(f"Strike price changed from {Straddle_chart.range(f'C{last_row-1}').value} to {strike_price}")
        else:
            data_to_write.append("")
        Straddle_chart.range(f'A{last_row}:E{last_row}').value = data_to_write
                
        # Initialize variables with default values before try block
        tc1 = tc2 = tc3 = tc4 = False

        try:
            # Get first and current candle for 3-minute timeframe
            First_cc = merged_df.iloc[0] # First candle of 1-min period
            cc = merged_df.iloc[-1] # Current candle of 1-min period
            
            # Check if we're at the 3-min candle close
            current_minute = current_time.minute
            if current_minute % 3 != 0:  # Only take trade at 3-min candle close
                continue
            
            # Check if combined premium is lower than 3 candles ago
            tc1 = cc['combined_premium'] < First_cc['combined_premium']
            # Check if Supertrend exists and has data before accessing it
            tc2 = False  # Default value
            if Supertrend is not None and len(Supertrend) > 0:
                tc2 = Supertrend['SUPERTd_10_2.0'].iloc[-1] == -1
            tc3 = current_time.time() > datetime.time(9, 15) and current_time.time() < datetime.time(23, 30)
            tc4 = orderbook[name]['traded'] is None
        except Exception as e:
            print("Error accessing data:", e)
            print("Supertrend status:", "None" if Supertrend is None else "Has data")
            print("merged_df status:", "None" if merged_df is None else f"Has {len(merged_df)} rows")
            continue

        # Add a check before using Supertrend
        ec1 = False  # Default value
        if Supertrend is not None and len(Supertrend) > 0:
            ec1 = Supertrend['SUPERTd_10_2.0'].iloc[-1] == 1

        # Exit if current strike price differs from entry strike price
        if orderbook[name].get('entry_strike') is None:
            ec2 = False
        else:
            ec2 = strike_price != orderbook[name]['entry_strike']
            
        ec3 = current_time.time() >= datetime.time(15, 15)  # Exit at 3:15 PM
        ec4 = orderbook[name]['traded'] == "yes"  # Check if trade is active

        if tc1 and tc2 and tc3 and tc4:
            print("Trade condition met. Placing order...Short Straddle")
            # margin_avialable = tsl.get_balance()
            # margin_required  = 200000

            # if margin_avialable < margin_required:
            #     print(f"Less margin, not taking order : margin_avialable is {margin_avialable} and margin_required is {margin_required} for {name}")
            
            ce_lot_size = tsl.get_lot_size(tradingsymbol=ce_name)
            pe_lot_size = tsl.get_lot_size(tradingsymbol=pe_name)

            # Set the quantity to 1 lot for both CE and PE
            ce_qty = ce_lot_size * 5
            pe_qty = pe_lot_size * 5

            print(f"Attempting to place CE order: Symbol={ce_name}, Qty={ce_qty}")
            print(f"Attempting to place PE order: Symbol={pe_name}, Qty={pe_qty}")
            
            orderbook[name]['name'] = name
            orderbook[name]['date'] = str(current_time.date())
            orderbook[name]['entry_time'] = str(current_time.time())[:8]
            orderbook[name]['buy_sell'] = "SELL"
            orderbook[name]['qty'] = ce_qty or pe_qty

            try:
                # ce_entry_ordrid = tsl.order_placement(...)
                orderbook[name]['ce_entry_ordrid'] = 11111111
                orderbook[name]['pe_entry_ordrid'] = 11111111
                # orderbook[name]['ce_entry_price'] = tsl.get_executed_price(orderid=orderbook[name]['ce_entry_ordrid'])
                # orderbook[name]['pe_entry_price'] = tsl.get_executed_price(orderid=orderbook[name]['pe_entry_ordrid'])
                orderbook[name]['entry_time'] = str(datetime.datetime.now().time())[:8]
                orderbook[name]['entry_datetime'] = datetime.datetime.now()
                orderbook[name]['traded'] = "yes"

                # message = "\n".join(f"'{key}': {repr(value)}" for key, value in orderbook[name].items())
                # message = f"Entry_done {name} \n\n {message}"
                # tsl.send_telegram_alert(message=message,receiver_chat_id=receiver_chat_id,bot_token=bot_token)
            except Exception as e:
                print(f"Error placing orders: {str(e)}")
                print(f"Traceback: {traceback.format_exc()}")

        else:
            print("Trade condition not met. Skipping entry.")

        if orderbook[name]['traded'] == "yes":
            orderbook[name]['buy_sell'] == "SELL"
        # ------------------------------------- Exit Condition -------------------------------------
        if (ec1 or ec2 or ec3) and ec4:
            print("Exit condition met. Closing straddle position...")
            try:
                # Store exit details
                current_trade                   = orderbook[name].copy()
                orderbook[name]['ce_name']      = ce_name
                orderbook[name]['pe_name']      = pe_name
                orderbook[name]['buy_sell']     = "BUY" 
                orderbook[name]['date']         = str(datetime.datetime.now().date())
                orderbook[name]['exit_time']    = str(datetime.datetime.now().time())[:8]
                orderbook[name]['exit_datetime'] = datetime.datetime.now()

                # Place sell orders to close straddle position
                # ce_exit_ordrid                  = tsl.order_placement(tradingsymbol=orderbook[name]['ce_name'], exchange='BFO', quantity=orderbook[name]['qty'], price=0, trigger_price=0, order_type='MARKET', transaction_type='BUY', trade_type='MIS')
                # pe_exit_ordrid                  = tsl.order_placement(tradingsymbol=orderbook[name]['pe_name'], exchange='BFO', quantity=orderbook[name]['qty'], price=0, trigger_price=0, order_type='MARKET', transaction_type='BUY', trade_type='MIS')

                # Store exit order IDs
                orderbook[name]['ce_exit_ordrid'] = 11111111
                orderbook[name]['pe_exit_ordrid'] = 11111111
                orderbook[name]['traded'] = None  # Reset traded status

                # Get exit prices with timeout and error handling
                ce_exit_price = tsl.get_executed_price(orderid=orderbook[name]['ce_exit_ordrid'])
                pe_exit_price = tsl.get_executed_price(orderid=orderbook[name]['pe_exit_ordrid'])

                if ce_exit_price is None or pe_exit_price is None:
                    print("Failed to get exit prices, will retry next iteration")
                    continue

                # Update the current trade with PnL information
                current_trade.update({
                    'ce_pnl': (ce_exit_price - current_trade['ce_entry_price']) * current_trade['ce_qty'],
                    'pe_pnl': (pe_exit_price - current_trade['pe_entry_price']) * current_trade['pe_qty'],
                    'total_pnl': (ce_exit_price - current_trade['ce_entry_price']) * current_trade['ce_qty'] + 
                                (pe_exit_price - current_trade['pe_entry_price']) * current_trade['pe_qty']
                })

                # Append completed trade to completed_orders list
                completed_orders.append(current_trade)

                print(f"Straddle PnL: CE={current_trade['ce_pnl']:.2f}, PE={current_trade['pe_pnl']:.2f}, Total={current_trade['total_pnl']:.2f}")
                # Reset orderbook entry for new trades
                orderbook[name] = single_order.copy()
            except Exception as e:
                print(f"Error closing straddle position: {str(e)}")
                print(f"Traceback: {traceback.format_exc()}")
            
        if reentry == "yes":
            completed_orders.append(orderbook[name])
            orderbook[name] = None

    # Modify sleep calculation to account for processing time more precisely
    current_time = datetime.datetime.now()
    time_since_last_candle = (current_time - last_candle_time).total_seconds()
    
    if time_since_last_candle < 60:  # If we haven't reached the next 1-minute mark
        sleep_time = 60 - time_since_last_candle
        if sleep_time > 0:
            time.sleep(sleep_time)
    


Hi @Sobhit

Code seems to be correct, Also do test the code and let us know if any errors faced.

Thanks, My running order and completed order sheets are not getting updated. please help on the same.

the order and completed order sheets will update only after we receive an entry or exit

But i am giving entry and exit in my code, it should show atleast prices being updated in excel

Below fields will be updated when entry or exit happens

{‘Option name’: None,‘entry_strike’: None, ‘date’: None, ‘entry_time’: None, ‘ce_entry_price’: None, ‘pe_entry_price’: None, ‘buy_sell’: None, ‘qty’: None, ‘sl’: None, ‘exit_time’: None, ‘exit_price’: None, ‘pnl’: None, ‘remark’: None, ‘traded’: None}