Lesson · Historical Market Data

Download free 1-minute
NIFTY & BANKNIFTY data.

Backtesting needs data. We'll use Dhan's free API to download 1-minute OHLCV candles and save them as a Parquet file — compact, fast, ready for pandas.

Cost: Free
Dhan API · Python · Parquet
~15 minutes end to end
The problem

No data = no backtests.

You can't test a strategy on vibes. You need historical minute-level candles. But where do you get them — free, reliable, and for Indian markets?

Source 1-Min Candles Free Lookback Verdict
Yahoo Finance (yfinance) Yes Yes ~7 days Useless for backtesting
NSE Bhav Copy No (daily only) Yes Years No intraday
Upstox API Yes Free* ~1 year Needs trading account
Dhan API Yes Free 90+ days Best free option
Dhan gives you a free account, free API access, and 1-minute candles. That's our pick.
By the end of this lesson

Two Parquet files. Ready for pandas.

A free Dhan account with API access enabled
nifty_1min.parquet — 1-minute OHLCV candles for NIFTY 50 (last 30 days)
banknifty_1min.parquet — same for BANKNIFTY
A reusable Python script you can run anytime to refresh the data
Download once. Backtest a hundred times. That's the idea.
Vocabulary

Five terms you'll use today.

OHLCV
Open, High, Low, Close, Volume — the five numbers that describe one candle.
open=24510 high=24525 low=24498 close=24520 vol=13400
Parquet
A columnar file format. 10x smaller than CSV, 50x faster to read. The industry standard for data analysis.
df.to_parquet("nifty.parquet")
security_id
Dhan's unique number for each instrument. NIFTY 50 = 13, BANKNIFTY = 25.
security_id='13'
access_token
A temporary key from Dhan that lets your script talk to their API. Expires daily.
DHAN_ACCESS_TOKEN="eyJ0eXAi..."
dhanhq
Dhan's official Python SDK. One pip install and you're connected.
pip install dhanhq
Step 1 of 6

Create a free Dhan account.

1

Sign up

Go to dhan.co and create an account. No minimum balance required.

Free. No trading required.
2

Complete KYC

Aadhaar + PAN verification. Takes about 24 hours to get approved.

One-time process.
3

Get API access

Go to Profile → API Access in your Dhan dashboard. Generate your access token.

Note down: Client ID + Access Token

Token expires daily

Dhan access tokens reset every day. You'll need to regenerate before each download. This is normal — it's a security feature.

Step 2 of 6

Install three packages.

terminal
$ python3 -m pip install dhanhq pandas pyarrow

Collecting dhanhq
  Downloading dhanhq-2.1.0-py3-none-any.whl
Collecting pandas
  Downloading pandas-2.2.2-cp312-cp312-manylinux.whl
Collecting pyarrow
  Downloading pyarrow-16.1.0-cp312-cp312-manylinux.whl

Successfully installed dhanhq-2.1.0 pandas-2.2.2 pyarrow-16.1.0

dhanhq

Dhan's official SDK. Handles auth, endpoints, pagination.

pandas

Data manipulation. Turns raw API response into a DataFrame.

pyarrow

Parquet engine. Reads and writes .parquet files. 10x smaller than CSV.

Step 3 of 6

Set your credentials. Never hardcode them.

terminal
# Set these before running the script
$ export DHAN_CLIENT_ID="1234567890"
$ export DHAN_ACCESS_TOKEN="eyJ0eXAiOiJKV1QiLCJhbGciOi..."

# Verify they're set
$ echo $DHAN_CLIENT_ID
1234567890
Ready.

Why environment variables?

Pasting tokens into your code is how secrets end up on GitHub. Environment variables keep them out of your source files. This is a habit — build it now.

Replace the values above with YOUR Client ID and Access Token from Dhan's dashboard.
Step 4 of 6

The download script. 10 lines that matter.

download_dhan_history.py
from dhanhq import DhanHQ
import pandas as pd

dhan = DhanHQ("YOUR_CLIENT_ID", "YOUR_ACCESS_TOKEN")

# NIFTY 50 index — security_id = 13
resp = dhan.intraday_minute_data(
    security_id='13',
    exchange_segment='IDX_I',
    instrument_type='INDEX',
    from_date='2026-04-20',
    to_date='2026-05-20',
    interval=1
)

df = pd.DataFrame(resp['data'])
df.to_parquet('nifty_1min.parquet')
print(f"Saved {len(df)} rows")

This is the core idea. The full script (which we provide) handles chunking, both instruments, and error handling automatically.

Step 5 of 6

Run the script. Watch it download.

terminal
$ DHAN_CLIENT_ID="1234567890" DHAN_ACCESS_TOKEN="eyJ..." \
  python scripts/download_dhan_history.py

Downloading NIFTY (security_id=13)
  NIFTY 2026-04-20 → 2026-04-25 ... 1875 rows
  NIFTY 2026-04-26 → 2026-05-01 ... 1870 rows
  NIFTY 2026-05-02 → 2026-05-07 ... 1880 rows
  NIFTY 2026-05-08 → 2026-05-13 ... 1865 rows
  NIFTY 2026-05-14 → 2026-05-19 ... 1870 rows
  NIFTY 2026-05-20 → 2026-05-20 ... 375 rows
  Saved 9735 rows → data/nifty_1min.parquet

Downloading BANKNIFTY (security_id=25)
  BANKNIFTY 2026-04-20 → 2026-04-25 ... 1875 rows
  ...
  Saved 9740 rows → data/banknifty_1min.parquet

Done.
Takes about 30 seconds. Two files appear in the data/ folder.
Step 6 of 6

Use the data. Three lines of pandas.

python3
>>> import pandas as pd
>>> df = pd.read_parquet("data/nifty_1min.parquet")
>>> df.head()

         timestamp    open    high     low   close  volume
0  2026-04-20 09:15  24510  24525  24498  24520   13400
1  2026-04-20 09:16  24520  24535  24515  24530    8200
2  2026-04-20 09:17  24530  24540  24525  24538    6100
3  2026-04-20 09:18  24538  24545  24530  24542    5800
4  2026-04-20 09:19  24540  24548  24535  24545    7200

>>> print(f"Total candles: {len(df)}")
Total candles: 9735

>>> print(f"Date range: {df['timestamp'].min()} to {df['timestamp'].max()}")
Date range: 2026-04-20 09:15:00 to 2026-05-20 15:29:00
That's it. You now have minute-level data to build and test strategies on.
The columns

What's inside each row.

Column Type Example Meaning
timestamp datetime 2026-04-20 09:15 Start of the 1-minute candle (IST)
open float 24510.00 Price at the start of the minute
high float 24525.00 Highest price during the minute
low float 24498.00 Lowest price during the minute
close float 24520.00 Price at the end of the minute
volume int 13400 Total contracts/shares traded
375 candles per trading day (9:15 AM to 3:29 PM). About 7,500 per month.
Common issues

When things go wrong.

"no data" for some days

Weekends and market holidays return empty. This is normal — the market was closed. Your script skips them cleanly.

Token expired / auth error

Dhan tokens expire daily. Go to your Dhan dashboard, regenerate the token, and set the new value in your environment variable.

Empty response for all days

Check that your KYC is complete and API access is enabled in your Dhan profile. New accounts may take 24 hours.

ModuleNotFoundError: dhanhq

You forgot to install. Run python3 -m pip install dhanhq pandas pyarrow and try again.

Most errors are auth-related. When in doubt: regenerate the token.
Try it yourself

Practice exercise.

Your turn

  1. Create a Dhan account (if you don't have one) and generate an API token
  2. Install the three packages: python3 -m pip install dhanhq pandas pyarrow
  3. Set your credentials as environment variables
  4. Run the download script and verify two .parquet files appear in data/
  5. Load the NIFTY file in pandas. Answer: how many candles do you have? What's the date range?
  6. Bonus: Plot a simple line chart of NIFTY closing prices using df['close'].plot()
Stuck? The most common issue is an expired token. Regenerate it from the Dhan dashboard.

End of Lesson

You now have free market data.
Time to backtest.

data source: Dhan API (dhanhq) · format: Apache Parquet
← → navigate · F fullscreen · click to advance
1 / 14