Supertrend backtest giving 0 trades even though stocks were in strong uptrend — help needed!

I’ve been trying to backtest a simple Supertrend strategy on 5 min Dhan data for INDORAMA, SOUTHBANK, INDOFARM on 20th Oct 2025, and I’m stuck with 0 trades despite the market being in a clear uptrend all day.

What I’m doing:

Fetching 5-min intraday data using:
{
“securityId”: “10993”,
“exchangeSegment”: “NSE_EQ”,
“instrument”: “EQUITY”,
“interval”: “5”,
“oi”: false,
“fromDate”: “2025-10-20 09:15:00”,
“toDate”: “2025-10-20 15:30:00”
}

  • Getting 74 candles, timestamps in epoch seconds — all good.
  • Using manual Supertrend logic (no pandas_ta) to match TradingView Pine v6.
  • Buy condition:
    • close > Supertrend
    • Green candle (close > open)
    • Previous direction was uptrend (direction[i-1] < 0)

Problem:

  • No buys at all.
  • But when I check the charts, all three stocks were above Supertrend from 09:15 onwards.
  • Log shows data fetched, but no “BUY” entries.
  • supertrend_trades.csv is empty.

Latest Log (last few lines):

2025-10-24 09:18:56,867 Fetched 74 5-min candles for 10993
2025-10-24 09:18:58,177 Fetched 74 5-min candles for 5948
2025-10-24 09:18:59,478 Fetched 74 5-min candles for 29025

My Questions:

  1. Is my manual Supertrend logic correct vs. TradingView?
  2. Why no buy signals even when close > Supertrend + green candle?
  3. Should the uptrend switch condition be removed for the first signal?
  4. Any known issues with 5min data alignment or ATR calculation in Python?

Here’s my code: import requests
import pandas as pd
import logging
import numpy as np

logging.basicConfig(level=logging.INFO)

— Dhan API —

def fetch_data(security_id):
url = “https://api.dhan.co/v2/charts/intraday
payload = {
“securityId”: str(security_id),
“exchangeSegment”: “NSE_EQ”,
“instrument”: “EQUITY”,
“interval”: “5”,
“oi”: False,
“fromDate”: “2025-10-20 09:15:00”,
“toDate”: “2025-10-20 15:30:00”
}
headers = {
‘access-token’: ‘YOUR_TOKEN_HERE’,
‘client-id’: ‘YOUR_CLIENT_ID_HERE’,
‘Content-Type’: ‘application/json’
}
r = requests.post(url, json=payload, headers=headers)
d = r.json()
df = pd.DataFrame({
‘open’: d[‘open’], ‘high’: d[‘high’], ‘low’: d[‘low’],
‘close’: d[‘close’], ‘volume’: d[‘volume’]
})
df[‘timestamp’] = pd.to_datetime(d[‘timestamp’], unit=‘s’)
df.set_index(‘timestamp’, inplace=True)
logging.info(f"Fetched {len(df)} candles for {security_id}")
return df

— Manual Supertrend (Pine v6) —

def supertrend(df, length=10, mult=3.0):
tr1 = df[‘high’] - df[‘low’]
tr2 = (df[‘high’] - df[‘close’].shift(1)).abs()
tr3 = (df[‘low’] - df[‘close’].shift(1)).abs()
tr = pd.concat([tr1, tr2, tr3], axis=1).max(axis=1)
atr = tr.rolling(length).mean()
hl2 = (df[‘high’] + df[‘low’]) / 2
upper = hl2 + mult * atr
lower = hl2 - mult * atr

st = pd.Series(np.nan, index=df.index)
direction = pd.Series(np.nan, index=df.index)

for i in range(length, len(df)):
    final_upper = upper.iloc[i] if df['close'].iloc[i-1] > upper.iloc[i-1] else min(upper.iloc[i], upper.iloc[i-1])
    final_lower = lower.iloc[i] if df['close'].iloc[i-1] < lower.iloc[i-1] else max(lower.iloc[i], lower.iloc[i-1])

    if df['close'].iloc[i] > final_upper:
        st.iloc[i] = final_lower
    elif df['close'].iloc[i] < final_lower:
        st.iloc[i] = final_upper
    else:
        st.iloc[i] = st.iloc[i-1]

    direction.iloc[i] = 1 if st.iloc[i] > st.iloc[i-1] else -1

return st, direction

— Backtest —

def run(symbol, sid):
df = fetch_data(sid)
st, dir = supertrend(df)
df = df.assign(Supertrend=st, Direction=dir)
pos = None

for i in range(1, len(df)):
    c = df.iloc[i]
    t = c.name
    green = c['close'] > c['open']
    above = c['close'] > st.iloc[i]
    up = dir.iloc[i-1] < 0

    if not pos and green and above and up:
        entry = c['close'] * 1.001
        qty = np.floor(50000 / entry)
        if qty > 0:
            pos = {'entry': entry, 'qty': qty, 'time': t}
            logging.info(f"BUY {symbol} @ {t} price={entry:.2f}")

    if pos and (dir.iloc[i] > 0 or t.hour >= 15):
        exit_p = c['close'] * 0.999
        pnl = (exit_p - pos['entry']) * pos['qty']
        logging.info(f"SELL {symbol} @ {t} pnl={pnl:.2f}")
        pos = None

— Run —

run(“INDORAMA”, 10993)
run(“SOUTHBANK”, 5948)
run(“INDOFARM”, 29025)

@Hardik @Shubham_Singh @Trishul_Devadiga @Shrutika_Poojari @Prithvi

Hey @Ziaul ,

As checked, you are fetching intraday historical data, and it is being received successfully as confirmed by you. However, since the order placement logic and code are implemented by you, we request you to please debug the same at your end.