Learn Algo Trading with Python | Codes | Youtube Series

While using the packages of Dhan_Tradehull , Dhan_Codebase etc. Is the privacy of user data assured while using those code. Is the execution data, strategy, code & other sensitive data available to Tradehull while using their package etc ? Is it safe ?

1 Like

Closing automatically

Hi @Tradehull_Imran Sir,

made Changes, but today still got error-

Reason - is

RMS:22250319231501:Insufficient Funds, required margin is 193311.75 and available margin 39391. Add Funds to Trade

my new code is-

sl_order_id = tsl.order_placement(option_symbol, 
               "NFO", 
                 client_qty,
                 sl_price - 0.5, 
                 sl_price,
                 "STOPLIMIT", 
                  "SELL", 
                  "MIS")

BTW, are both sl_price and triggr_price mandatory ? It seems like Selling CALL…!! Pls correct the SL Order.

for your information this is the order status -

{'dhanClientId': '110XXXXXXXX0', 'orderId': '22250319231501', 'exchangeOrderId': '0', 'correlationId': '1102350080-1742359314096', 'orderStatus': 'REJECTED', **'transactionType': 'SELL**', 'exchangeSegment': 'NSE_FNO', 'productType': 'INTRADAY', 'orderType': 'STOP_LOSS_MARKET', 'validity': 'DAY', 'tradingSymbol': 'NIFTY-Mar2025-22850-PE', 'securityId': '50218', 'quantity': 75, 'disclosedQuantity': 0, 'price': 0.0, 'triggerPrice': 77.69, 'afterMarketOrder': False, 'boProfitValue': 0.0, 'boStopLossValue': 0.0, 'legName': 'NA', 'createTime': '2025-03-19 10:11:54', 'updateTime': '2025-03-19 10:11:54', 'exchangeTime': '0001-01-01 00:00:00', 'drvExpiryDate': '2025-03-20', **'drvOptionType': 'PUT',** 'drvStrikePrice': 22850.0, 'omsErrorCode': '0', 'omsErrorDescription': 'RMS:22250319231501:Insufficient Funds, required margin is 193311.75 and available margin 39391. Add Funds to Trade', 'algoId': '0', 'remainingQuantity': 75, 'averageTradedPrice': 0.0, 'filledQty': 0}

I am confused, I Simply want to place a Stop loss order after buying atm option. after scrolling back, I found in your reply this -

    sl_orderid        = tsl.order_placement(stock_name,
                                'NSE', 
                                1, 
                                0, 
                                sl_price, 
                                'STOPMARKET', 
                                'SELL', 
                                'MIS')

in your sl order, you have used 0 and i hv used sl_price-0.5 and for trigger price, u hv used sl_price and I too hv used same… I am confused, please explain and tell me exact code to be used…

Where m i going wrong? Pls explain

Have a nice day…
Regards

tsl.cancel_all_orders() is not working now it appears, its not cancelling any open orders

Hi,

if you are using get_intraday_data() method, then its deprecated, instead use get_historical_data() to fetch the data. Also try to use print(your_stockname) so that you will know which stock is generating this error. pls scroll upward to get proper method, Imran Sir had earlier answered on this topic. pls check this link-

HTH,
Regards

Hi @Ganesh_Surwase ,

Refer the below code to place AMO orders:

orderid = tsl.order_placement(tradingsymbol="ACC", exchange="NSE", quantity=1, price=0, trigger_price=0, order_type='MARKET', transaction_type='BUY', trade_type='MIS', after_market_order=True, amo_time='OPEN')

  • tsl.order_placement(tradingsymbol: str, exchange: str, quantity: int, price: int, trigger_price: int, order_type: str, transaction_type: str, trade_type: str, disclosed_quantity=0, after_market_order=False, validity=‘DAY’, amo_time=‘OPEN’, bo_profit_value=None, bo_stop_loss_value=None) → str
  • Arguments:
    • tradingsymbol (str): The trading symbol (e.g., ‘NIFTY 21 NOV 23300 CALL’).
    • exchange (str): The exchange (e.g., ‘NFO’, ‘MCX’, ‘NSE’).
    • quantity (int): The number of contracts to buy/sell.
    • price (int): The price at which to place the order.
    • trigger_price (int): The trigger price for stop orders.
    • order_type (str): Type of order (‘MARKET’, ‘LIMIT’, ‘STOPLIMIT’, ‘STOPMARKET’).
    • transaction_type (str): Type of transaction (‘BUY’ or ‘SELL’).
    • trade_type (str): Type of trade (‘MIS’, ‘MARGIN’, ‘MTF’, ‘CO’, ‘BO’, ‘CNC’).
    • disclosed_quantity (int, optional): Quantity disclosed to the market (default is 0).
    • after_market_order (bool, optional): Whether it is an after-market order (default is False).
    • validity (str, optional): Validity of the order (‘DAY’, ‘IOC’).
    • amo_time (str, optional): AMO time (‘PRE_OPEN’, ‘OPEN’, ‘OPEN_30’, ‘OPEN_60’) if after-market order.

For more details refer the below URL:
Dhan-Tradehull ¡ PyPI

Hi @trader_in_loss ,

Yes, using the Dhan_Tradehull, Dhan_Codebase, and related packages is completely safe. These libraries do not collect, transmit, or store any user data, execution details, strategies, or code.

They function purely as execution tools and do not have any mechanisms to access or extract sensitive information.

1 Like

Hi @Jana_HS ,

The issue may arise because max_risk_for_today exceeds the live PNL, causing the code to break midway.

Hi @anandc ,

Your code seems to be right for STOPLIMIT order, but the order status mentions that the account has in sufficient funds,

{‘dhanClientId’: ‘110XXXXXXXX0’, ‘orderId’: ‘22250319231501’, ‘exchangeOrderId’: ‘0’, ‘correlationId’: ‘1102350080-1742359314096’, ‘orderStatus’: ‘REJECTED’, ‘transactionType’: 'SELL’, ‘exchangeSegment’: ‘NSE_FNO’, ‘productType’: ‘INTRADAY’, ‘orderType’: ‘STOP_LOSS_MARKET’, ‘validity’: ‘DAY’, ‘tradingSymbol’: ‘NIFTY-Mar2025-22850-PE’, ‘securityId’: ‘50218’, ‘quantity’: 75, ‘disclosedQuantity’: 0, ‘price’: 0.0, ‘triggerPrice’: 77.69, ‘afterMarketOrder’: False, ‘boProfitValue’: 0.0, ‘boStopLossValue’: 0.0, ‘legName’: ‘NA’, ‘createTime’: ‘2025-03-19 10:11:54’, ‘updateTime’: ‘2025-03-19 10:11:54’, ‘exchangeTime’: ‘0001-01-01 00:00:00’, ‘drvExpiryDate’: ‘2025-03-20’, ‘drvOptionType’: ‘PUT’, ‘drvStrikePrice’: 22850.0, ‘omsErrorCode’: ‘0’, ‘omsErrorDescription’: ‘RMS:22250319231501:Insufficient Funds, required margin is 193311.75 and available margin 39391. Add Funds to Trade’, ‘algoId’: ‘0’, ‘remainingQuantity’: 75, ‘averageTradedPrice’: 0.0, ‘filledQty’: 0}

Hi @Msk92 ,

Kindly use the updated codebase version 3.0.6.

  • Open Command Prompt: Press Win, type cmd, and press Enter.
  • Install Dhan-Tradehull: Run pip install Dhan-Tradehull
  • Confirm the installation by running pip show Dhan-Tradehull

Guide to use the updated codebase:
Video reference :

Refer the below pypi link for more details:
https://pypi.org/project/Dhan-Tradehull/

Hi @Tradehull_Imran SIR,

I have 40K, out of which, say I bought put at 100 rs then 7500 will get minus from account, still balance will be 32500, so do placing stop loss need margin …? Also, my sl_Price is 20% of buy price, which means 80 will be my sl level, so 80*75=6000, which is very less than my balance… !!! then why insufficient fund?

Sir, Kuch to gadbad hain, jo mujhe samaz nahi aa rahi hain…

Doesn’t seem to work

-----Logged into Dhan-----
reading existing file all_instrument 2025-03-19.csv
Got the instrument file
Exception in Getting OHLC data as ‘int’ object has no attribute ‘upper’
Traceback (most recent call last):
File “Screener 1.py”, line 18, in
chart[‘rsi’] = talib.RSI(chart[“close”], timeperiod=14)
TypeError: ‘NoneType’ object is not subscriptable

C:\Users\Ajay Singh Rajput\Downloads\6. Session6- 1st Live Algo\6. Session6- 1st Live Algo\1st live Algo>


watchlist = ["SHRIRAMFIN", "HDFCBANK","COALINDIA","TRENT","HINDALCO","AXISBANK","ADANIENT","ADANIPORTS","GRASIM","RELIANCE","DRREDDY","TATASTEEL","LT","ITC","HchartCLIFE","ASIANPAINT","HEROMOTOCO","NTPC","APOLLOHOSP","POWERGRID","ICICIBANK","BAJFINANCE","SBIN","BEL","JSWSTEEL","HINDUNILVR","ONGC","CIPLA","KOTAKBANK","EICHERMOT","SBILIFE","BPCL","BAJAJFINSV","HCLTECH","ULTRACEMCO","MARUTI","SUNPHARMA","NESTLEIND","TCS","BAJAJ-AUTO","BRITANNIA","INFY","TATACONSUM","TITAN","TATAMOTORS","M&M","BHARTIARTL","WIPRO","TECHM","INDUSINDBK",]

for stock in watchlist:

	chart = tsl.get_historical_data(stock, 'NSE', 5)

	chart['rsi'] = talib.RSI(chart['close'], timeperiod=14)
	
	lcc  = chart.iloc[-2] 

	uptrend   = lcc['rsi'] > 60
	downtrend = lcc['rsi']  < 30

	if uptrend:
		print(stock, "is in uptrend")

	if downtrend:
		print(stock, "is in downtrend")

Dear @RahulDeshpande @Tradehull_Imran,

I’ve been following your “ALGO TRADING WITH PYTHON” series and really enjoying the content. However, I noticed that it has been over five months and the series is still incomplete.

I completely understand that creating quality content takes time, but I (and many others) am eagerly waiting for the back-testing videos. Would it be possible to upload more frequently?

Thanks for all the hard work you put into your content—I really appreciate it!

Thanks

1 Like

@Tradehull_Imran Dear Sir, I just wanted to take a moment to sincerely thank you for your invaluable guidance and support in teaching us automated trading using Python. Your in-depth knowledge, clear explanations, and practical insights have made learning this complex topic both engaging and insightful.

The skills you’ve shared will undoubtedly help me in my trading journey. I truly appreciate the effort you put into making each session informative and interactive.

Once again, thank you for your mentorship and for making this learning experience so rewarding. I look forward to applying what I’ve learned and continuing to grow in this field.

Sir, I require assistance with my order execution algorithm, as I am experiencing difficulties.
I have developed an Index Scanner Algo and Order execution Algo, the scanner is working efficiently. The scanner updates key trading parameters such as strike price, entry price, target price, and stop-loss (SL) price in an Excel file. Additionally, the Excel file incorporates automation using VBA to update buy condition, sl trigger price, lock profit, initial tsl, final tsl, exit status and exchange.

However, there are some issues with the order execution algo:

  • Sometimes, the stop-loss (SL) order is not placed as expected.
  • Occasionally, SL order modifications do not work properly, leading to execution errors.

I have attached my excel sheet and code, please help me to structure the code properly into a well-organized framework.

Code_______
import pdb
import time
import talib
import logging
import datetime
import traceback
import pandas as pd
import xlwings as xw
import logging # LOGGING ADDED
from pprint import pprint
from Dhan_Tradehull import Tradehull

Configure logging # LOGGING ADDED

log_handler = logging.FileHandler(“trade_log.log”, mode=“a”, encoding=“utf-8”) # Set encoding explicitly
log_handler.setFormatter(logging.Formatter(“%(asctime)s - %(levelname)s - %(message)s”))

logger = logging.getLogger()
logger.setLevel(logging.INFO)
logger.addHandler(log_handler)

def log_and_print(message, level=“info”):
“”“Logs and prints messages simultaneously.”“”
print(message)
if level == “info”:
logger.info(message)
elif level == “warning”:
logger.warning(message)
elif level == “error”:
logger.error(message)
elif level == “critical”:
logger.critical(message)

Client details for Dhan API

client_code = “xxxxxxxxxxxx”
token_id = “xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx”
tsl = Tradehull(client_code, token_id)

wb = xw.Book(‘00. Trade_Details.xlsm’)
Live_Trading = wb.sheets[‘Live_Trading’]
Orderbook = wb.sheets[‘Orderbook’]

previous_sl_prices = {}
order_entry_time = {}
trade_count = 0
trade_pnl =

Live_Trading.range(“A2:H1000”).value = None
Live_Trading.range(“J2:K1000”).value = None
Live_Trading.range(“M2:R1000”).value = None
Live_Trading.range(“T2:X1000”).value = None

log_and_print(“Trading script started”) # LOGGING ADDED

while True:
try:
watchlist = Live_Trading.range(‘B2’).expand(‘down’).value
if watchlist is None:
log_and_print(“Watchlist is empty. Retrying…”, “warning”) # LOGGING ADDED
time.sleep(1)
continue

    if isinstance(watchlist, str):
        watchlist = [watchlist]

    current_time = datetime.datetime.now()

    # Fetch LTP for all scripts
    try:
        ltp_for_all_scripts = tsl.get_ltp_data(names=watchlist)  # UPDATED LOGIC
    except Exception as e:
        log_and_print(f"Error fetching LTP data: {e}", "error")  # LOGGING ADDED
        continue

    for row_no, name in enumerate(watchlist, start=2):  # UPDATED LOGIC - Loop through all rows
        try:
            if name is None:
                log_and_print(f"Skipping None value in row {row_no}.", "warning")  # LOGGING ADDED
                continue

            p_column_value = Live_Trading.range(f'P{row_no}').value  # UPDATED LOGIC
            if p_column_value is not None and p_column_value != "":  # UPDATED LOGIC - Skip rows where P is not blank
                # log_and_print(f"Skipping row {row_no} as column P is not blank.", "info")  # LOGGING ADDED
                continue

            ltp = ltp_for_all_scripts.get(name)
            if ltp is None:
                log_and_print(f"Skipping {name}: LTP not found.", "warning")  # LOGGING ADDED
                continue
            
            log_and_print(f"Updating LTP: {name} LTP:{ltp}")  # LOGGING ADDED
            Live_Trading.range(f'G{row_no}').value = ltp  # UPDATED LOGIC - Update LTP for each row

            # Proceed with the existing trade logic for each row
            is_this_script_traded = Live_Trading.range(f'J{row_no}').value
            buy_cell_value = Live_Trading.range(f'H{row_no}').value

            if is_this_script_traded is not None:
                buy_order_status = tsl.get_order_status(is_this_script_traded)
                Live_Trading.range(f'Q{row_no}').value = buy_order_status
                log_and_print(f"Order {is_this_script_traded} status: {buy_order_status}")  # LOGGING ADDED

                if buy_order_status == "PENDING":
                    if name in order_entry_time:
                        elapsed_time = (current_time - order_entry_time[name]).total_seconds() / 60
                        if elapsed_time > 4:
                            log_and_print(f"Cancelling buy order for {name} after 5 minutes.", "warning")  # LOGGING ADDED
                            tsl.cancel_order(is_this_script_traded)
                            Live_Trading.range(f'J{row_no}').value = None
                            del order_entry_time[name]
                    else:
                            order_entry_time[name] = current_time  

            if buy_cell_value == "BUY" and is_this_script_traded is None and trade_count < 3:
                if trade_count == 2 and len(trade_pnl) >= 2 and trade_pnl[0] < 0 and trade_pnl[1] < 0:
                    log_and_print("Skipping third trade due to previous losses.", "info")  # LOGGING ADDED
                    continue

                quantity = tsl.get_lot_size(name)
                Live_Trading.range(f'X{row_no}').value = quantity
                sl_trigger_price = Live_Trading.range(f'I{row_no}').value
                entry_price = Live_Trading.range(f'C{row_no}').value
                sl_price = Live_Trading.range(f'N{row_no}').value
                exch = Live_Trading.range(f'Y{row_no}').value
                margin_available = tsl.get_balance()
                margin_required  = entry_price * quantity

                if margin_available < margin_required + 50:
                    continue

                entry_orderid = tsl.order_placement(
                    tradingsymbol=name, exchange=exch, quantity=quantity,
                    price=entry_price, trigger_price=0,
                    order_type='LIMIT', transaction_type='BUY', trade_type='MIS'
                )
                log_and_print(f"Buy order placed: {name} at {entry_price}")  # LOGGING ADDED

                if entry_orderid:
                    Live_Trading.range(f'J{row_no}').value = entry_orderid
                    trade_count += 1
                    order_entry_time[name] = current_time  

                buy_order_status = tsl.get_order_status(entry_orderid)
                Live_Trading.range(f'Q{row_no}').value = buy_order_status
                log_and_print(f"Buy order status: {buy_order_status}")  # LOGGING ADDED
                # aa=Live_Trading.range(f'K{row_no}').value
                # print(aa)
            if entry_orderid is not None and Live_Trading.range(f'K{row_no}').value is None and buy_order_status == "TRADED":

                sl_orderid = tsl.order_placement(
                    tradingsymbol=name, exchange=exch, quantity=quantity,
                    price=sl_price, trigger_price=sl_trigger_price,
                    order_type='STOPLIMIT', transaction_type='SELL', trade_type='MIS'
                )
                log_and_print(f"SL order placed: {name} at {sl_price}")  # LOGGING ADDED
                Live_Trading.range(f'K{row_no}').value = sl_orderid
                previous_sl_prices[name] = sl_price

            new_sl_price = Live_Trading.range(f'N{row_no}').value
            if name in previous_sl_prices and previous_sl_prices[name] != new_sl_price:
                log_and_print(f"SL changed: {name} {previous_sl_prices[name]} → {new_sl_price}")  # LOGGING ADDED
                modify_status = tsl.modify_order(
                    order_id=sl_orderid,
                    order_type="STOPLIMIT",
                    quantity=quantity,
                    price=new_sl_price,
                    trigger_price=new_sl_price + 0.1,
                    disclosed_quantity=0,
                    validity="DAY"
                )
                if modify_status:
                    previous_sl_prices[name] = new_sl_price
        except Exception as e:
            log_and_print(f"Error processing {name}: {e}", "error")  # LOGGING ADDED
            traceback.print_exc()
            continue

except Exception as e:
    log_and_print(f"Unexpected error: {e}", "critical")  # LOGGING ADDED
    traceback.print_exc()

time.sleep(1)

sir,
i tried to run loop to fetch daily historical data(time frame DAY) by below listed coding

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 datetime

client_code = “”
token_id = “”
tsl = Tradehull(client_code,token_id)

watchlist = [“INDUSINDBK”,“TATAMOTORS”,“ULTRACEMCO”,“POWERGRID”,“TATASTEEL”,“BAJAJFINSV”,“JSWSTEEL”,“SUNPHARMA”,“ICICIBANK”,“COALINDIA”,“GRASIM”,“ONGC”,“SBILIFE”,“BEL”,“NTPC”,“ITC”,“TECHM”,“SBIN”,“HINDALCO”,“AXISBANK”,“LT”,“MARUTI”,“HDFCLIFE”,“DRREDDY”,“WIPRO”,“TRENT”,“TATACONSUM”,“BAJAJ-AUTO”,“HDFCBANK”,“CIPLA”,“BAJFINANCE”,“KOTAKBANK”,“M&M”,“ADANIPORTS”,“HCLTECH”,“RELIANCE”,“TCS”,“HINDUNILVR”,“NESTLEIND”,“TITAN”,“ADANIENT”,“SHRIRAMFIN”,“ASIANPAINT”,“HEROMOTOCO”,“BHARTIARTL”,“BPCL”,“EICHERMOT”,“APOLLOHOSP”,“INFY”,“BRITANNIA”]
for name in watchlist:
#print(name)
daily_data = tsl.get_historical_data(tradingsymbol= name,exchange=‘NSE’,timeframe=“DAY”)

Am trying to trade the Nifty ATM Strikes of next week (27 Mar) expiry . But the data is fetching for Nifty ATM Strikes only but its showing as FinNifty. Even the Python code is referring for Nifty only. Is there any glitch on DHAN API.

Hi @anandc ,

There is an API call in Dhan TradeHull codebase… which can fetch margin required to place an order.

margin = tsl.margin_calculator(tradingsymbol='NIFTY 19 DEC 24400 CALL', exchange='NFO', transaction_type='BUY', quantity=25, trade_type='MARGIN', price=43, trigger_price=0)

Also you can check the available balance in your account;

tsl.get_balance()

Hi @Ajay_Singh_Rajput ,

The code seems to be right, make sure you have subscribed to the data API.

Hi @iamsanjay ,

Can you elaborate your issue?

Hi @Mahikbs ,

Use the below code to fetch ATM strikes of next week.

CE_symbol_name, PE_symbol_name, atm_strike = tsl.ATM_Strike_Selection(Underlying='NIFTY', Expiry=1)