Learn Algo Trading with Python | Codes | Youtube Series

@Tradehull_Imran Suppose I placed a Sell order in MIS (Intraday) and now I have an open position. To close this position, do I need to place a Buy order with the same quantity, or is there another method?

Additionally, if I have an open position, how can I set a Stop Loss (SL) or Take Profit (TP) for it?

NEW ORDER WILL BE CREATED FOR ‘Stop Loss (SL)’ AND U CAN MODIFY IT FOR Take ‘Profit (TP)’

FOR STOP LOSS
stoploss_orderid = tsl.order_placement(trading_symbol, "NFO", qty, sl_limit_price, stop_loss_price, 'STOPLIMIT', 'BUY', 'MIS')

FOR PROFIT BOOKING
if current_market_price >= target_price:
                tsl.modify_order(order_id=stoploss_orderid, order_type="MARKET", quantity=qty, price=0, trigger_price=0)
1 Like

SIR @Tradehull_Imran , JUST CHECK HOW IT IS, ANY FLAWS IF YOU FIND
I HAVE MADE IT FOR SINGLE ORDER MANAGEMENT (STATIC)
ONCE ORDER IS PLACED IF WENT BELOW SL BEFORE EXECUTION IT WILL CANCEL ORDER, IF EXECUTED IT WILL PLACE SL ORDER AND IF TARGET REACHED IT MODIFY TO MARKET FOR BOOKING PROFIT, IF SL ORDER SKIPS IT WILL MODIFY SL-LIMIT TO MARKET FOR SAFETY.

import tkinter as tk
from tkinter import messagebox
import time
import traceback
import threading
from queue import Queue
from Dhan_Tradehull_V2 import Tradehull
import logging
import os
import winsound

# Logging Setup
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', filename='trade_execution.log', filemode='a')

# Client Credentials (ensure these are securely stored and retrieved)
CLIENT_CODE = os.getenv("CLIENT_CODE", "1100578034")
TOKEN_ID = os.getenv("TOKEN_ID", 

# Initialize Tradehull
tsl = Tradehull(CLIENT_CODE, TOKEN_ID)

# Telegram Credentials
bot_token = "000000"
receiver_chat_id = "0000000"

# Send login confirmation to Telegram
try:
    tsl.send_telegram_alert(message="Login Done Successfully", receiver_chat_id=receiver_chat_id, bot_token=bot_token)
except Exception as e:
    logging.error(f"Failed to send Telegram login confirmation: {e}")

# Tkinter Root Window
root = tk.Tk()
root.title("Trading Strategy GUI")
root.geometry("400x400")

# Tkinter Variables
trading_symbol_var = tk.StringVar(value="NIFTY 06 MAR 22200 PUT")
qty_var = tk.IntVar(value=75)
buying_trigger_var = tk.DoubleVar(value=270.35)
stop_loss_offset_var = tk.DoubleVar(value=245.95)
target_offset_var = tk.DoubleVar(value=35.0)
profit_lock_point_var = tk.DoubleVar(value=29.0)
sltrail_var = tk.DoubleVar(value=1.0)

# Log queue for updating UI
log_queue = []

def play_sound(frequency, duration, repeat=1, pause=0.2):
     for _ in range(repeat):
        winsound.Beep(frequency, duration)
        time.sleep(pause)

def log_message(msg):
    log_queue.append(msg)
    log_text.insert(tk.END, msg + "\n")
    log_text.see(tk.END)
    try:
        tsl.send_telegram_alert(message=msg, receiver_chat_id=receiver_chat_id, bot_token=bot_token)
    except Exception as e:
        logging.error(f"Failed to send Telegram alert: {e}")

def execute_order():
    order_thread = threading.Thread(target=execute_order_thread_function)
    order_thread.start()

def execute_order_thread_function():
    trading_symbol = trading_symbol_var.get()
    qty = qty_var.get()
    buying_trigger = buying_trigger_var.get()
    stop_loss_offset = stop_loss_offset_var.get()
    target_offset = target_offset_var.get()
    profit_lock_point = profit_lock_point_var.get()
    try:
        log_message(f"Placing buy order for {trading_symbol}...")
        buy_entry_orderid = tsl.order_placement(trading_symbol, "NFO", qty, buying_trigger + 0.50, buying_trigger, "STOPLIMIT", 'BUY', 'MIS')
        log_message(f"Buy Order Placed. Order ID: {buy_entry_orderid}")
        message = (f"Buy Order Placed. Order ID: {buy_entry_orderid}")
        time.sleep(0.2)

        while True:
            order_status = tsl.get_order_status(orderid=buy_entry_orderid)
            log_message(f"Order Status: {order_status}")
            time.sleep(1)

            if order_status == "PENDING":
                current_market_price_dict = tsl.get_ltp_data(names=[trading_symbol])
                current_market_price = current_market_price_dict[trading_symbol]

                if current_market_price <= stop_loss_offset:
                    log_message(f"Market price {current_market_price} is below stop-loss offset. Canceling order.")
                    tsl.Dhan.cancel_order(buy_entry_orderid)
                    break

            elif order_status == "TRADED":
               manage_trade_logic(trading_symbol, qty, buying_trigger, target_offset, stop_loss_offset, profit_lock_point)
               break
    except Exception as e:
        log_message(f"Error during order execution: {traceback.format_exc()}")


def manage_trade_logic(stoploss_orderid, trading_symbol, qty, buy_price, target_offset, stop_loss_offset, profit_lock_point):
    try:
        target_price = buy_price + target_offset
        stop_loss_price = buy_price - stop_loss_offset
        sl_limit_price = stop_loss_price - 1

        stoploss_orderid = tsl.order_placement(trading_symbol, "NFO", qty, sl_limit_price, stop_loss_price, 'STOPLIMIT', 'SELL', 'MIS')
        log_message(f"Initial Stop Loss Order Placed. Order ID: {stoploss_orderid}")
        play_sound(3468, 300, 2, 0.1)
        time.sleep(0.2)

        profit_locked = False
        last_sl_price = stop_loss_price
        last_trail_price = buy_price + profit_lock_point

        while True:
            current_market_price_dict = tsl.get_ltp_data(names=[trading_symbol])
            current_market_price = current_market_price_dict[trading_symbol]

            if current_market_price >= target_price:
                tsl.modify_order(order_id=stoploss_orderid, order_type="MARKET", quantity=qty, price=0, trigger_price=0)
                log_message(f"Target reached. Selling at market price.")
                play_sound(3468, 300, 3, 0.1)
                break

            if current_market_price < sl_limit_price:
                tsl.modify_order(order_id=stoploss_orderid, order_type="MARKET", quantity=qty, price=0, trigger_price=0)
                log_message("Stop-loss limit skipped, modifying to market order.")
                break

            if not profit_locked and current_market_price >= (buy_price + profit_lock_point):
                profit_locked = True
                last_sl_price = buy_price + profit_lock_point
                tsl.modify_order(order_id=stoploss_orderid, order_type="STOPLIMIT", quantity=qty, price=last_sl_price - 1, trigger_price=last_sl_price)
                log_message(f"Profit locked. Stop Loss set to ₹{last_sl_price}.")
                play_sound(3468, 300, 5, 0.1)

            elif profit_locked and current_market_price >= last_trail_price + sltrail_var.get():
                last_trail_price += sltrail_var.get()
                last_sl_price = last_trail_price
                tsl.modify_order(order_id=stoploss_orderid, order_type="STOPLIMIT", quantity=qty, price=last_sl_price - 1, trigger_price=last_sl_price)
                log_message(f"Trailing Stop Loss updated to ₹{last_sl_price}.")
                play_sound(3468, 300, 1, 0.1)

            time.sleep(0.2)
    except Exception as e:
        log_message(f"Error in trade management: {traceback.format_exc()}")

# GUI Layout
tk.Label(root, text="Trading Symbol:").grid(row=0, column=0, padx=5, pady=5, sticky="e")
tk.Entry(root, textvariable=trading_symbol_var, width=25).grid(row=0, column=1, padx=5, pady=5)

tk.Label(root, text="Quantity:").grid(row=1, column=0, padx=5, pady=5, sticky="e")
qty_dropdown = tk.OptionMenu(root, qty_var, *[75, 150, 225, 300, 375, 450, 525, 600, 675, 750, 825, 900])
qty_dropdown.grid(row=1, column=1, padx=5, pady=5)

tk.Label(root, text="Buying Trigger Price:").grid(row=2, column=0, padx=5, pady=5, sticky="e")
tk.Entry(root, textvariable=buying_trigger_var, width=25).grid(row=2, column=1, padx=5, pady=5)

tk.Label(root, text="Stop Loss Offset:").grid(row=3, column=0, padx=5, pady=5, sticky="e")
tk.Entry(root, textvariable=stop_loss_offset_var, width=25).grid(row=3, column=1, padx=5, pady=5)

tk.Label(root, text="Target Offset:").grid(row=4, column=0, padx=5, pady=5, sticky="e")
tk.Entry(root, textvariable=target_offset_var, width=25).grid(row=4, column=1, padx=5, pady=5)

tk.Label(root, text="Profit Lock At:").grid(row=5, column=0, padx=5, pady=5, sticky="e")
tk.Entry(root, textvariable=profit_lock_point_var, width=25).grid(row=5, column=1, padx=5, pady=5)

tk.Label(root, text="SL Trail Step:").grid(row=6, column=0, padx=5, pady=5, sticky="e")
tk.Entry(root, textvariable=sltrail_var, width=25).grid(row=6, column=1, padx=5, pady=5)

tk.Button(root, text="Login", command=lambda: threading.Thread(target=lambda: log_message("Login Triggered")).start()).grid(row=7, column=0, padx=5, pady=5)
tk.Button(root, text="Execute Order", command=execute_order).grid(row=7, column=1, padx=5, pady=5)

# Log Display
log_text = tk.Text(root, height=10, width=50)
log_text.grid(row=8, column=0, columnspan=2, padx=5, pady=5)

# Run the Tkinter Main Loop
root.mainloop()

tsl.get_order_detail() Fetches you entire dictionary, which is good for overview,
but if you want a specific information, you might wanna, slice a specific value of dict.

Better just stick to the get_order_status which will fetch you the status

status = self.get_order_status(order_id=stop_loss_order_id)
in return you will get, one of these options
TRANSIT, PENDING, REJECTED, CANCELLED, TRADED, EXPIRED

only if the status is TRADED, you will find more about it not in orders, but in Positions
by self.get_positions()

to my best knowledge, maybe sir can confirm this ? @Tradehull_Imran

1 Like

@Tradehull_Imran
sir, how to implement “fair value gap” strategy… Pls. Help to making this algo code…pls.pls.pls.give complete code

2 Likes

Hi @Tradehull_Imran,
How can we calculate historical data for higher time frames like Weekly, Monthly etc?

Hi @rahulcse56,
Imran has already explained performance optimisation tips in this video.
URL: https://www.youtube.com/watch?v=PLnM8kCE8uc

Instead of fetching LTP one by one. You can create a watchlist and fetch LTP for all stocks in watchlist in single request.

@Tradehull_Imran
Thank you for creating great content on Algo Trading. I have already started following your Advance Algo trading series and started using Dhan-TradeHull python codebase library.

I have couple of points to add/ask:

  1. Currently if I execute the code then it downloads the dependencies every time. Even if I run the code on same day. Can you please update the logic to may be check if file for same day is already exist then don’t redownload it. Otherwise download it. This will save lot of initial time when we re-execute the code.

  2. I am using MAC-OS for building my Algo and in 3rd sessions you have covered topic using Excel which is difficult to implement on Mac. Can you please provide alternative option for mac users?

Hi @Tradehull_Imran Sir,
can you give me the code to place an OCO order?

Have a nice day
Regards


I’m getting this error, can somebody please help?

HCLTECH
Traceback (most recent call last):
File “D:\DATA\Documents\DHAN\8. Session8- 2nd Live Algo\8. Session 8 Dhan_Tradehull_V2\Dhan_Tradehull_V2.py”, line 139, in order_placement
orderid = order[“data”][“orderId”]
KeyError: ‘orderId’
Traceback (most recent call last):
File “D:\DATA\Documents\DHAN\8. Session8- 2nd Live Algo\8. Session 8 Dhan_Tradehull_V2\Dhan_Tradehull_V2.py”, line 139, in order_placement
orderid = order[“data”][“orderId”]
KeyError: ‘orderId’

Advanced Algo Trading Series | Episode 4: Framework of Live Algo | Dhan

2 Likes

Thanks Siddhesh. I am doing the same in algo… fetching LTP for all shortlisted stocks in a single request.

1 Like

HI @Tradehull_Imran sir, @Dhan

Today I was working with NIFTY, the 1 min data fetched was totally wrong, pls see the image below-

NIFTY at 4 digits, is it a special DHAN exchange where NIFTY IS trading at this level. OR is it a kind of joke…!!! See many peoples are relying on you for their algos. are you fooling them with such kinda data? Before this at least 2 times i have seen FINNIFTY ATM options instead of NIFTY… then you show exactly the correct data, but what about the problem at that moment when we fetch and get such wrong data…

Ab to algo ke galat hone se darr nahi lagta DHAN ke data se Darr lagne laga hain…

Data accuracy bhi koi chidiya hain …
Bahut majak kar liye… Now be serious aisa rahan to DHAN change karna padega…
ab to saala roj utho algo run karo aur galat data dekho…trd mis karo upar se 495+gst har mahine do aur galat data fedd ke maje lo…

to sum up-

  1. daily koi naya locha ho to samjh mein aata hain yahan to repeated wohi roj ho rahan hain…
  2. mental harassment, woh alag
  3. trades mis hote hain
  4. Abhi tak API ka sahi doumentation nahi hain…
2 Likes

@Tradehull_Imran @Hardik please explain this error why am i not getting my P AND L

ERROR:root:got exception in pnl as Failed to get pnl data
Traceback (most recent call last):
File “/usr/local/lib/python3.11/dist-packages/Dhan_Tradehull/Dhan_Tradehull.py”, line 342, in get_live_pnl
raise Exception(“Failed to get pnl data”)
Exception: Failed to get pnl data

got exception in pnl as Failed to get pnl data
Failed to get PnL data: 0
<Dhan_Tradehull.Dhan_Tradehull.Tradehull object at 0x788aabbc6ed0> PnL: None

Hi @Tradehull_Imran ,

How to fetch the weightage of HDFCBANK, ICICIBANK in Nifty50 …?

because it keeps on rebalancing…

Also,
Dhan Nifty 50 weightage of HDFCBANK, ICICIBANK, RELIANCE does not match with the NSE data: NSE Nifty 50 and Weightages

Please help me out.
TIA :slightly_smiling_face:

Really good question. Weightages are part of fundamental statistics and I don’t think Dhan is providing any kind of fundamental statistics through API.
To achieve this you can try workaround as add extra column in your excel or separate tab for managing Fundamental details and then fetch this information in your logic.
You can update this information manually on periodic basis like monthly or quarterly as it will not change frequently.

@Tradehull_Imran Please share more details on getting fundamental data programmatically.
e.g. market cap, PE, revenue, promotor holding, etc

Hi @Mahikbs ,

Do use the below code to fetch the historical data for NIFTY,

data = tsl.get_historical_data(tradingsymbol='NIFTY', exchange='INDEX', timeframe="1")

If you still facing issues, kindly share your code to review the same.

Hi @Dhananjay_Umalkar ,

Yes, it is correct.

Hi @Dev_Goswami ,

Data may vary slightly between brokers and trading platforms. The data provided by the Dhan API accurately aligns with Dhan’s charts.

Hi @Dev_Goswami ,

  1. Yes we need to place a BUY order with same quantity in MIS(Intraday) .
  2. If you have an open position, set the stop-loss price and place a stop-loss order accordingly, or set a target price and continuously monitor its status.
sl_hit    = tsl.get_order_status(orderid=orderbook[name]['sl_orderid']) == "TRADED" # for stoploss order
tg_hit    = ltp > orderbook[name]['tg'] # for target 

Below is the reference code for the tested framework:


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 winsound



client_code = "1102790337"
token_id    = "bhgvsaoieqhjvhg"
tsl         = Tradehull(client_code,token_id)



watchlist = ['BEL', 'BOSCHLTD', 'COLPAL', 'HCLTECH', 'HDFCBANK', 'HAVELLS', 'HAL', 'ITC', 'IRCTC', 'INFY', 'LTIM', 'MARICO', 'MARUTI', 'NESTLEIND', 'PIDILITIND', 'TCS', 'TECHM', 'WIPRO']




single_order     = {'name':None, 'date':None , 'entry_time': None, 'entry_price': None, 'buy_sell': None, 'qty': None, 'sl': None, 'exit_time': None, 'exit_price': None, 'pnl': None, 'remark': None, 'traded':None}
orderbook        = {}
wb               = xw.Book('Live Trade Data.xlsx')
live_Trading     = wb.sheets['Live_Trading']
completed_orders_sheet = wb.sheets['completed_orders']
reentry          = "yes" #"yes/no"
completed_orders = []


bot_token        = "8059847390:AAECSnQK-yOaGJ-clJchb1cx8CDhx2VQq-M"
receiver_chat_id = "1918451082"


live_Trading.range("A2:Z100").value = None
completed_orders_sheet.range("A2:Z100").value = None

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



while True:

	print("starting while Loop \n\n")

	current_time = datetime.datetime.now().time()
	if current_time < datetime.time(13, 55):
		print(f"Wait for market to start", current_time)
		time.sleep(1)
		continue

	if current_time > datetime.time(15, 15):
		order_details = tsl.cancel_all_orders()
		print(f"Market over Closing all trades !! Bye Bye See you Tomorrow", current_time)
		pdb.set_trace()
		break


	all_ltp = tsl.get_ltp_data(names = watchlist)
	for name in watchlist:


		orderbook_df                       = pd.DataFrame(orderbook).T
		live_Trading.range('A1').value     = orderbook_df

		completed_orders_df                =  pd.DataFrame(completed_orders)
		completed_orders_sheet.range('A1').value = completed_orders_df


		current_time          = datetime.datetime.now()
		print(f"Scanning        {name} {current_time}")




		try:
			chart                 = tsl.get_historical_data(tradingsymbol = name,exchange = 'NSE',timeframe="5")
			chart['rsi']          = talib.RSI(chart['close'], timeperiod=14)
			cc  = chart.iloc[-2]

			# buy entry conditions
			bc1 = cc['rsi'] > 45
			bc2 = orderbook[name]['traded'] is None
		except Exception as e:
			print(e)
			continue



		if bc1 and bc2:
			print("buy ", name, "\t")

			margin_avialable = tsl.get_balance()
			margin_required  = cc['close']/4.5

			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}")
				continue


			orderbook[name]['name']           = name
			orderbook[name]['date']           = str(current_time.date())
			orderbook[name]['entry_time']     = str(current_time.time())[:8]
			orderbook[name]['buy_sell']       = "BUY"
			orderbook[name]['qty']            = 1


			try:
				entry_orderid                     = tsl.order_placement(tradingsymbol=name ,exchange='NSE', quantity=orderbook[name]['qty'], price=0, trigger_price=0,    order_type='MARKET',     transaction_type='BUY',   trade_type='MIS')
				orderbook[name]['entry_orderid']  = entry_orderid
				orderbook[name]['entry_price']    = tsl.get_executed_price(orderid=orderbook[name]['entry_orderid'])

				orderbook[name]['tg']             = round(orderbook[name]['entry_price']*1.002, 1)   # 1.01
				orderbook[name]['sl']             = round(orderbook[name]['entry_price']*0.998, 1)    # 99
				sl_orderid                        = tsl.order_placement(tradingsymbol=name ,exchange='NSE', quantity=orderbook[name]['qty'], price=0, trigger_price=orderbook[name]['sl'], order_type='STOPMARKET', transaction_type ='SELL', trade_type='MIS')
				orderbook[name]['sl_orderid']     = sl_orderid
				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(e)
				pdb.set_trace(header= "error in entry order")





		if orderbook[name]['traded'] == "yes":
			bought = orderbook[name]['buy_sell'] == "BUY"

			if bought:

				try:
					ltp       = all_ltp[name]
					sl_hit    = tsl.get_order_status(orderid=orderbook[name]['sl_orderid']) == "TRADED"
					tg_hit    = ltp > orderbook[name]['tg']
				except Exception as e:
					print(e)
					pdb.set_trace(header = "error in sl order cheking")



				if sl_hit:

					try:
						orderbook[name]['exit_time']  = str(current_time.time())[:8]
						orderbook[name]['exit_price'] = tsl.get_executed_price(orderid=orderbook[name]['sl_orderid'])
						orderbook[name]['pnl']        = round((orderbook[name]['exit_price'] - orderbook[name]['entry_price'])*orderbook[name]['qty'],1)
						orderbook[name]['remark']     = "Bought_SL_hit"

						message = "\n".join(f"'{key}': {repr(value)}" for key, value in orderbook[name].items())
						message = f"SL_HIT {name} \n\n {message}"
						tsl.send_telegram_alert(message=message,receiver_chat_id=receiver_chat_id,bot_token=bot_token)



						if reentry == "yes":
							completed_orders.append(orderbook[name])
							orderbook[name] = None
					except Exception as e:
						print(e)
						pdb.set_trace(header = "error in sl_hit")



				if tg_hit:

					try:
						tsl.cancel_order(OrderID=orderbook[name]['sl_orderid'])
						time.sleep(2)
						square_off_buy_order          = tsl.order_placement(tradingsymbol=orderbook[name]['name'] ,exchange='NSE', quantity=orderbook[name]['qty'], price=0, trigger_price=0,    order_type='MARKET',     transaction_type='SELL',   trade_type='MIS')

						orderbook[name]['exit_time']  = str(current_time.time())[:8]
						orderbook[name]['exit_price'] = tsl.get_executed_price(orderid=square_off_buy_order)
						orderbook[name]['pnl']        = (orderbook[name]['exit_price'] - orderbook[name]['entry_price'])*orderbook[name]['qty']
						orderbook[name]['remark']     = "Bought_TG_hit"

						message = "\n".join(f"'{key}': {repr(value)}" for key, value in orderbook[name].items())
						message = f"TG_HIT {name} \n\n {message}"
						tsl.send_telegram_alert(message=message,receiver_chat_id=receiver_chat_id,bot_token=bot_token)


						if reentry == "yes":
							completed_orders.append(orderbook[name])
							orderbook[name] = None

						winsound.Beep(1500, 10000)

					except Exception as e:
						print(e)
						pdb.set_trace(header = "error in tg_hit")