Learn Algo Trading with Python | Codes | Youtube Series

do we require Data API token by paying 500 everymonth only then excel will work?

first of all note that 500p.m. is for data fetching and excel if u are taking about in relation to websocket, imran has already told 1000 times that wesocket is difficult to implement so go for historical candle option with xlswriter u can see them in excel

{‘dhanClientId’: ‘XXXXXXXX’, ‘orderId’: ‘12250731126020’, ‘exchangeOrderId’: ‘1900000036653284’, ‘correlationId’: ‘110
1309119-1753936236168’, ‘orderStatus’: ‘REJECTED’, ‘transactionType’: ‘SELL’, ‘exchangeSegment’: ‘NSE_FNO’, 'productType
': ‘INTRADAY’, ‘orderType’: ‘STOP_LOSS’, ‘validity’: ‘DAY’, ‘tradingSymbol’: ‘BANKNIFTY-Jul2025-55800-PE’, ‘securityId’:
‘54062’, ‘quantity’: 35, ‘disclosedQuantity’: 0, ‘price’: 165.78, ‘triggerPrice’: 169.15, ‘afterMarketOrder’: False, ‘boProfitValue’: 0.0, ‘boStopLossValue’: 0.0, ‘legName’: ‘NA’, ‘createTime’: ‘2025-07-31 10:00:36’, ‘updateTime’: ‘2025-07-31 10:00:36’, ‘exchangeTime’: ‘1980-01-01 00:00:00’, ‘drvExpiryDate’: ‘2025-07-31’, ‘drvOptionType’: ‘PUT’, ‘drvStrikePrice’: 55800.0, ‘omsErrorCode’: ‘16283’, ‘omsErrorDescription’: ‘EXCH:16283:The order price is not multiple of the tick size.’, ‘algoId’: ‘0’, ‘remainingQuantity’: 35, ‘averageTradedPrice’: 0.0, ‘filledQty’: 0}

I am getting error ‘EXCH:16283:The order price is not multiple of the tick size.’ How to solve this issue.
I am using

tick_size  = 0.05
sl_price   = round(math.floor(sl_price_1 / tick_size) * tick_size, 2)

and it is woking for Nifty and Sensex, but i am getting error in case of Banknifty. Please guide me.

Dear sir i am facing some isue in my algo.

D:\3.1 Codebase Upgrade>py “EMA20 NIFTY NEXT CANDLE, sl new.py”
Codebase Version 2.8 : Solved - Strike Selection Issue
-----Logged into Dhan-----
reading existing file all_instrument 2025-07-31.csv
Got the instrument file
Available balance: 0.0
Max risk for the day: -0.0
Exception at getting Expiry list as {‘status’: ‘failure’, ‘remarks’: {‘error_code’: None, ‘error_type’: None, ‘error_message’: None}, ‘data’: {‘data’: {‘806’: ‘Data APIs not Subscribed’}, ‘status’: ‘failed’}}
Unable to find the correct Expiry for NIFTY
Traceback (most recent call last):
File “EMA20 NIFTY NEXT CANDLE, sl new.py”, line 25, in
ce_name, pe_name, strike = tsl.ATM_Strike_Selection(Underlying=‘NIFTY’, Expiry=1)
TypeError: cannot unpack non-iterable NoneType object

here is my algo code

import pdb
import time
import datetime
import traceback
import talib
from Dhan_Tradehull_V2 import Tradehull
import pandas as pd

Initialize client details

client_code = “110452”
token_id = “eyJ0eXAiOiJKV1QiLC5jx6EXZFqDWpT_XQhJwOa2MQlNOxG_II3YwmSv-jP4Q6OBgZTdisj3ovvJmsfXc8wFMdpFO8HVA” # Replace with your actual token
tsl = Tradehull(client_code, token_id) # tradehull_support_library

Fetch balance and calculate risk limit

available_balance = tsl.get_balance()
max_risk_for_the_day = (available_balance * 1) / 100 * -1

print(“Available balance:”, available_balance)
print(“Max risk for the day:”, max_risk_for_the_day)

order_active_call = False
order_active_put = False

Select ATM Strike Price options for NIFTY

ce_name, pe_name, strike = tsl.ATM_Strike_Selection(Underlying=‘NIFTY’, Expiry=0)
print(ce_name, pe_name, strike)

Initialize variables

traded_watchlist =
target_profit = 20 # Set your desired profit target

Main trading loop

try:
while True:
# Restrict trading hours to 9:16 AM to 2:55 PM
if not (datetime.time(9, 16) <= datetime.datetime.now().time() <= datetime.time(22, 55)):
time.sleep(10) # Sleep for 1 minute before checking again
continue

    # Fetch LTP for CALL and PUT options
    ltp1 = tsl.get_ltp_data(ce_name)
    time.sleep(5)
    ltp2 = tsl.get_ltp_data(pe_name)

    # Check if data is valid before proceeding
    if not ltp1 or not ltp2:
        print("LTP data fetch failed, retrying...")
        time.sleep(5)
        continue  # Skip to the next iteration if data is invalid

    ltp1_value = list(ltp1.values())[0] if ltp1 else None
    ltp2_value = list(ltp2.values())[0] if ltp2 else None

    if ltp1_value is None or ltp2_value is None:
        print("Received empty LTP data, retrying...")
        time.sleep(5)
        continue  # Skip if no valid LTP values are found

    # Fetch intraday data and calculate EMA for CALL and PUT options
    chart1 = tsl.get_historical_data(tradingsymbol=ce_name, exchange='NFO', timeframe="5")
    time.sleep(5)
    chart2 = tsl.get_historical_data(tradingsymbol=pe_name, exchange='NFO', timeframe="5")

    chart1['ema'] = talib.EMA(chart1['close'], timeperiod=20)
    chart2['ema'] = talib.EMA(chart2['close'], timeperiod=20)

    # Get the last EMA values
    last_candle1 = chart1['ema'].iloc[-1]
    last_candle2 = chart2['ema'].iloc[-1]
    last_candle_LOW1 = chart1['low'].iloc[-2]
    last_candle_LOW2 = chart2['low'].iloc[-2]


    # Convert to integers if necessary
    last_candle_close1 = int(last_candle1 + 1)
    last_candle_close2 = int(last_candle2 + 1)

    print("LTP CALL:", ltp1_value)
    print("LTP PUT:", ltp2_value)
    print("EMA CALL:", last_candle_close1)
    print("EMA PUT:", last_candle_close2)
    print("LTP LOW1:", last_candle_LOW1)
    print("LTP LOW2:", last_candle_LOW2)

    # Check if CALL order condition is met and hasn't been placed yet
    if last_candle_close1 <= ltp1_value and ce_name not in traded_watchlist:
        print("Placing CALL order on the next candle")
        traded_watchlist.append(ce_name)
        time.sleep(180)  # Wait for 3 minutes (180 seconds)
        ltp1 = tsl.get_ltp_data(ce_name)
        ltp1_value = list(ltp1.values())[0] if ltp1 else None
        if ltp1_value and last_candle1 < ltp1_value:
            print("Condition met, placing CALL order.")
            limit_price_call = ltp1_value            
            # entry_order_id1  = tsl.order_placement(tradingsymbol='ce_name' ,exchange='NFO', quantity=50, price=0, trigger_price=0, order_type='MARKET', transaction_type='BUY', trade_type='MIS')
            
            # Define initial target  for CALL
            
            target_call = ltp1_value + target_profit
            order_active_call = True

            # Monitor the CALL position
            while order_active_call:
                chart1_sl = tsl.get_historical_data(tradingsymbol=ce_name, exchange='NFO', timeframe="5")
                last_current_candle_LOW1 = chart1_sl['low'].iloc[-2]
                current_price_call = tsl.get_ltp_data(ce_name)
                current_price_call_1 = list(current_price_call.values())[0] if current_price_call else None
                if current_price_call_1 is None:
                    print("Error: current_price_call_1 is None. Skipping update_stop_loss.")
                    time.sleep(3)
                    continue                
                
                # Trigger SL if price goes below the last candle's high
                if current_price_call_1 <= last_current_candle_LOW1:
                    print("Trailing stop-loss hit for CALL, exiting position")                    
                    # tsl.order_placement(tradingsymbol='ce_name' ,exchange='NFO', quantity=25, price=29, trigger_price=30, order_type='STOPLIMIT', transaction_type='SELL', trade_type='MIS')
                    order_active_call = False

                elif current_price_call_1 >= target_call:
                    print("Target hit for CALL, exiting position")                   
                    # tsl.order_placement(tradingsymbol='ce_name' ,exchange='NFO', quantity=25, price=29, trigger_price=30, order_type='STOPLIMIT', transaction_type='SELL', trade_type='MIS')
                    order_active_call = False


    # Check if EMA is now above LTP before allowing re-entry
    if last_candle_close1 > ltp1_value and ce_name in traded_watchlist:
        traded_watchlist.remove(ce_name)
        print(f"{ce_name} removed from watchlist; EMA is now above LTP.")

        time.sleep(5)            

    # Repeat similar logic for PUT options
    if last_candle_close2 <= ltp2_value and pe_name not in traded_watchlist:
        print("Placing PUT order on the next candle")
        traded_watchlist.append(pe_name)
        time.sleep(180)  # Wait for 3 minutes (180 seconds)
        ltp2 = tsl.get_ltp_data(pe_name)
        ltp2_value = list(ltp2.values())[0] if ltp2 else None
        if ltp2_value and last_candle2 < ltp2_value:
            print("Condition met, placing PUT order.")
            limit_price_put = ltp2_value            
            # entry_orderid  = tsl.order_placement(tradingsymbol='pe_name' ,exchange='NFO', quantity=50, price=0, trigger_price=0, order_type='MARKET', transaction_type='BUY', trade_type='MIS')
            
            # Define initial target for PUT
        
            target_put = ltp2_value + target_profit
            order_active_put = True

            # Monitor the PUT position
            while order_active_put:
                chart2_sl = tsl.get_historical_data(tradingsymbol=pe_name, exchange='NFO', timeframe="5")
                last_current_candle_LOW2 = chart2_sl['low'].iloc[-2]
                current_price_put = tsl.get_ltp_data(pe_name)
                current_price_put_1 = list(current_price_put.values())[0] if current_price_put else None
                if current_price_put_1 is None:
                    print("Error: current_price_put_1 is None. Skipping update_stop_loss.")
                    time.sleep(5)
                    continue
                
                
                # Trigger SL if price goes below the last candle's high
                if current_price_put_1 <= last_current_candle_LOW2:
                    print("Trailing stop-loss hit for PUT, exiting position")                    
                    # tsl.order_placement(tradingsymbol='pe_name' ,exchange='NFO', quantity=25, price=29, trigger_price=30, order_type='STOPLIMIT', transaction_type='SELL', trade_type='MIS')
                    order_active_put = False

                elif current_price_put_1 >= target_put:
                    print("Target hit for PUT, exiting position")                    
                    # tsl.order_placement(tradingsymbol='pe_name' ,exchange='NFO', quantity=25, price=29, trigger_price=30, order_type='STOPLIMIT', transaction_type='SELL', trade_type='MIS')
                    order_active_put = False

    # Check if EMA is now above LTP before allowing re-entry
    if last_candle_close2 > ltp2_value and pe_name in traded_watchlist:
        traded_watchlist.remove(pe_name)
        print(f"{pe_name} removed from watchlist; EMA is now above LTP.")

        time.sleep(1)  
                  
    # Wait before the next iteration
    time.sleep(5)

except Exception as e:
print(“An error occurred:”, e)
print(traceback.format_exc())
pdb.set_trace()

hi, i am facing error while running websocket file.

kindly help

Hello @Tradehull_Imran

Every month FnO stock list got updated, how can we include the included stock in Dhan_Tradehull_V2.py. Is their any way to automate to fetch latest list on monthly basis.?


I AM FACING DIFFICULTIES TO RUN Dhan codebase usage.py (ModuleNotFoundError: No module named ‘talib’)

bro websocket method has been discontinued just ignore that 3rd video and watch this Episode 3.1: UPDATED Code Base | FREE Algo Trading Course

you can download the related file from pinned comment by Dhan 0n this video Episode 1: Introduction to Algo Trading | FREE Course by Dhan

1 Like


dear @Tradehull_Imran , I am facing this problem from last many days. Please help me to solve this problem. "MODULE NOTFOUND ERROR :: NO MODULE NAMED “TALIB”. THANK YOU

my websocket is not pulling data on excel

1 Like

help me too

run the command pip install talib

1 Like

why is this so
excel sheet data is not pulling up
i have changed watchlist

check ur python version compatible with talib version or use chatgpt

Hey @Tradehull_Imran,

Can we get scanX data through Dhan Data API,
Please help.

the one which we got in session 2 installation
pip install Ta-lib done
its satisfied
still this issue

Hi @Tradehull_Imran tradehull_imran, please help me out in getting the previous_hist_data & intraday_hist_data from the code. i am not getting the data while running the code

import pdb
import time
import datetime
import traceback
from Dhan_Tradehull import Tradehull
import pandas as pd
from pprint import pprint
import talib


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


pdb.set_trace()

all_ltp_data   = tsl.get_ltp_data(names = ['NIFTY 14 AUG 24500 CALL', 'NIFTY 14 AUG 24500 PUT', "ACC", "CIPLA"])
acc_ltp = all_ltp_data['ACC']
pe_ltp  = all_ltp_data['NIFTY 14 AUG 24500 PUT']

available_balance = tsl.get_balance()
max_risk_for_the_day = (available_balance*1)/100*-1

stock_name = 'NIFTY'
ltp   = tsl.get_ltp_data(names = [stock_name])[stock_name]




chart = tsl.get_historical_data(tradingsymbol = 'NIFTY',  exchange = 'INDEX',timeframe="DAY")
data  = tsl.get_historical_data(tradingsymbol = 'SWANENERGY'     ,exchange = 'NSE'  ,timeframe="15")

previous_hist_data = tsl.get_historical_data('ACC','NSE',"12")
intraday_hist_data = tsl.get_intraday_data(tradingsymbol ='ACC',exchange = 'NSE',timeframe="1")

order_status  = tsl.get_order_status(orderid=82241218256027)
order_price   = tsl.get_executed_price(orderid=82241218256027)
order_time    = tsl.get_exchange_time(orderid=82241218256027)


positions = tsl.get_positions()
orderbook = tsl.get_orderbook()
tradebook = tsl.get_trade_book()
holdings = tsl.get_holdings()


ce_name, pe_name, strike = tsl.ATM_Strike_Selection(Underlying='NIFTY', Expiry=0)


ce_name, pe_name, ce_strike, pe_strike = tsl.OTM_Strike_Selection(Underlying='NIFTY', Expiry=0, OTM_count=3)

ce_name, pe_name, ce_strike, pe_strike = tsl.ITM_Strike_Selection(Underlying='NIFTY', Expiry=0, ITM_count=5)

# Equity
entry_orderid  = tsl.order_placement(tradingsymbol='ACC' ,exchange='NSE', quantity=1, price=0, trigger_price=0,    order_type='MARKET',     transaction_type='BUY',   trade_type='MIS')
sl_orderid     = tsl.order_placement(tradingsymbol='ACC' ,exchange='NSE', quantity=1, price=0, trigger_price=2200, order_type='STOPMARKET', transaction_type ='SELL', trade_type='MIS')

# Options
entry_orderid  = tsl.order_placement(tradingsymbol='NIFTY 14 AUG 24500 CALL' ,exchange='NFO', quantity=50, price=0, trigger_price=0, order_type='MARKET', transaction_type='BUY', trade_type='MIS')
sl_orderid     = tsl.order_placement(tradingsymbol='NIFTY 14 AUG 24500 CALL' ,exchange='NFO', quantity=25, price=29, trigger_price=30, order_type='STOPLIMIT', transaction_type='SELL', trade_type='MIS')

modified_order = tsl.modify_order(order_id=sl_orderid,order_type="STOPLIMIT",quantity=50,price=price,trigger_price=trigger_price)

order_ids      = tsl.place_slice_order(tradingsymbol="NIFTY 14 AUG 24500 CALL",   exchange="NFO",quantity=5000, transaction_type="BUY",order_type="LIMIT",trade_type="MIS",price=0.05)



margin = tsl.margin_calculator(tradingsymbol='ACC', exchange='NSE', transaction_type='BUY', quantity=2, trade_type='MIS', price=2180, trigger_price=0)

margin = tsl.margin_calculator(tradingsymbol='NIFTY 14 AUG 24500 CALL', exchange='NFO', transaction_type='SELL', quantity=25, trade_type='MARGIN', price=43, trigger_price=0)

margin = tsl.margin_calculator(tradingsymbol='NIFTY 14 AUG 24500 CALL', exchange='NFO', transaction_type='BUY', quantity=25, trade_type='MARGIN', price=43, trigger_price=0)
margin = tsl.margin_calculator(tradingsymbol='NIFTY DEC FUT', exchange='NFO', transaction_type='BUY', quantity=25, trade_type='MARGIN', price=24350, trigger_price=0)


exit_all       = tsl.cancel_all_orders()





websocket not good way try fetching historical and intraday data and make them in loop

so that means we cannot use excel sheet to pulle ddata ?

u can but its problematic