Getting Error in Order Placing on Zerodha

from Zerodha_Tradehull import Tradehull
from rich import print
import os
import talib
import pandas as pd
import pandas_ta as pta
import datetime
import time
import xlwings as xw
import pdb
import numpy as np
import pickle


api_key    = ""
api_secret = ""
tsl        = Tradehull(api_key, api_secret, "yes")
kite       = tsl.kite

bot_token 			= "8275097183:AAEhEvqanbH3jgNbw6KEaAHWmPdmydxS4DQ"
receiver_chat_id 	= "5296353864"


book       			= xw.Book('User_Interface_Stock.xlsx')
sheet      			= book.sheets['Live Orderbook']
c_sht      			= book.sheets['Completed_Orderbook']
s_con      			= book.sheets['Strategy']

watchlist  			= [x for x in set(s_con.range("A2:A59").value)]
watchlist 			= [x for x in watchlist if x is not None]
traded_watchlist 	= []


status    = {'underlying_name':None, 'date':None, 'entry_time': None, 'entry_price': None, 'buy_sell': None, 'qty': None, 'exit_time': None, 'exit_price': None, 'pnl': None, 'remark': None, 'traded':None, "entry_ordrid":None, "exit_ordrid":None, 'entry_datetime':None, 'selling_price':None}
orderbook = {}
reentry   = True
completed_orderbook = []

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

sheet.range('A1:Z100').value	= None
c_sht.range('A1:Z100').value 	= None
s_con.range('B6').value      	= None
start_time           			= datetime.datetime(1899, 12, 30) + datetime.timedelta(days=s_con.range("K2").value)
exit_time            			= datetime.datetime(1899, 12, 30) + datetime.timedelta(days=s_con.range("K3").value)
first_day            			= True


if not first_day:
	orderbook = pickle.load(open("orderbook.pkl", "rb"))

trades_in_progress = [x['underlying_name'] for x in orderbook.values() if x['traded'] is not None]

opening_balance 	= tsl.kite.margins("equity")['net']	
base_capital 		= 1544601.80
market_money 		= opening_balance - base_capital

if (market_money < 0):
	market_money == 0
	base_capital == opening_balance

risk_market_money 	= (market_money*1)/100
risk_base_capital 	= (base_capital*0.5)/100
max_risk_for_today 	= risk_market_money + risk_base_capital
max_order_for_today	= 5
max_risk_per_trade  = max_risk_for_today / max_order_for_today
capital_per_trade 	= opening_balance / max_order_for_today

# ------------------------------------------- Indicator Parameters ---------------------
short_SUPT_len 	= 10
short_SUPT_mult = 2
long_SUPT_len 	= 21
long_SUPT_mult 	= 4

# ------------------------------------------- Heikin_ashi Chart ---------------------
def convert_heikin_ashi(df):
    try:
        if df.empty:
            raise ValueError("Input DataFrame is empty.")
        
        # Ensure the DataFrame has the required columns
        required_columns = ['open', 'high', 'low', 'close', 'date']
        if not all(col in df.columns for col in required_columns):
            raise ValueError(f"Input DataFrame must contain these columns: {required_columns}")

        # Prepare Heikin-Ashi columns
        ha_close = (df['open'] + df['high'] + df['low'] + df['close']) / 4
        ha_open = [df['open'].iloc[0]]  # Initialize the first open value
        ha_high = []
        ha_low = []

        # Compute Heikin-Ashi values
        for i in range(1, len(df)):
            ha_open.append((ha_open[-1] + ha_close.iloc[i - 1]) / 2)
            ha_high.append(max(df['high'].iloc[i], ha_open[-1], ha_close.iloc[i]))
            ha_low.append(min(df['low'].iloc[i], ha_open[-1], ha_close.iloc[i]))

        # Append first values for high and low
        ha_high.insert(0, df['high'].iloc[0])
        ha_low.insert(0, df['low'].iloc[0])

        # Create a new DataFrame for Heikin-Ashi values
        ha_df = pd.DataFrame({
            'date': df['date'],
            'open': ha_open,
            'high': ha_high,
            'low': ha_low,
            'close': ha_close
        })

        ha_df['volume'] = df['volume'].copy()

        return ha_df
    except Exception as e:
        print(f"Error in Heikin-Ashi calculation: {e}")
        return pd.DataFrame()
# ------------------------------------------- Main Loop ---------------------

while True:

	current_dtime    = datetime.datetime.now()

	if current_dtime.time() < start_time.time():
		print(f"Wait for market to start", current_dtime)
		continue

	watchlist       = set([x for x in set(s_con.range("A2:A59").value)] + trades_in_progress)
	live_pnl          = tsl.get_live_pnl()
	market_over       = current_dtime.time() > exit_time.time()
	max_loss_hit 	= live_pnl < max_risk_for_today


	if market_over:
		print(f"Market over Closing all trades !! Bye Bye See you Tomorrow", current_dtime)
		# tsl.market_over_close_all_order()
		os.makedirs(f'Logs/{str(current_dtime.date())}', exist_ok=True)
		odf.to_csv(f'Logs/{str(current_dtime.date())}/odf.csv', index=True)
		pd.DataFrame(kite.orders()).to_csv(f'Logs/{str(current_dtime.date())}/orders.csv', index=True)
		pd.DataFrame(kite.positions()).to_csv(f'Logs/{str(current_dtime.date())}/positions.csv', index=True)
		pickle.dump(orderbook, open(f'orderbook.pkl', "wb"))
		break

	for name in watchlist:        

		print(name)
		odf                     = pd.DataFrame(orderbook).T
		sheet.range('A1').value = odf
		c_sht.range('A1').value = pd.DataFrame(completed_orderbook)
		current_dt              = datetime.datetime.now()


		ltp 					= tsl.get_ltp(name, "NSE")
		orderbook[name]['Ltp']  = ltp

		chart 					= tsl.get_short_term_hist_data(name=name, exchange="NSE", interval="60minute", oi = True)
		chart_ha 				= convert_heikin_ashi(chart)
		
		indi_Short         		= pta.supertrend(chart_ha['high'], chart_ha['low'], chart_ha['close'], length=short_SUPT_len, multiplier=short_SUPT_mult)
		chart_ha   				= pd.concat([chart_ha, indi_Short], axis=1, join='inner')
		st1_col, st1d_col, st1l_col, st1s_col           =   indi_Short.columns

		indi_Long         		= pta.supertrend(chart_ha['high'], chart_ha['low'], chart_ha['close'], length=long_SUPT_len, multiplier=long_SUPT_mult)
		chart_ha    			= pd.concat([chart_ha, indi_Long], axis=1, join='inner').round(2)
		st2_col, st2d_col, st2l_col, st2s_col           =   indi_Long.columns

		comp_candle 			= chart_ha.iloc[-2]
		prev_candle				= chart_ha.iloc[-3]
		Traded 					= orderbook[name]['traded']


		bc1 = comp_candle[st1d_col] == 1
		bc2 = comp_candle[st2d_col] == 1
		bc3 = Traded is None
		bc4 = (len(completed_orderbook) + odf[odf["underlying_name"].notna()].shape[0]) <= 5

		sc1 = comp_candle[st1d_col] == -1
		sc2 = comp_candle[st2d_col] == -1
		sc3 = Traded is None
		sc4 = (len(completed_orderbook) + odf[odf["underlying_name"].notna()].shape[0]) <= 5


		if bc1 and bc2 and bc3 and bc4:
			print(name, "Supertrend Buy Signal, Uptrend")
			quantity 			= 1 #int(capital_per_trade/ltp)
			Entry_Price     	= tsl.get_ltp(name, "NSE")

			Entry_Order_ID    	= tsl.place_order(variety="regular", exchange='NSE', tradingsymbol=name, transaction_type='BUY', quantity=quantity, product="CNC", order_type="LIMIT", price = Entry_Price, trigger_price = Entry_Price)
			
			message = f"Traded in {name} \nQuantity {quantity} \nPrice {Entry_Price}"
			tsl.send_telegram_alert(message=message,receiver_chat_id=receiver_chat_id,bot_token=bot_token)
			
			orderbook[name]['underlying_name']   = name
			orderbook[name]['date']              = str(current_dt.date())
			orderbook[name]['entry_time']        = str(current_dt.time())
			orderbook[name]['entry_price']       = Entry_Price #tsl.get_executed_price(order_id = entry_id)
			orderbook[name]['buy_sell']          = 'Buy'
			orderbook[name]['qty']               = quantity
			orderbook[name]['traded']            = True
			orderbook[name]['entry_ordrid']      = Entry_Order_ID
			orderbook[name]['entry_datetime']    = current_dt

		if sc1 and sc2 and sc3 and sc4:
			print(name, "Supertrend Sell Signal , Downtrend")
			quantity 			= 1 #int(capital_per_trade/ltp)
			Entry_Price     	= tsl.get_ltp(name, "NSE")

			Entry_Order_ID    	= tsl.place_order(variety="regular", exchange='NSE', tradingsymbol=name, transaction_type='SELL', quantity=quantity, product="CNC", order_type="LIMIT", price = Entry_Price, trigger_price = Entry_Price)
			
			message = f"Traded in {name} \nQuantity {quantity} \nPrice {Entry_Price}"
			tsl.send_telegram_alert(message=message,receiver_chat_id=receiver_chat_id,bot_token=bot_token)
			
			orderbook[name]['underlying_name']   = name
			orderbook[name]['date']              = str(current_dt.date())
			orderbook[name]['entry_time']        = str(current_dt.time())
			orderbook[name]['entry_price']       = Entry_Price #tsl.get_executed_price(order_id = entry_id)
			orderbook[name]['buy_sell']          = 'Sell'
			orderbook[name]['qty']               = quantity
			orderbook[name]['traded']            = True
			orderbook[name]['entry_ordrid']      = Entry_Order_ID
			orderbook[name]['entry_datetime']    = current_dt
			
		if orderbook[name]['traded']:

			bought  = orderbook[name]['buy_sell'] == 'Buy'
			sold    = orderbook[name]['buy_sell'] == 'Sell'

			if bought:
				supertrend_change = comp_candle[st1d_col] == -1 and comp_candle[st2d_col] == 1

				if supertrend_change:
					
					quantity 			= orderbook[name]['qty']
					selling_price 		= tsl.get_ltp(orderbook[name]['underlying_name'], "NSE")
					
					exit_order_id    	= tsl.place_order(variety="regular", exchange='NSE', tradingsymbol=orderbook[name]['underlying_name'], transaction_type='SELL', quantity=quantity, product="CNC", order_type="LIMIT", price = selling_price)
					
					orderbook[name]['remark'] 			= "Target Sell-Hit"
					orderbook[name]['selling_price']    = selling_price
					orderbook[name]['exit_ordrid']    	= exit_order_id
					orderbook[name]['exit_time']     	= str(current_dt.time())

					if reentry:
						completed_orderbook.append(orderbook[name])						
						orderbook[name] = status.copy()

			if sold:
				supertrend_change = comp_candle[st1d_col] == 1 and comp_candle[st2d_col] == -1

				if supertrend_change:
					
					quantity 		= orderbook[name]['qty']
					selling_price 	= tsl.get_ltp(orderbook[name]['underlying_name'], "NSE")
					
					exit_order_id   = tsl.place_order(variety="regular", exchange='NSE', tradingsymbol=orderbook[name]['underlying_name'], transaction_type='BUY', quantity=quantity, product="CNC", order_type="LIMIT", price = selling_price)
					
					orderbook[name]['remark'] 			= "Target Buy-Hit"
					orderbook[name]['selling_price']    = selling_price
					orderbook[name]['exit_ordrid']    	= exit_order_id
					orderbook[name]['exit_time']     	= str(current_dt.time())

					if reentry:
						completed_orderbook.append(orderbook[name])						
						orderbook[name] = status.copy()
PS C:\Users\HP\OneDrive\Working Algo\Double ST> & C:/Users/HP/AppData/Local/Programs/Python/Python38/python.exe "c:/Users/HP/OneDrive/Working Algo/Double ST/Double-ST_Zerodha-1.py"
Zerodha CodeBase Version 1.0.3
Logging into zerodha
You have already loggged in for today
reading existing file all_instrument 2025-11-19.csv
You are connected to zerodha Tarun Sharma 
UNIONBANK
UNIONBANK Supertrend Buy Signal, Uptrend
TATAPOWER
TATAPOWER Supertrend Sell Signal , Downtrend
Traceback (most recent call last):
  File "C:\Users\HP\AppData\Local\Programs\Python\Python38\lib\site-packages\Zerodha_Tradehull\Zerodha_Tradehull.py", line 1269, in place_order
    order_id = self.kite.place_order(variety=variety, exchange=exchange, tradingsymbol=tradingsymbol, transaction_type=transaction_type, quantity=quantity, product=product, order_type=order_type, price=price, validity=validity, disclosed_quantity=disclosed_quantity, trigger_price=trigger_price, validity_ttl= validity_ttl,iceberg_legs = iceberg_legs, iceberg_quantity=iceberg_quantity, auction_number= auction_number, tag=tag)
  File "C:\Users\HP\AppData\Local\Programs\Python\Python38\lib\site-packages\kiteconnect\connect.py", line 361, in place_order
    return self._post("order.place",
  File "C:\Users\HP\AppData\Local\Programs\Python\Python38\lib\site-packages\kiteconnect\connect.py", line 865, in _post
    return self._request(route, "POST", url_args=url_args, params=params, is_json=is_json, query_params=query_params)
  File "C:\Users\HP\AppData\Local\Programs\Python\Python38\lib\site-packages\kiteconnect\connect.py", line 937, in _request
    raise exp(data["message"], code=r.status_code)
kiteconnect.exceptions.InputException: Insufficient stock holding or there are pending sell orders for this stock. Check the orderbook. Order quantity: 1, Holding quantity: 0
TATASTEEL
TATASTEEL Supertrend Sell Signal , Downtrend
Traceback (most recent call last):
  File "C:\Users\HP\AppData\Local\Programs\Python\Python38\lib\site-packages\Zerodha_Tradehull\Zerodha_Tradehull.py", line 1269, in place_order
    order_id = self.kite.place_order(variety=variety, exchange=exchange, tradingsymbol=tradingsymbol, transaction_type=transaction_type, quantity=quantity, product=product, order_type=order_type, price=price, validity=validity, disclosed_quantity=disclosed_quantity, trigger_price=trigger_price, validity_ttl= validity_ttl,iceberg_legs = iceberg_legs, iceberg_quantity=iceberg_quantity, auction_number= auction_number, tag=tag)
  File "C:\Users\HP\AppData\Local\Programs\Python\Python38\lib\site-packages\kiteconnect\connect.py", line 361, in place_order
    return self._post("order.place",
  File "C:\Users\HP\AppData\Local\Programs\Python\Python38\lib\site-packages\kiteconnect\connect.py", line 865, in _post
    return self._request(route, "POST", url_args=url_args, params=params, is_json=is_json, query_params=query_params)
  File "C:\Users\HP\AppData\Local\Programs\Python\Python38\lib\site-packages\kiteconnect\connect.py", line 937, in _request
    raise exp(data["message"], code=r.status_code)
kiteconnect.exceptions.InputException: Insufficient stock holding or there are pending sell orders for this stock. Check the orderbook. Order quantity: 1, Holding quantity: 0
SHRIRAMFIN
SHRIRAMFIN Supertrend Buy Signal, Uptrend
RECLTD
RECLTD Supertrend Sell Signal , Downtrend
Traceback (most recent call last):
  File "C:\Users\HP\AppData\Local\Programs\Python\Python38\lib\site-packages\Zerodha_Tradehull\Zerodha_Tradehull.py", line 1269, in place_order
    order_id = self.kite.place_order(variety=variety, exchange=exchange, tradingsymbol=tradingsymbol, transaction_type=transaction_type, quantity=quantity, product=product, order_type=order_type, price=price, validity=validity, disclosed_quantity=disclosed_quantity, trigger_price=trigger_price, validity_ttl= validity_ttl,iceberg_legs = iceberg_legs, iceberg_quantity=iceberg_quantity, auction_number= auction_number, tag=tag)
  File "C:\Users\HP\AppData\Local\Programs\Python\Python38\lib\site-packages\kiteconnect\connect.py", line 361, in place_order
    return self._post("order.place",
  File "C:\Users\HP\AppData\Local\Programs\Python\Python38\lib\site-packages\kiteconnect\connect.py", line 865, in _post
    return self._request(route, "POST", url_args=url_args, params=params, is_json=is_json, query_params=query_params)
  File "C:\Users\HP\AppData\Local\Programs\Python\Python38\lib\site-packages\kiteconnect\connect.py", line 937, in _request
    raise exp(data["message"], code=r.status_code)
kiteconnect.exceptions.InputException: Insufficient stock holding or there are pending sell orders for this stock. Check the orderbook. Order quantity: 1, Holding quantity: 0

Also facing an error extracting data into Excel.

Hello @tarsharm20 ,

You’re getting this error because you are placing SELL orders with product=“CNC”:

kiteconnect.exceptions.InputException: 
Insufficient stock holding... Holding quantity: 0

CNC cannot short-sell unless the stock already exists in your Demat.
So Zerodha is blocking your SELL trades.

:white_check_mark: Fix

Use MIS instead of CNC for intraday:

tsl.place_order(
    variety="regular",
    exchange="NSE",
    tradingsymbol=name,
    transaction_type='SELL',
    quantity=quantity,
    product="MIS",        # ← FIXED
    order_type="LIMIT",
    price=Entry_Price
)

After changing to MIS, both BUY/SELL will work and your Excel update error will also stop.

Hi @Tradehull_Sathesh

Thank you for your reply.

But I want to use this for positional trading. Can you please explain how I can use a sell order for positional trading?

Hi Tarun, we cannot short sell equity/stocks.
Try selling futures instead.