You can’t build an AI workflow for Indian stocks without data. And data acquisition in India is messier than the tutorials let on.
This is the working guide for getting NSE data into Python in 2026 — what each library is good for, what breaks, and how to compute indicators on top.
The four real options
| Source | Free | Realtime | Historical depth | Reliability |
|---|---|---|---|---|
yfinance (Yahoo) |
Yes | ~15-min delayed | Years | Decent for daily, flaky for intraday |
nsepython (scrapes NSE) |
Yes | Live | Limited intraday | Breaks when NSE changes site |
| Kite Connect (Zerodha) | ₹2,000/mo | Real-time | Years | Best paid option |
| Upstox / Dhan / IIFL APIs | Mostly free | Real-time | Years | Newer; quality varies |
Pick based on use case:
- Research and backtesting on daily data:
yfinance. - Light intraday research:
nsepython(with caveats). - Live algo or production: Kite Connect.
- Sentiment / news pipeline: add
feedparserfor RSS.
yfinance — daily and weekly data
import yfinance as yf
df = yf.download(
"RELIANCE.NS",
start="2024-01-01",
end="2026-05-01",
interval="1d",
auto_adjust=True,
)
print(df.tail())
Tickers use .NS suffix for NSE, .BO for BSE.
Gotchas:
interval="1m"gives 7 days max history.interval="5m"gives 60 days max.- Sometimes returns empty for valid tickers — retry.
- Adjusted prices include corporate actions; check
auto_adjust.
For Nifty index: ^NSEI. Bank Nifty: ^NSEBANK.
nsepython — live quotes & option chain
from nsepython import nse_eq, nse_optionchain_scrapper
quote = nse_eq("RELIANCE")
print(quote["priceInfo"]["lastPrice"])
oc = nse_optionchain_scrapper("BANKNIFTY")
print(oc["records"]["expiryDates"][:3])
Use it for:
- Live LTP, day range, volume.
- Option chain snapshots (for personal F&O dashboards).
- Index constituents.
Don’t use it for:
- Backfills of historical intraday data (NSE removed the API).
- High-frequency polling — you’ll get rate-limited and possibly IP-blocked.
Polling cadence: every 30 seconds is safe; every 5 seconds will get you blocked.
Kite Connect — production data
from kiteconnect import KiteConnect
kite = KiteConnect(api_key="your_key")
# (auth flow via OAuth-style login)
kite.set_access_token("token_from_login")
# Historical 5-min for the last 30 days
from datetime import datetime, timedelta
instrument_token = 738561 # RELIANCE
to_date = datetime.now()
from_date = to_date - timedelta(days=30)
candles = kite.historical_data(
instrument_token,
from_date,
to_date,
interval="5minute"
)
This is the cleanest data feed in India for retail. Combined with WebSocket ticks (KiteTicker), it’s production-grade.
Gotchas:
- Daily access tokens — re-login every morning.
- Instrument tokens differ per symbol; cache the master list.
- F&O tokens change at expiry rollover.
For the broader Python build, see building a personal AI stock screener with Python.
Computing indicators with pandas-ta
Once you have OHLCV in a DataFrame, indicators are one-liners with pandas-ta:
import pandas_ta as ta
df["rsi"] = ta.rsi(df["Close"], length=14)
df["ema20"] = ta.ema(df["Close"], length=20)
df["atr"] = ta.atr(df["High"], df["Low"], df["Close"], length=14)
df["vwap"] = ta.vwap(df["High"], df["Low"], df["Close"], df["Volume"])
# MACD returns a DataFrame
macd = ta.macd(df["Close"])
df = df.join(macd)
For VWAP specifically, make sure the data is intraday — VWAP on daily bars is meaningless.
Indicator references: - RSI for intraday - MACD explained - VWAP strategy - ATR for intraday
A minimal screener loop
import pandas as pd
import yfinance as yf
import pandas_ta as ta
universe = ["RELIANCE.NS", "HDFCBANK.NS", "TCS.NS", "INFY.NS", "ITC.NS"]
results = []
for sym in universe:
df = yf.download(sym, period="60d", interval="1d", auto_adjust=True)
if df.empty:
continue
df["rsi"] = ta.rsi(df["Close"], length=14)
df["ema50"] = ta.ema(df["Close"], length=50)
last = df.iloc[-1]
if last["Close"] > last["ema50"] and 40 < last["rsi"] < 60:
results.append((sym, last["Close"], last["rsi"]))
print(pd.DataFrame(results, columns=["symbol", "close", "rsi"]))
That’s a “trend-pullback” screener in 15 lines. Not glamorous, but it works — and it’s the skeleton you extend with AI signals on top.
Common mistakes
- Treating Yahoo intraday as gospel. It’s delayed and sometimes wrong on volume. Acceptable for research; not for execution.
- Polling NSE endpoints aggressively. You will be blocked.
- Forgetting timezone. Convert NSE timestamps to
Asia/Kolkata. - Ignoring corporate actions. Splits and bonuses break un-adjusted series.
- Caching incorrectly. Cache historical bars indefinitely; never cache current-day data past its update time.
A clean stack for personal use
- Daily data: yfinance + SQLite for cache.
- Intraday research: Kite Connect historical + parquet files.
- Live trading: Kite Connect WebSocket → in-memory rolling DataFrames.
- Indicators: pandas-ta.
- News: feedparser + RSS + LLM pipeline (see LLM news sentiment).
- Storage: SQLite for state, parquet for time-series, Redis if you outgrow it.
That stack will carry you from “first screener” to “personal trading system” without rewrites.
FAQs
Is there a totally free intraday data source for years of NSE data? Not reliably. Kite Connect at ₹2,000/month is the cheapest trustworthy option.
Can I scrape moneycontrol or screener.in? Their terms restrict it. For personal/research use occasional pulls are usually tolerated; don’t redistribute.
Should I store data in a database or files? Parquet files for time-series. SQLite/Postgres for state (positions, orders, journal entries).
For where this fits in the wider AI-trading picture, see AI stock analysis in India: an overview.