Hi @Tradehull_Imran ,
I am facing an error while fetching OHLC data while executing the following code. Please resolve the issue
Here is the Code…
import time
import datetime
from Dhan_Tradehull import Tradehull
import pandas as pd
import talib
import logging
from dotenv import load_dotenv
import os
# Load environment variables
load_dotenv('dhan.env')
# API credentials
client_code = os.getenv('CLIENT_ID')
token_id = os.getenv('API_KEY')
broker = Tradehull(client_code, token_id)
# Global variables for position tracking
active_position = None
def clear_screen():
"""Clear the terminal screen"""
os.system('cls' if os.name == 'nt' else 'clear')
def display_header(title):
"""Display section header"""
clear_screen()
print(f"\n{'='*50}")
print(f"{title.center(50)}")
print(f"{'='*50}\n")
def select_from_list(options, prompt):
"""Display a numbered list and return selected value"""
for idx, option in enumerate(options, 1):
print(f"{idx}. {option}")
while True:
try:
choice = int(input(f"\n{prompt} (1-{len(options)}): "))
if 1 <= choice <= len(options):
return options[choice-1]
print("Invalid choice. Please try again.")
except ValueError:
print("Please enter a number.")
def get_instrument():
"""Select trading instrument"""
instruments = ["NIFTY", "BANKNIFTY", "SENSEX"]
return select_from_list(instruments, "Select Instrument")
def get_expiry(instrument):
"""Select expiry date"""
expiries = broker.get_expiry_list(Underlying=instrument, exchange='INDEX')
return select_from_list(expiries, "Select Expiry")
def get_quantity(instrument):
"""Get quantity input with lot size display"""
try:
lot_size = int(broker.get_lot_size(tradingsymbol=instrument))
print(f"\n\033[1;36mLot size for {instrument}: {lot_size}\033[0m")
except:
# Fallback hardcoded lot sizes
lot_sizes = {"NIFTY": 50, "BANKNIFTY": 25, "SENSEX": 10}
lot_size = lot_sizes.get(instrument, 1)
print(f"\n\033[1;33mUsing default lot size for {instrument}: {lot_size}\033[0m")
while True:
try:
lots = int(input("\nEnter number of lots: "))
total_qty = lots * lot_size
print(f"\033[1;36mTotal Quantity: {total_qty}\033[0m")
return total_qty
except ValueError:
print("\033[1;31mPlease enter a valid number.\033[0m")
def get_product_type():
"""Select product type with warnings"""
product = select_from_list(["MIS", "CNC"], "Select Product Type")
print("\n\033[1;33m" + "="*50)
if product == "MIS":
print("⚠️ Exiting MIS trade at 3:25 PM")
else:
print("ℹ️ CNC trade will continue to the next day.")
print("="*50 + "\033[0m")
return product
def get_order_type(instrument, ltp):
"""Select order type with strike info"""
# Ensure ltp is a numeric value
try:
if isinstance(ltp, dict):
ltp = float(ltp.get('last_price', 0))
else:
ltp = float(ltp)
except (ValueError, TypeError):
print("\n\033[1;31mError: Could not fetch valid LTP!\033[0m")
return None, None
# Calculate step size
step = broker.index_step_dict.get(instrument, 50)
# Calculate ATM strike
atm_strike = round(ltp / step) * step
# Order type selection
order_type = select_from_list(["MARKET", "LIMIT"], "Select Order Type")
# Display strike info
print("\n\033[1;36m" + "="*50)
if order_type == "MARKET":
print(f"ATM Price: {atm_strike}")
else:
strikes = [atm_strike + (i * step) for i in range(1, 6)]
print("OTM Strikes:")
print(", ".join([f"OTM{i+1}: {strike}" for i, strike in enumerate(strikes)]))
print("="*50 + "\033[0m")
return order_type, atm_strike
def get_valid_strikes(instrument, indicators, order_type):
ltp = indicators['close']
step = broker.index_step_dict.get(instrument, 50)
atm_strike = round(ltp / step) * step
strikes = [atm_strike + (i * step) for i in range(-3, 7)]
h4, h3, l3, l4 = indicators['pivots']
ema13, ema21, ema34 = indicators['emas']
close = indicators['close']
valid_strikes = []
for strike in strikes:
is_otm = (strike > ltp) if (close >= h4 or close <= l3) else (strike < ltp)
ema_condition = (close > ema13 and close > ema21 and close > ema34) if is_otm else (
close < ema13 and close < ema21 and close < ema34)
if indicators['cpr_class'] in ['Narrow', 'Normal'] and ema_condition:
if order_type == 'LIMIT' and is_otm:
valid_strikes.append(strike)
elif order_type == 'MARKET' and strike == atm_strike:
valid_strikes.append(strike)
return valid_strikes, atm_strike
def get_strike_price(instrument, indicators, order_type):
valid_strikes, atm_strike = get_valid_strikes(instrument, indicators, order_type)
if order_type == 'MARKET':
if atm_strike in valid_strikes:
print(f"\nAuto-selected ATM strike: {atm_strike}")
return atm_strike
print("\nNo valid ATM strike available based on strategy rules")
return None
if not valid_strikes:
print("\nNo valid strikes available based on strategy rules")
return None
return select_from_list(valid_strikes, "Select Strike Price")
def calculate_indicators(data):
"""Calculate technical indicators with validation"""
try:
# Validate input data
required_columns = ['open', 'high', 'low', 'close']
if not all(col in data.columns for col in required_columns):
raise ValueError(f"Missing required columns: {required_columns}")
# EMAs
data['13_EMA'] = talib.EMA(data['close'], timeperiod=13)
data['21_EMA'] = talib.EMA(data['close'], timeperiod=21)
data['34_EMA'] = talib.EMA(data['close'], timeperiod=34)
# ATR
data['ATR'] = talib.ATR(data['high'], data['low'], data['close'], 14)
# CPR Calculations
high = data['high'].iloc[-1]
low = data['low'].iloc[-1]
close = data['close'].iloc[-1]
pivot = (high + low + close) / 3
bc = (high + low) / 2
tc = (pivot - bc) + pivot
cpr_width = ((tc - bc) / pivot) * 100
cpr_class = 'Wide'
if cpr_width <= 20: cpr_class = 'Narrow'
elif cpr_width <= 25: cpr_class = 'Normal'
# Camarilla Pivots
h4 = close + (high - low) * 1.1 / 2
h3 = close + (high - low) * 1.1 / 4
l3 = close - (high - low) * 1.1 / 4
l4 = close - (high - low) * 1.1 / 2
return {
'cpr_class': cpr_class,
'h4': h4,
'h3': h3,
'l3': l3,
'l4': l4,
'close': close,
'emas': (data['13_EMA'].iloc[-1], data['21_EMA'].iloc[-1], data['34_EMA'].iloc[-1]),
'ATR': data['ATR'].iloc[-1]
}
except Exception as e:
print(f"\n\033[1;31mError calculating indicators: {str(e)}\033[0m")
return None
def strategy_1(data, broker, params):
"""CPR-EMA Strategy Implementation"""
try:
data, cpr_class, h4, h3, l3, l4 = calculate_indicators(data)
close = data['close'].iloc[-1]
ema_13 = data['13_EMA'].iloc[-1]
ema_21 = data['21_EMA'].iloc[-1]
ema_34 = data['34_EMA'].iloc[-1]
signal = None
if cpr_class in ['Narrow', 'Normal']:
if (close <= l3 or close >= h4) and close > ema_13 and close > ema_21 and close > ema_34:
signal = 'Buy'
elif (close >= h3 or close <= l4) and close < ema_13 and close < ema_21 and close < ema_34:
signal = 'Sell'
if signal:
result = broker.execute_trade(
instrument=params['instrument'],
expiry=params['expiry'],
quantity=params['quantity'],
product=params['product'],
order_type=params['order_type'],
strike=params['strike']
)
return result
return None
except Exception as e:
logging.error(f"Strategy 1 error: {str(e)}")
print("\n\033[1;31mStrategy entry conditions not met!\033[0m")
print("Required conditions:")
print("- Close price beyond H4/L3 Camarilla levels")
print("- EMA alignment (price above/below all 3 EMAs)")
return None
def execute_strategy():
"""Execute trading strategy"""
global active_position
display_header("Execute Trading Strategy")
# Strategy Selection
strategies = [
"CPR-EMA Strategy",
"Momentum Breakout Strategy",
"Mean Reversion Strategy",
"MACD Crossover Strategy",
"Bollinger Bands Strategy"
]
strategy = select_from_list(strategies, "Select Trading Strategy")
if strategy != "CPR-EMA Strategy":
print("\n\033[1;33mSelected strategy is not implemented yet!\033[0m")
return
# Get trade parameters
instrument = get_instrument()
expiry = get_expiry(instrument)
try:
# Fetch and process OHLC data
raw_data = broker.get_ohlc_data([instrument])
if not isinstance(raw_data, dict) or instrument not in raw_data:
raise ValueError("Invalid data format received from broker")
instrument_data = raw_data[instrument]
if not isinstance(instrument_data, dict):
raise ValueError("Unexpected data structure for instrument OHLC")
# Create DataFrame with proper column names
data = pd.DataFrame([{
'close': instrument_data.get('last_price'),
'high': instrument_data.get('day_high'),
'low': instrument_data.get('day_low'),
'open': instrument_data.get('day_open')
}])
# Validate required columns
if data.isnull().values.any():
missing = data.columns[data.isnull().any()].tolist()
raise ValueError(f"Missing data for columns: {missing}")
indicators = calculate_indicators(data)
except Exception as e:
print(f"\nError processing market data: {str(e)}")
return
order_type = get_order_type()
strike = get_strike_price(instrument, indicators, order_type)
if not strike:
print("Aborting trade execution due to invalid strike price")
return
quantity = get_quantity(instrument)
product = get_product_type()
# Check market hours
if not is_market_open():
print("\nMarket is closed. Trading not allowed.")
return
# Execute trade
try:
params = {
"instrument": instrument,
"expiry": expiry,
"quantity": quantity,
"product": product,
"order_type": order_type,
"strike": strike
}
result = strategy_1(pd.DataFrame(ohlc_data), broker, params)
if result:
active_position = {
"strategy": strategy,
"instrument": instrument,
"strike": strike,
"quantity": quantity,
"product": product,
"order_type": order_type,
"expiry": expiry,
"timestamp": datetime.datetime.now()
}
print("\n\033[1;32mTrade executed successfully!\033[0m")
print("Order Details:", result)
else:
print("\n\033[1;31mTrade execution failed!\033[0m")
except Exception as e:
logging.error(f"Strategy Execution Error: {str(e)}")
print(f"\n\033[1;31mError executing trade: {str(e)}\033[0m")
def close_position():
"""Close active position"""
global active_position
display_header("Close Position")
if not active_position:
print("No active position to close")
return
print("Current Position Details:")
for key, value in active_position.items():
print(f"{key.capitalize()}: {value}")
confirm = input("\nAre you sure you want to close this position? (y/n): ").lower()
if confirm == 'y':
try:
result = broker.execute_trade(
instrument=active_position['instrument'],
expiry=active_position['expiry'],
quantity=active_position['quantity'],
product=active_position['product'],
order_type="MARKET",
strike=active_position['strike'],
transaction_type="SELL"
)
if result:
active_position = None
print("\nPosition closed successfully!")
else:
print("\nFailed to close position")
except Exception as e:
print(f"\nError closing position: {str(e)}")
def is_market_open():
"""Check if market is open"""
now = datetime.datetime.now().time()
market_open = datetime.time(9, 15) # Market opens at 9:15 AM
market_close = datetime.time(15, 30) # Market closes at 3:30 PM
return market_open < now < market_close
def account_info():
print("\n=== Account Information ===")
try:
balance = broker.get_balance()
positions = broker.get_positions()
orders = broker.get_orderbook()
print(f"\nAccount Balance: ₹{balance:,.2f}")
print("\nActive Positions:")
if not positions.empty:
print(positions)
else:
print("No active positions")
print("\nOrder Book:")
if not orders.empty:
print(orders)
else:
print("No active orders")
except Exception as e:
print(f"\nError fetching account info: {str(e)}")
def main_menu():
while True:
print("\n=== Main Menu ===")
print("1. Execute Strategy")
print("2. Close Position")
print("3. Account Info")
print("4. Exit")
choice = input("Select Action (1-4): ")
if choice == "1":
execute_strategy()
elif choice == "2":
close_position()
elif choice == "3":
account_info()
elif choice == "4":
print("\nExiting program...")
break
else:
print("Invalid choice. Please try again.")
if __name__ == "__main__":
main_menu()
And Here is the ERROR…
Select Instrument (1-3): 1
1. 2025-02-20
2. 2025-02-27
3. 2025-03-06
4. 2025-03-13
5. 2025-03-20
6. 2025-03-27
7. 2025-04-24
8. 2025-06-26
9. 2025-09-25
10. 2025-12-24
11. 2026-06-25
12. 2026-12-31
13. 2027-06-24
14. 2027-12-30
15. 2028-06-29
16. 2028-12-28
17. 2029-06-28
18. 2029-12-27
Select Expiry (1-18): 1
Error processing market data: Missing data for columns: ['high', 'low', 'open']
=== Main Menu ===
1. Execute Strategy
2. Close Position
3. Account Info
4. Exit
Select Action (1-4):
Some parameters related error i think in fetching OHLC from Tradehull class. Please help me.