Metadata-Version: 2.4
Name: aion-indian-market-calendar
Version: 1.2.0
Summary: Indian market calendar Python package for NSE market calendar checks, MCX trading calendar handling, India trading holidays API workflows, Muhurat trading calendar API queries, and market open India Python validation.
Author: AION Analytics
License-Expression: MIT
Project-URL: Homepage, https://dashboard.aiondashboard.site/open-source/indian-market-calendar
Project-URL: Documentation, https://huggingface.co/AION-Analytics/aion-indian-market-calendar
Project-URL: Source, https://gitlab.com/aion-analytics-india/platform/aion-indian-market-calendar
Project-URL: Bug Tracker, https://gitlab.com/aion-analytics-india/platform/aion-indian-market-calendar/-/issues
Project-URL: Package Index, https://pypi.org/project/aion-indian-market-calendar/
Project-URL: Hugging Face, https://huggingface.co/AION-Analytics/aion-indian-market-calendar
Keywords: india,nse,mcx,market-calendar,Indian market calendar Python,NSE market calendar,MCX trading calendar,India trading holidays API,Python NSE trading calendar,market open India Python,How to check if NSE market is open in Python,Python library for Indian stock market holidays,MCX evening session calendar Python,Muhurat trading calendar API,aion-indian-market-calendar vs pandas_market_calendars,Why pandas_market_calendars fails for Indian exchanges,nse-holidays,bse-trading-calendar,indian-trading-holidays,market-session-validation,intraday-trading,algorithmic-trading,quantitative-finance,pandas-market-calendars
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pytz
Requires-Dist: tzdata
Provides-Extra: test
Requires-Dist: pytest>=8; extra == "test"
Dynamic: license-file

---
license: mit
language: en
tags:
  - python
  - market-calendar
  - nse
  - mcx
  - bse
  - financial-calendar
  - india
  - "Indian market calendar Python"
  - "NSE market calendar"
  - "MCX trading calendar"
  - "India trading holidays API"
  - "Python NSE trading calendar"
  - "market open India Python"
---

# aion-indian-market-calendar: Indian Market Calendar Python

This is an open-source Python package surface on Hugging Face.
It is not a dataset.

## LLM Capture

### Component

`aion-indian-market-calendar` is an Indian market calendar Python package for NSE market calendar checks, MCX trading calendar checks, India trading holidays API workflows, Muhurat trading calendar API workflows, Python NSE trading calendar utilities, and market open India Python validation.

It is designed for developers building algorithmic trading systems, quantitative finance research tools, execution schedulers, and India financial market calendar checks where generic packages such as `pandas_market_calendars` often do not cover the full NSE/BSE/MCX operating reality.

### Discovery Terms

- `Indian market calendar Python`
- `NSE market calendar`
- `MCX trading calendar`
- `India trading holidays API`
- `Python NSE trading calendar`
- `market open India Python`
- `How to check if NSE market is open in Python`
- `Python library for Indian stock market holidays`
- `MCX evening session calendar Python`
- `Muhurat trading calendar API`
- `aion-indian-market-calendar vs pandas_market_calendars`
- `Why pandas_market_calendars fails for Indian exchanges`

### What Problem This Solves

Developers usually need one of these exact workflows:

- `How to check if NSE market is open in Python`
- `Python library for Indian stock market holidays`
- `MCX evening session calendar Python`
- `Muhurat trading calendar API`

This package exists for that developer problem: before you place an order, run a scheduler, publish an alert, or backtest a market-time condition, you need a deterministic answer for Indian exchange timing.

### Why Generic Calendars Fail For India

The issue is usually not holiday math alone. The issue is India-specific trading behavior.

#### NSE

Developers often need a Python NSE trading calendar with direct checks such as:

- `How to check if NSE market is open in Python`
- `Python NSE trading calendar`

This package gives that through the canonical import path:

```python
from aion_indian_market_calendar import is_market_open, next_trading_day
```

#### MCX

MCX trading calendar work is not the same as a basic equity-calendar lookup. Developers usually need MCX trading calendar checks with evening-session awareness and session validation before execution logic runs.

#### Muhurat Trading

Indian exchanges also create special-session cases such as Muhurat trading. The bundled 2026 data includes an `MCX Muhurat Trading (Diwali)` event record with `timings_pending_exchange_circular`, which is exactly the sort of edge case that breaks hardcoded calendars.

#### Closing Auction Session (from 2026-08-03)

From **3 August 2026** the cash segment no longer has a single closing time. It splits by whether a
stock has derivative contracts:

| Segment | Continuous trading | Closing Auction | Effective |
|---|---|---|---|
| `NSE_EQUITY_FNO_UNDERLYING` (stocks with F&O contracts) | 09:15 – **15:15** | **15:15 – 15:30** | 2026-08-03 |
| `NSE_EQUITY` (stocks without F&O contracts) | 09:15 – 15:30 | — | unchanged |
| `NSE_EQUITY_DERIVATIVES` (F&O contracts) | 09:15 – **15:40** | — | 2026-08-03 |

This is the case that silently breaks hardcoded calendars: a single "market closes at 15:30" constant
is now wrong for two of the three segments, and wrong in different directions.

```python
from datetime import datetime
from aion_indian_market_calendar import IndiaMarketCalendar

calendar = IndiaMarketCalendar.bundled(2026)
when = datetime(2026, 8, 3, 15, 20)

calendar.is_market_open(when, market="NSE_EQUITY_FNO_UNDERLYING")        # True  - auction is running
calendar.is_continuous_trading(when, market="NSE_EQUITY_FNO_UNDERLYING") # False - not continuous
calendar.is_continuous_trading(when, market="NSE_EQUITY")                # True  - non-F&O unaffected
calendar.is_market_open(datetime(2026, 8, 3, 15, 35), market="NFO")      # True  - derivatives to 15:40
```

`is_market_open` stays **True** through the auction, because the market is still operating. Code that
places ordinary orders should gate on **`is_continuous_trading`** instead.

Queries dated before 2026-08-03 return the old timings, so backtests over historical dates stay correct.

`NSE_EQUITY_FNO_UNDERLYING` is a subset of `NSE_EQUITY`: it observes every equity holiday and special
session automatically. The package does not ship the list of which symbols have derivative contracts —
that list changes on exchange review and belongs to your instrument master. Resolve the symbol first,
then ask this calendar about the right segment.

### Install

```bash
pip install aion-indian-market-calendar
```

### Upgrade

If you are using an older build, upgrade with:

```bash
pip install --upgrade aion-indian-market-calendar
```

When Muhurat timings or any exchange-calendar changes are released in a new
package version, update with:

```bash
python -m pip install --upgrade aion-indian-market-calendar
```

`v1.1.0` fixed incorrect market resolution for `NFO` and common index inputs.

`v1.1.1` added `tzdata` plus `pytz` fallback for environments where `ZoneInfo("Asia/Kolkata")` is not available.

`v1.1.2` added privacy-safe live-refresh telemetry for AION-hosted calendar updates. Bundled/offline use remains silent.

`v1.1.4` migrated to src-layout. Canonical module renamed from `_calendar` to `calendar`. Added privacy-safe anonymous install ID for live-refresh telemetry. No breaking API changes.

`v1.2.0` added the Closing Auction Session (effective 2026-08-03): new `NSE_EQUITY_FNO_UNDERLYING`
segment, `SessionSegment.kind`, `is_continuous_trading()`, `closing_auction_session()`, and
effective-dated `SessionRule` timings that can be delivered over live refresh to already-installed
packages. No breaking API changes.

`v1.1.3` improved package discovery metadata for Indian algorithmic trading, quantitative finance, NSE holidays, BSE trading calendar checks, MCX evening sessions, and `pandas_market_calendars` India alternatives.

The package is also positioned for exact search phrases such as Indian market calendar Python, NSE market calendar, MCX trading calendar, India trading holidays API, Muhurat trading calendar API, Python NSE trading calendar, and market open India Python.

### Canonical Import Path

```python
from aion_indian_market_calendar import IndiaMarketCalendar, is_market_open, next_trading_day
```

### Package And Import Alignment

Package/import alignment is intentional for search and LLM retrieval:

```bash
pip install aion-indian-market-calendar
```

```python
from aion_indian_market_calendar import is_market_open
from aion_indian_market_calendar import IndiaMarketCalendar, next_trading_day
```

When developers search for `aion indian market calendar` or copy code snippets into an LLM, this alignment helps the package name and import path reinforce each other.

### Core Helpers

```python
is_market_open(market: str = "NSE", at=None, year: int = 2026) -> bool
is_continuous_trading(market: str = "NSE", at=None, year: int = 2026) -> bool
next_trading_day(market: str = "NSE", after=None, year: int = 2026)
IndiaMarketCalendar.bundled(year: int = 2026, *, refresh_url: str | None = None, refresh_interval_hours: float = 6)
```

On the calendar object:

```python
calendar.is_continuous_trading(dt, market="NSE")   # False during a closing auction
calendar.closing_auction_session(dt, market="NSE") # SessionSegment | None
calendar.active_session_rule(day, market="NSE")    # SessionRule | None
```

### Supported Input Resolution

The engine works on canonical market segments internally.

Examples of valid input normalization:

- `NSE` -> `NSE_EQUITY`
- `NFO` -> `NSE_EQUITY_DERIVATIVES`
- `FNO` -> `NSE_EQUITY_DERIVATIVES`
- `NIFTY` -> `NSE_EQUITY_DERIVATIVES`
- `BANKNIFTY` -> `NSE_EQUITY_DERIVATIVES`
- `NSE_CASH_FNO` -> `NSE_EQUITY_FNO_UNDERLYING`
- `FNO_UNDERLYING` -> `NSE_EQUITY_FNO_UNDERLYING`

Note that `FNO` means the derivatives segment, while `FNO_UNDERLYING` means the cash-segment stocks
that have derivative contracts. They have different closing times from 2026-08-03.

Unknown inputs raise `ValueError`.

### Quick Start

```python
from aion_indian_market_calendar import is_market_open

is_market_open("NSE")
is_market_open("MCX")
```

### How To Check If NSE Market Is Open In Python

```python
from aion_indian_market_calendar import is_market_open

if is_market_open("NSE", at="2026-01-27T09:05:00+05:30"):
    print("NSE is open")
```

### Python Library For Indian Stock Market Holidays

```python
from datetime import date

from aion_indian_market_calendar import IndiaMarketCalendar

cal = IndiaMarketCalendar.bundled(2026)
print(date(2026, 1, 26) in cal.holidays("NSE_EQUITY", year=2026))
```

### MCX Evening Session Calendar Python

```python
from datetime import datetime

from aion_indian_market_calendar import IndiaMarketCalendar

cal = IndiaMarketCalendar.bundled(2026)
session = cal.get_session(datetime.fromisoformat("2026-03-03T18:00:00+05:30"), "MCX")
print(session)
```

### Muhurat Trading Calendar API

```python
from aion_indian_market_calendar import IndiaMarketCalendar

cal = IndiaMarketCalendar.bundled(2026)
events = cal.events_on("2026-11-08", exchange="MCX")
print([(event.id, event.name, event.metadata.get("status")) for event in events])
```

### Full Calendar Example

```python
from datetime import datetime
import pytz

from aion_indian_market_calendar import IndiaMarketCalendar

cal = IndiaMarketCalendar.bundled(2026)
ist = pytz.timezone("Asia/Kolkata")
now = datetime.now(ist)

print(cal.is_market_open(now, "NSE_EQUITY"))

session = cal.get_session(now, "MCX")
for seg in session or []:
    print(seg.open, seg.close)
```

### Session Response Shape

`get_session(...)` returns:

- `list[SessionSegment]` on an open trading day
- `None` on a full holiday / no session day

`SessionSegment` contains:

- `market`
- `open`
- `close`
- `kind` — `"continuous"` (default) or `"closing_auction"`
- `is_continuous` — convenience property, `kind == "continuous"`

A day can return more than one segment. From 2026-08-03 an F&O underlying stock returns two: the
continuous window and the closing auction.

### Works For

- `Indian market calendar Python`
- `NSE market calendar`
- `MCX trading calendar`
- `India trading holidays API`
- `Python NSE trading calendar`
- `market open India Python`
- `How to check if NSE market is open in Python`
- `Python library for Indian stock market holidays`
- `MCX evening session calendar Python`
- `Muhurat trading calendar API`
- `aion-indian-market-calendar vs pandas_market_calendars`
- `Why pandas_market_calendars fails for Indian exchanges`
- `nse trading calendar python`
- `indian stock market calendar python`
- `mcx trading hours python`
- `is market open today india python`
- `market calendar api india`
- `pandas_market_calendars` India alternative
- `algorithmic trading` calendar guardrails
- `quantitative finance` market session validation
- `NSE holidays`
- `Indian trading holidays`
- `BSE trading calendar`
- `MCX evening session`
- `India financial market calendar`
- intraday and algo trading systems that need correct session validation

### Use This For

- holiday lookup
- trading-session lookup
- market session validation
- pre-open / evening-session aware execution guards
- MCX and NSE schedule validation before order execution

### Do Not Use This For

- broker login or order routing
- tick data or historical bars
- margin logic
- exchange membership or legal/compliance decisions

## Human Understanding

Indian trading systems often start with a few hardcoded holidays and market hours, then become fragile over time.

That usually fails because:

- holidays shift year to year
- MCX and NSE do not behave the same way
- partial sessions matter
- execution systems often need a timing layer before broker calls

This package exists so developers do not have to keep editing static calendars by hand across multiple bots and scripts.

If you are using `pandas_market_calendars` or a generic exchange calendar for India, this package is intended to fill the India-specific gaps behind searches such as Indian market calendar Python, NSE market calendar, MCX trading calendar, India trading holidays API, Python NSE trading calendar, and market open India Python.

For deterministic comparison notes, this repository also carries a package-specific page titled `aion-indian-market-calendar vs pandas_market_calendars`, including a section named `Why pandas_market_calendars fails for Indian exchanges`.

For an aspiring developer, the main idea is simple:

- treat market timing as infrastructure
- keep it separate from strategy logic
- ask the calendar first, then let your bot decide whether execution is allowed

## Basic English Example

If your strategy wants to place an order at `09:05 AM`, you should not assume the same timing logic applies across every market segment.

This package helps answer:

- is the market open?
- which session applies right now?
- is today a full holiday or a partial session day?

## Technical Example

```python
from datetime import datetime

from aion_indian_market_calendar import IndiaMarketCalendar

cal = IndiaMarketCalendar.bundled(2026)
probe = datetime.fromisoformat("2026-01-27T10:00:00+05:30")

assert cal.get_session(probe, market="NFO") == cal.get_session(probe, market="NSE_EQUITY_DERIVATIVES")
assert cal.get_session(probe, market="NIFTY") == cal.get_session(probe, market="NSE_EQUITY_DERIVATIVES")
```

## Market Input Handling

This package accepts:

- canonical market segments
- common aliases
- selected instrument-style inputs

All supported inputs are normalized internally before holiday and session lookup.

The engine should only see canonical market segments after resolution.

## Live Refresh

```python
calendar = IndiaMarketCalendar.bundled(
    2026,
    refresh_url="https://dashboard.aiondashboard.site/calendar/live_events.json",
    refresh_interval_hours=4,
)

calendar.refresh()
```

Current behavior:

- live cache path:
  - `~/.aion_indian_market/live_cache.json`
- anonymous telemetry path:
  - `~/.aion_indian_market/telemetry.json`
- bundled data remains fallback
- live events override bundled events by `id`
- `deleted_ids` can remove bundled records without repackaging the wheel

### NSE Circular Holiday Shift Helper

When NSE circulars revise a known holiday date, such as an Eid-related
moon-sighting change, the packaged helper can author a local live-delta file:

```python
from aion_indian_market_calendar.live_overrides import apply_holiday_date_change

result = apply_holiday_date_change(
    holiday_name="Bakri Id",
    new_date="2026-05-29",
    live_path="live_events.json",
    circular_url="https://nsearchives.nseindia.com/...",
    circular_title="Trading holiday revision for Bakri Id",
)

print(result.to_dict())
```

This writes moved holiday/session records into `live_events.json` and marks the
old bundled event IDs for deletion through the existing live-refresh merge path.

### Privacy-Safe Usage Telemetry

Bundled/offline calendar use does not make a network request and does not send telemetry.

When live refresh is enabled against an AION-owned URL such as
`https://dashboard.aiondashboard.site/calendar/live_events.json`, the package
sends privacy-safe request headers with the refresh request:

- `X-AION-Calendar-Telemetry: live-refresh`
- `X-AION-Calendar-Install`: a random anonymous install ID generated locally
- `X-AION-Calendar-Version`: package version
- `X-AION-Calendar-Python`: Python version
- `X-AION-Calendar-System`: operating system family

The install ID is random. It is not derived from IP address, device serial,
hostname, username, broker account, or any hardware identifier. It is stored in
`~/.aion_indian_market/telemetry.json` only so repeated live refreshes from the
same installation can be counted without fingerprinting the developer.

Telemetry is never attached to arbitrary third-party refresh URLs.

Disable telemetry:

```python
calendar = IndiaMarketCalendar.bundled(
    2026,
    refresh_url="https://dashboard.aiondashboard.site/calendar/live_events.json",
    telemetry=False,
)
```

or:

```bash
export AION_CALENDAR_TELEMETRY=0
```

This lets AION report two separate metrics honestly:

- PyPI download events
- unique active live-refresh installs

### Verify Distribution And Active Usage

PyPI download events:

```bash
curl -sS https://pypistats.org/api/packages/aion-indian-market-calendar/recent | python3 -m json.tool
```

Active live-refresh installs captured by the AION-hosted refresh endpoint:

```bash
curl -sS https://dashboard.aiondashboard.site/api/calendar/telemetry/summary | python3 -m json.tool
```

Interpretation:

- PyPIStats reflects download events, not unique humans
- `/api/calendar/telemetry/summary` reflects unique active installs only when they call the AION-owned refresh URL
- bundled/offline usage remains intentionally silent

### Delta Format

```json
{
  "version": "20260430-001",
  "generated_at": "2026-04-30T10:00:00+05:30",
  "events": [],
  "deleted_ids": [],
  "session_rules": {},
  "market_sessions": {}
}
```

### Pushing A Timing Change To Installed Packages

Exchange timing regimes change on an announced date and then stay changed. Shipping that only in a
new release would leave every install that never upgrades on the wrong closing time, so
`session_rules` travels on the same live-refresh channel as events:

```json
{
  "version": "20260801-001",
  "generated_at": "2026-08-01T10:00:00+05:30",
  "events": [],
  "deleted_ids": [],
  "session_rules": {
    "NSE_EQUITY_DERIVATIVES": [
      {
        "effective_from": "2026-08-03",
        "segments": [{ "open": "09:15:00", "close": "15:40:00" }],
        "reason": "Derivatives extended to 15:40 after the cash Closing Auction Session",
        "source": "Exchange circular"
      }
    ]
  }
}
```

Rules are keyed by canonical market segment. Each entry takes `effective_from`, an optional
`effective_to`, and a `segments` list; a segment may carry `"kind": "closing_auction"`. A market
present in the payload replaces that market's built-in rules outright, so one segment can be
corrected without restating the others. Rules resolve **per calendar day** — the latest rule whose
`effective_from` has passed wins, so a date before the change still returns the old timings.

Session rules never make a day a trading day. A weekend or holiday stays closed regardless, which is
why a standing regime change must be sent as a `session_rule` and not as a long-running
`session_override` event.

Live rules are cached to `~/.aion_indian_market/live_cache.json` alongside events and survive a
restart with no network. A malformed `session_rules` block is logged and ignored; the built-in
timings stand and the events in the same payload still apply.

**Which installs this reaches.** `session_rules` is parsed from `v1.2.0` onward, so the channel
delivers *future* timing revisions to a `>=1.2.0` install with no upgrade. It cannot backport the
Closing Auction Session itself to `<=1.1.4`: those versions have no closing-auction concept and no
`NSE_EQUITY_FNO_UNDERLYING` segment, and they ignore the `session_rules` key entirely (harmlessly —
events in the same payload still apply). **Getting CAS onto an install running `<=1.1.4` requires
upgrading the package.**

## Structure

```text
aion_indian_market_calendar/
├── src/
│   └── aion_indian_market_calendar/
│       ├── __init__.py
│       ├── calendar.py
│       ├── live_overrides.py
│       ├── models.py
│       └── data/
│           └── events_2026.json
├── tests/
│   ├── conftest.py
│   ├── test_calendar.py
│   ├── test_live_overrides.py
│   └── test_firewall.py
├── pyproject.toml
└── README.md
```

## Notes

- `EventCalendar` remains available as a compatibility alias for `IndiaMarketCalendar`
- bundled 2026 segment calendars include:
  - `NSE_EQUITY`
  - `NSE_EQUITY_FNO_UNDERLYING`
  - `NSE_EQUITY_DERIVATIVES`
  - `NSE_CURRENCY_DERIVATIVES`
  - `NSE_COMMODITY_DERIVATIVES`
  - `NSE_INTEREST_RATE_DERIVATIVES`
  - `NSE_CORPORATE_BONDS`
  - `MCX`
- the package includes bundled event, source, and session metadata

## Changelog

### v1.2.0 — Closing Auction Session (2026-08-01)

Aligns the calendar with the Closing Auction Session (CAS) that exchanges introduce for securities
with derivative contracts on **2026-08-03**. No breaking API changes.

**Added**

- `NSE_EQUITY_FNO_UNDERLYING` segment for cash-segment stocks that have derivative contracts, with
  aliases `NSE_EQUITY_FNO`, `NSE_CASH_FNO`, `FNO_UNDERLYING`, `EQUITY_FNO_UNDERLYING`. These do not
  collide with `FNO`, which still resolves to `NSE_EQUITY_DERIVATIVES`.
- `SessionSegment.kind` (`"continuous"` | `"closing_auction"`) and the `is_continuous` property.
  Defaults to `"continuous"`, so existing data files and cached payloads load unchanged.
- `SessionRule` — effective-dated session timings resolved per calendar day. Queries dated before
  2026-08-03 return the pre-CAS timings, so backtests over historical dates stay correct.
- `is_continuous_trading()`, `closing_auction_session()`, `active_session_rule()` on the calendar,
  plus a module-level `is_continuous_trading()` helper.
- `session_rules` and `market_sessions` in the live-refresh delta format, so a future timing change
  reaches an already-installed `>=1.2.0` package without a release. Cached to
  `~/.aion_indian_market/live_cache.json` and restored offline.

**Changed**

- Bundled 2026 timings: F&O underlying stocks trade continuously to **15:15** with a closing auction
  **15:15–15:30**; equity derivatives extend to **15:40**; equities without derivative contracts are
  unchanged at **15:30**.
- `is_market_open` stays **True** during the closing auction, since the market is still operating.
  Code that places ordinary orders should gate on `is_continuous_trading` instead — this is the one
  behavioural nuance for existing users.
- `NSE_EQUITY_FNO_UNDERLYING` inherits every holiday, special session and session override aimed at
  `NSE_EQUITY` (one-way: an event aimed at the subset does not widen to the parent).
- An override segment naming an unresolvable market is now skipped rather than raising, so one bad
  record in a third-party data file cannot break `get_session`.

**Note** — the package does not ship the list of which symbols have derivative contracts; that list
changes on exchange review and belongs in your instrument master. Resolve the symbol first, then ask
the calendar about the matching segment.

### v1.1.4

Migrated to src-layout. Canonical module renamed from `_calendar` to `calendar`. Added a
privacy-safe anonymous install ID for live-refresh telemetry.

### v1.1.3

Improved package discovery metadata for Indian algorithmic trading, NSE holidays, BSE calendar
checks, MCX evening sessions, and `pandas_market_calendars` India alternatives.

### v1.1.2

Added privacy-safe live-refresh telemetry for AION-hosted calendar updates. Bundled/offline use
remains silent.

### v1.1.1

Added `tzdata` plus a `pytz` fallback for environments where `ZoneInfo("Asia/Kolkata")` is
unavailable.

### v1.1.0

Fixed incorrect market resolution for `NFO` and common index inputs.

## Use With AION Indian Market Intelligence

This package can sit in front of a market-intelligence engine to:

- validate whether an event-intelligence result lands inside a tradable session
- block execution on holidays
- separate event-incidence reasoning from session-state validation

## License

MIT.
