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.
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.
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.