Kite Connect gives you 60 days of 1-minute candles per request, and minute data goes back to around 2015. To get everything from 1 January 2015 to today for one instrument, you need 72 requests. At the documented limit of 3 historical requests a second, that's 24 seconds of downloading, plus whatever your own code adds.
This guide works through the arithmetic, then shows the loop I'd write to do it without hitting rate limits or saving duplicate candles. It assumes you already have an API key, the ₹500-a-month Connect plan that includes data, and a valid access token. If you don't, start with what Kite Connect costs and its limits and the daily token refresh.
The limits that shape the loop
There are two limits to plan around: how many days one request can cover, and how many requests you can make a second.
Days per request, by candle size, as given by Zerodha staff on the Kite Connect forum:
| Candle size | Days per request |
|---|---|
| 1 minute | 60 |
| 3, 5 and 10 minutes | 100 |
| 15 and 30 minutes | 200 |
| 60 minutes | 400 |
| Daily | 2,000 |
Requests per second, from the Kite Connect documentation:
| Endpoint | Limit |
|---|---|
| Historical candles | 3 a second |
| Quote | 1 a second |
| Order placement and everything else | 10 a second |
Go over the limit and the API returns HTTP 429, "Too many requests". In the Python client that comes back as a NetworkException.
The days limit is in calendar days, not trading days. A 60-day window ending on Friday, 9 October 2026 starts on Tuesday, 11 August. That window has 44 weekdays, and two of them (14 September and 2 October) were NSE holidays, so it covers 42 trading sessions.
The worked example: Nifty 50 back to 2015
How many candles in one request? A full NSE session runs from 9:15 AM to 3:30 PM, which is 375 minutes, so 375 one-minute candles. (Today's Nifty session had 25 fifteen-minute candles on Kite, which is the same 375 minutes.) One 60-day request covering those 42 sessions returns 42 × 375 = 15,750 candles. Shortened sessions, such as Muhurat trading, will have fewer.
How many requests to go back to 2015? From 1 January 2015 to 9 October 2026 is 4,300 calendar days: 11 full years from 2015 to 2025 with three leap years in them, plus 282 days of 2026.
| Candle size | Days per request | Requests for 4,300 days |
|---|---|---|
| 1 minute | 60 | 72 |
| 5 minutes | 100 | 43 |
| 15 minutes | 200 | 22 |
| 60 minutes | 400 | 11 |
| Daily | 2,000 | 3 |
Each figure is 4,300 divided by the limit, rounded up.
How long does it take? At 3 requests a second, 72 requests take at least 24 seconds. That's one instrument. For all 50 Nifty stocks, it's 50 × 72 = 3,600 requests, or at least 1,200 seconds: 20 minutes. In practice it will be longer, because each request takes time to come back and you'll want a little slack under the limit.
That 20 minutes is the number that changed how I think about it. One instrument is a quick script. A whole index is a job you start, leave running and come back to, so it has to survive errors and restarts.
The loop in Python
Here is the pattern, using the official kiteconnect package and SQLite. It's a simplified version of the approach I use, without anything specific to my own setup.
import sqlite3
import time
from datetime import date, datetime, timedelta
from kiteconnect import KiteConnect
from kiteconnect.exceptions import NetworkException
kite = KiteConnect(api_key="your_api_key")
kite.set_access_token("todays_access_token")
CHUNK_DAYS = {"minute": 60, "5minute": 100, "15minute": 200, "60minute": 400, "day": 2000}
PAUSE = 0.35 # seconds between requests, to stay under 3 a second
db = sqlite3.connect("candles.db")
db.execute("""
CREATE TABLE IF NOT EXISTS candles (
token INTEGER, interval TEXT, ts TEXT,
open REAL, high REAL, low REAL, close REAL, volume INTEGER,
PRIMARY KEY (token, interval, ts)
)
""")
def chunks(start, end, days):
"""Yield (from, to) date pairs that each fit in one request."""
cur = start
while cur <= end:
stop = min(cur + timedelta(days=days - 1), end)
yield cur, stop
cur = stop + timedelta(days=1)
def fetch(token, interval, start, end):
for frm, to in chunks(start, end, CHUNK_DAYS[interval]):
for attempt in range(5):
try:
rows = kite.historical_data(
token,
datetime.combine(frm, datetime.min.time()),
datetime.combine(to, datetime.max.time().replace(microsecond=0)),
interval,
)
break
except NetworkException:
time.sleep(2 ** attempt) # back off after a 429 or a network error
else:
raise RuntimeError(f"gave up on {token} {frm} to {to}")
db.executemany(
"INSERT OR IGNORE INTO candles VALUES (?,?,?,?,?,?,?,?)",
[(token, interval, r["date"].isoformat(), r["open"], r["high"],
r["low"], r["close"], r["volume"]) for r in rows],
)
db.commit()
print(token, frm, to, len(rows))
time.sleep(PAUSE)
fetch(256265, "minute", date(2015, 1, 1), date(2026, 10, 9)) # 256265 = NIFTY 50
Why it's written that way
Chunks end the day before the next one starts. Each chunk runs from midnight on its first day to 23:59:59 on its last, and the next chunk starts the following day. With days - 1 in the arithmetic, every chunk is at most 60 calendar days including both ends.
The primary key does the de-duplication. INSERT OR IGNORE with (token, interval, ts) as the key means that if you rerun a range, or two chunks overlap because you changed the code, you don't get the same candle twice. This matters more than it sounds. Duplicate candles quietly double-count volume and distort anything that counts bars, like the time-of-day studies in when the Nifty makes its high and low.
Commit after every chunk. If the job dies at chunk 40 of 72, the first 39 are saved. To resume, I'd query the latest ts for that token and interval and start from that day. The primary key takes care of the partial day.
Back off on errors. A 429 means you went too fast; a timeout or dropped connection also comes back as a NetworkException. Waiting 1, 2, 4, 8 and 16 seconds before giving up handles both without hammering the API. A token error is a different exception, and it should stop the job, not retry it: the token won't fix itself until you log in again.
Pause between requests. A pause of 0.35 seconds after each request keeps you under 3 a second even if a response comes back instantly. It costs a few seconds over 72 requests, and it's cheaper than handling a burst of 429s.
Things that catch people out
- Index candles have no volume. Nifty 50 minute candles come back with volume 0, because an index isn't traded. If you need volume, use the futures contract or the stocks.
- Expired derivatives aren't there. As I noted in the cost and limits guide, expired option contracts aren't available from the historical API. For futures there's a
continuousflag that stitches expiries together. If you need old options data, save it while the contracts are live, for example from the websocket. - Each contract has its own token. Every futures and options expiry is a separate instrument with its own token. Look tokens up from the instruments list each day rather than hard-coding them; the Nifty 50 token in the example is the exception I'm happy to hard-code.
- Candles are not ticks. Historical data is candles only. If you need tick-level history, record it yourself.
- Timestamps carry the timezone. The API returns times in IST with an offset. Store them consistently, either all with the offset or all as naive IST, and don't mix the two.
Checking what you downloaded
Before using the data in a backtest, I'd run three checks:
- Count candles per day. Most days should have 375. Anything far short is a gap in the data or a special session, and it's worth knowing which before you backtest an intraday idea on it.
- Compare daily closes. Build a daily close from the minute candles and compare it with the daily candles from the same API. Small differences can come from how the last minute is stamped and from the official closing price; large ones mean something is missing.
- Look for duplicate timestamps. With the primary key above there shouldn't be any. If you skipped the key, check now.
Sources
- Kite Connect documentation: historical candle data (endpoint, intervals,
continuousandoiparameters) - Kite Connect documentation: exceptions and rate limits (3 requests a second for historical data, HTTP 429)
- Kite Connect forum: historical data limits and retention (days per request, minute data from around 2015)
- Kite Connect forum: API rate limits
- Nifty 50 instrument token and 15-minute candles for 9 October 2026: Zerodha Kite market data
This guide is for information and education only. It is not investment advice or a recommendation to buy or sell any security. I am not registered with SEBI as an investment adviser or research analyst.