FII/DII Activity API

September 23, 2026 · View on GitHub

Daily FII/DII net buy/sell activity for Indian markets — scraped by GitHub Actions, served as static JSON. Zero servers, zero ongoing cost.

License: MIT Stars Last commit Python CI

Daily FII (Foreign Institutional Investors) and DII (Domestic Institutional Investors) net buy/sell activity for Indian equity markets — scraped by GitHub Actions and served as static JSON via GitHub Pages and raw.githubusercontent.com. A Python job runs after NSE close, validates the parse, commits it to the repo (git-as-DB), and GitHub Pages publishes a self-contained site + the raw JSON API.

⭐ If this is useful, please star the repo — it helps others find it.

FII/DII Activity API — live site

Live site screenshot, auto-captured from the deployed page by fii-dii screenshot tooling.

Contents

Data flow

flowchart LR
  subgraph cron["GitHub Actions (weekdays 13:00 UTC)"]
    F["Scrape<br/>NSE → Groww → Moneycontrol → placeholder"] --> V["Validate<br/>6 finite fields · buy−sell≈net · complete FII+DII"]
    V --> W["Write data/&lt;date&gt;.json<br/>+ data/latest.json"]
    W --> C["Regenerate README chart"]
    C --> G["git commit + rebase + push (git-as-DB)"]
  end
  G -->|push to main| B["deploy.yml → build_site.py → dist/"]
  B --> P["GitHub Pages (canonical API)"]
  G -.mirrors.-> M["raw.githubusercontent · jsDelivr · Statically"]

Chart

FII vs DII net equity flow (₹ crore, most recent sessions)

xychart-beta
    title "FII net (line 1) vs DII net (line 2) — INR crore"
    x-axis ["08-21", "08-25", "08-26", "08-27", "08-28", "08-31", "09-01", "09-02", "09-03", "09-04", "09-07", "09-08", "09-09", "09-10", "09-11", "09-15", "09-16", "09-17", "09-21", "09-22"]
    y-axis "Net (INR cr)" -7986 --> 8931
    line [-542.71, 1593.53, 502.63, -298.26, -5039.8, -7985.88, 1143.38, 6688.37, -2345.87, -3111.94, 280.13, -123.19, -582.99, -438.24, -930.9, -2977.86, -2032.61, -3208.76, -576.2, -3809.99]
    line [2124.14, 230.26, 6425.16, 4977.17, 5183.93, 4588.88, 1846.94, 2812.98, 4977.46, 8930.12, 566.76, 1349.64, 1509.04, 1025.85, 1968.17, 2686.05, 3908.23, 3617.75, 2797.27, 4120.07]

FII = first line, DII = second line. Auto-generated from data/ by python -m fii_dii.chart on each scrape. Last 20 session(s).

Endpoints (static JSON)

The canonical base URL is GitHub Pages — it never expires and has no external DNS dependency. The raw and CDN URLs are equivalent mirrors of the same committed data.

URLDescription
https://chirag127.github.io/fii-dii-activity-api/data/latest.jsonCanonical — most recent scrape
https://chirag127.github.io/fii-dii-activity-api/data/<YYYY-MM-DD>.jsonCanonical — a specific day
https://raw.githubusercontent.com/chirag127/fii-dii-activity-api/main/data/latest.jsonMirror via raw (no Pages dependency)
https://raw.githubusercontent.com/chirag127/fii-dii-activity-api/main/data/<YYYY-MM-DD>.jsonMirror via raw — a specific day
https://cdn.jsdelivr.net/gh/chirag127/fii-dii-activity-api@main/data/latest.jsonMirror via jsDelivr CDN (cached, fast)
https://cdn.statically.io/gh/chirag127/fii-dii-activity-api/main/data/latest.jsonMirror via Statically CDN

Machine-readable contract: openapi.yaml — OpenAPI 3.1, two GET endpoints, four equivalent servers (import into RapidAPI, Postman, Swagger UI, etc.):

Method + pathoperationIdPurpose
GET /latest.jsongetLatestMost recent daily FII/DII payload
GET /{date}.jsongetByDatePayload for a specific YYYY-MM-DD trading day (404 if none)

Response shape (latest.json)

{
  "date": "2026-07-21",
  "source": "nse",
  "equity":     { "fii_buy": 5917.71, "fii_sell": 5004.12, "fii_net": 913.59, "dii_buy": 6440.88, "dii_sell": 5165.66, "dii_net": 1275.22 },
  "derivative": { "fii_buy": 0, "fii_sell": 0, "fii_net": 0, "dii_buy": 0, "dii_sell": 0, "dii_net": 0 }
}

source is one of nse, groww (primary working source), moneycontrol (fallback), or placeholder (all failed → all zeros). All values are INR crores. equity is the Capital Market (cash) segment; derivative is reserved for F&O and is currently always zero (the upstreams report cash only).

How it works

  1. Fetchscrape.py tries NSE's fiidii JSON API, then Groww's server-rendered cash data (primary working source), then Moneycontrol; if all fail it writes an all-zero placeholder.
  2. Parseselectolax reads the server-rendered tables; toNumber-style normalization handles 1,234.50, , and accounting (913.59)-913.59.
  3. Validate — a scrape is accepted only if it validates and carries complete FII and DII equity data (all six fields finite, buy − sell ≈ net within ±1 cr) — a partial or all-zero parse is rejected and falls through to the next source, so a bad upstream can never overwrite good data with zeros.
  4. Write — the accepted payload is written to data/<date>.json + data/latest.json (git-as-DB: committed back with a rebase-before-push guard).
  5. Publish — the chart is regenerated, the commit is pushed, and deploy.yml rebuilds the self-contained static site to GitHub Pages; mirrors follow automatically.

Project layout

PathPurpose
src/fii_dii/__main__.pyScrape entry point (CLI fii-dii-scrape) — NSE → Groww → Moneycontrol → placeholder, validates, writes data/.
src/fii_dii/scrape.pyPer-source fetchers: try_nse, try_groww, try_moneycontrol.
src/fii_dii/schema.pyPure, tested core: build_payload, validate_payload, has_complete_equity.
src/fii_dii/chart.pyRegenerates the Mermaid chart between the <!-- CHART --> markers (CLI fii-dii-chart).
src/fii_dii/build_site.pyBuilds the dependency-free static site (dist/) for Pages: index.html + inline SVG chart + data/ + openapi.yaml (CLI fii-dii-build).
src/fii_dii/manifest.pyBuilds a data manifest (CLI fii-dii-manifest).
src/fii_dii/screenshot.pyCaptures docs/screenshot.png from the live/local site via Playwright.
src/fii_dii/backfill.pyOne-off historical backfill of data/.
data/*.jsonThe API payloads — one file per trading day plus latest.json.
openapi.yamlOpenAPI 3.1 contract.
.github/workflows/scrape.yml (cron), ci.yml (tests), deploy.yml (Pages), megalinter.yml.

CLI reference

Installed as console scripts (see pyproject.toml):

CommandPurpose
fii-dii-scrapeFetch today's data → data/<today>.json + data/latest.json
fii-dii-chartRegenerate the README Mermaid chart from data/
fii-dii-manifestBuild the data manifest
fii-dii-buildBuild the static site (dist/) — what GitHub Pages serves

Quick start

pip install -e ".[dev]"
python -m pytest -q               # offline test suite (deterministic)

fii-dii-scrape                    # real scrape (NSE may 404 from non-browser IPs — expected, falls back)
fii-dii-chart                     # refresh the README chart
fii-dii-build                     # build the site into dist/
npx serve dist                    # preview at http://localhost:3000

Configuration

Env vars only — never hardcoded. Names + purpose:

VariablePurpose
TELEGRAM_BOT_TOKENTelegram bot token for daily notify (optional)
TELEGRAM_CHAT_IDTarget Telegram chat id (optional)
SITEBase URL for the screenshot tool (defaults to the live site)

Testing

python -m pytest -q. The suite covers toNumber/parse edge cases, payload validation and has_complete_equity, every committed data/*.json being schema-valid, the README chart block being present, and openapi.yaml being a valid 3.1 spec that documents both endpoints and all servers. CI (ci.yml) runs the offline suite, asserts the chart is not stale, and confirms the static site builds — on every push and PR.

Schedule

Weekdays 13:00 UTC (0 13 * * 1-5, ~18:30 IST, after NSE close). Manually re-runnable via the scrape workflow (workflow_dispatch).

Part of the broader fleet

One of ~80 solo-run sites in a family of finance tools, blogs, and utilities. This one is hosted free on GitHub Pages + GitHub Actions (no Cloudflare, no backend, no ongoing cost) — the scrape runs on free Actions minutes and the data is served as static files.

Contributing

Issues and PRs welcome — see CONTRIBUTING.md and SECURITY.md. Conventional commits — they are the changelog.

License

MIT © Chirag Singhal

Status / roadmap

Stable, running daily. Roadmap: derivatives (F&O) block once a keyless source exposes it, longer historical backfill.


Disclaimer: General information, not investment advice. Institutional-flow data is descriptive, not a trade signal — do your own research.