NineFifteenAM

Pillar guide · updated monthly

Kite Connect historical data: fetching years of minute candles

7 min readBy NineFifteenAM

Kite Connect returns 60 days of 1-minute candles per request. Going back to 2015 for one instrument takes 72 requests. Here's the arithmetic and the Python loop.

Short answer

Split the date range into chunks that fit the per-request limit (60 days for 1-minute candles), request them one after another at no more than 3 requests per second, and save each chunk with the timestamp as a unique key so overlaps don't create duplicates. From 1 January 2015 to 9 October 2026 that is 72 requests for one instrument, which takes at least 24 seconds.

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

Checking what you downloaded

Before using the data in a backtest, I'd run three checks:

  1. 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.
  2. 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.
  3. Look for duplicate timestamps. With the primary key above there shouldn't be any. If you skipped the key, check now.

Sources

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.

Questions people ask me

How many days of minute data can I get from Kite Connect in one request?

60 days for 1-minute candles, 100 days for 3, 5 and 10-minute candles, 200 days for 15 and 30-minute, 400 days for 60-minute and 2,000 days for daily candles, according to Zerodha staff on the Kite Connect forum. You can make more requests to go further back.

How far back does Kite Connect minute data go?

Zerodha staff have said on the Kite Connect forum that minute-level data starts around early 2015. Daily candles for some NSE stocks go back to the late 1990s.

What is the Kite Connect historical data rate limit?

The Kite Connect documentation lists 3 requests per second for historical candles. Going over it returns HTTP 429, 'Too many requests'.

How many requests does it take to download all Nifty minute data since 2015?

From 1 January 2015 to 9 October 2026 is 4,300 calendar days. At 60 days per request that is 72 requests, or at least 24 seconds at 3 requests a second.

kite connecthistorical datapythonminute candleszerodha apibacktesting data
N

NineFifteenAM

One trader building an options bot for Indian index markets since early 2026. I write down how it is built, what broke, and what it cost — no tips, no calls, no returns.

Related

30 Sept 2026
Streaming live prices with the Kite Connect websocket in PythonA runnable Python script for Zerodha's Kite Connect websocket: subscribe, pick a mode, read a tick field by field, handle reconnects and shut down cleanly.
Guides
29 Sept 2026
How to place your first order with the Kite Connect API in PythonPlace, check and cancel your first order with Zerodha's Kite Connect API in Python, after rehearsing it in a paper mode that sends nothing to the exchange.
Guides
05 Oct 2026
The closing auction session explained: how F&O stocks close nowSince 3 August 2026, NSE sets the closing price of F&O stocks with a 3:15 to 3:35 PM auction. How it works, and why the last trade is no longer the close.
Guides