Skip to main content

Determine whether a given date/time is a valid market trading day and within market hours

Project description

TRADING_HOURS

Determine whether a given date/time is a valid market trading day and whether the current moment falls within a configurable market window.

Installation

pip install TRADING_HOURS

Quick Start

Set environment variables in .env

PROJECT_DIRECTORY=/path/to/your/project

Config Files (required)

Place these two JSON files relative to PROJECT_DIRECTORY:

{PROJECT_DIRECTORY}/_CONFIG/trading_holidays.json
{PROJECT_DIRECTORY}/_CONFIG/market_timings.json

trading_holidays.json format:

{
  "market_holidays": [
    {
      "year": 2026,
      "holidays": [
        {
          "date": "26-Feb-2026",
          "day": "Thursday",
          "description": "Mahashivratri"
        }
      ]
    }
  ]
}

market_timings.json format:

{
  "market_timings": {
    "close": "20:00",
    "open": "01:15",
    "timezone": "UTC",
    "trading_days_in_week": 5,
    "weekend_days": ["Saturday", "Sunday"],
    "trading_minutes": 375,
    "breaks": []
  }
}

Import and use

from TRADING_HOURS import (
    is_trading_day,
    is_today_trading_day,
    was_date_trading_day,
    find_next_trading_date,
    get_date_n_trading_days_later,
    is_market_open,
    processing_market_window,
)
from datetime import date

# Check if a specific date is a trading day
is_trading_day(date(2025, 7, 4))   # → True  (Friday)
is_trading_day(date(2025, 7, 5))   # → False (Saturday)

# Check today
is_today_trading_day()             # → True / False

# Historical check
was_date_trading_day(date(2025, 1, 1))  # → True / False

# Find next trading date
find_next_trading_date(date(2025, 7, 4))       # → date(2025, 7, 7) (Monday)
find_next_trading_date(date(2025, 7, 4), inclusive=True)  # → same if already trading day

# Settlement date calculations (T+1, T+2, etc.)
get_date_n_trading_days_later(date(2025, 7, 4), 1)  # → date(2025, 7, 7)
get_date_n_trading_days_later(date(2025, 7, 4), 2)  # → date(2025, 7, 8)
get_date_n_trading_days_later(date(2025, 7, 4), 0)  # → date(2025, 7, 4) (T+0)

# Check if market is currently open
is_market_open()                   # → True / False

# Check with configurable pre/post buffers
in_window, info = processing_market_window(minutes_before_open=15, minutes_after_close=30)

Configuration

Environment Variables

Variable Required Default Description
PROJECT_DIRECTORY Yes Root directory for config file storage

Config File Paths

File Path
Holiday calendar {PROJECT_DIRECTORY}/_CONFIG/trading_holidays.json
Market timings {PROJECT_DIRECTORY}/_CONFIG/market_timings.json

market_timings.json Fields

Field Required Default Description
open Yes Market open time in HH:MM format
close Yes Market close time in HH:MM format
timezone Yes IANA timezone (e.g. Asia/Kolkata, America/New_York)
trading_days_in_week No 5 Number of trading days per week
weekend_days No ["Saturday", "Sunday"] List of weekday names that are non-trading days
trading_minutes No 0 Total active trading minutes per session (excl. breaks)
breaks No [] List of mid-session breaks with start/end times

Key Features

  1. Pure Functions Only — No OOP, no class state; all logic in module-level functions
  2. Lazy Config Loading — No side effects on import; validated on first use
  3. Cached Holiday/Timing Data — Loaded once with thread-safe double-checked locking
  4. Configurable Market Windowminutes_before_open / minutes_after_close parameters
  5. Midnight-Crossing Sessions — Supports overnight sessions (close < open)
  6. stdlib zoneinfo — Uses Python 3.9+ zoneinfo exclusively; no pytz dependency
  7. Retry with Exponential Backoff + Jitter — Config file reads retry 3 times
  8. Settlement Date Calculations — T+0, T+1, T+2, etc.

API Reference

is_trading_day(check_date: date) -> bool

Check if a specific date is a trading day (not a weekend or holiday).

  • Returns: True if trading day, False otherwise

is_today_trading_day() -> bool

Check if today (UTC) is a trading day.

  • Returns: True if today is a trading day, False otherwise

was_date_trading_day(check_date: date) -> bool

Historical date check — same logic as is_trading_day with clearer intent for past dates.

  • Returns: True if it was a trading day, False otherwise

find_next_trading_date(from_date: date, inclusive: bool = False) -> date

Find the next valid trading date from a given date.

  • inclusive: If True, returns from_date itself if already a trading day
  • Returns: The next trading date

get_date_n_trading_days_later(from_date: date, trading_days: int) -> date

Calculate the date N trading days from a given date (T+1, T+2 settlement).

  • trading_days: 0 returns from_date unchanged
  • Returns: The resulting date

is_market_open() -> bool

Check if the market is currently open (no buffer).

  • Returns: True if within market hours on a trading day, False otherwise

processing_market_window(minutes_before_open: int = 0, minutes_after_close: int = 0) -> tuple[bool, str]

Check if current time falls within the market window, with optional buffers.

  • Returns: (in_window: bool, debug_info: str) tuple

HolidayConfigError

Raised when the holidays JSON is missing, malformed, or has an invalid date entry.

MarketTimingError

Raised when market_timings.json is missing, malformed, or contains an invalid time string.

Retry Policy

Config file reads use @with_retry decorator:

  • Max attempts: 3
  • Delay: Exponential backoff (1s, 2s, 4s) with ±25% jitter
  • Retryable: All exceptions during file read
  • Not retried: FileNotFoundError and json.JSONDecodeError (raised immediately as config errors)

Error Handling

The library will raise:

  • ValueError if PROJECT_DIRECTORY is not set (on first use, not at import)
  • HolidayConfigError if the holidays JSON file is missing or malformed
  • MarketTimingError if the market timings JSON file is missing, malformed, or has missing fields
  • ValueError if minutes_before_open or minutes_after_close are negative

Test Coverage

python3 -m pytest TRADING_HOURS.py -v
Function Tier Tests What is tested
is_trading_day() 1 3 Friday true, Saturday false, Sunday false
find_next_trading_date() 1 3 Friday→Monday, inclusive flag, Saturday→Monday
get_date_n_trading_days_later() 1 4 T+0 same, T+1 Friday, T+2 Friday, T+1 Saturday
parse_trading_holidays() 2 4 valid entry, malformed skipped, weekend holiday, UserWarning
with_retry() 2 4 first-attempt success, third-attempt success, exhaustion, all exception types
_parse_time_str() 2 3 valid HH:MM, invalid format, midnight
is_today_trading_day() 1 1 returns bool
was_date_trading_day() 1 2 weekend false, weekday true
processing_market_window() 1 4 returns tuple, debug info, buffer expansion, negative raises
is_market_open() 1 1 returns bool
fetch_trading_holidays() 2 3 returns set, missing file, invalid JSON
fetch_market_timings() 2 3 returns timings, missing file, missing field
_get_holidays() 2 2 returns cached, lazy loads
_get_timings() 2 2 returns cached, lazy loads
Import validation 3 1 missing PROJECT_DIRECTORY raises

Reloading Cached Data

Holiday and timing data are cached after the first load. To force a reload:

import TRADING_HOURS
TRADING_HOURS._HOLIDAY_CACHE = None
TRADING_HOURS._TIMINGS_CACHE = None

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

market_trading_hours-7.7.7.tar.gz (23.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

market_trading_hours-7.7.7-py3-none-any.whl (24.3 kB view details)

Uploaded Python 3

File details

Details for the file market_trading_hours-7.7.7.tar.gz.

File metadata

  • Download URL: market_trading_hours-7.7.7.tar.gz
  • Upload date:
  • Size: 23.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for market_trading_hours-7.7.7.tar.gz
Algorithm Hash digest
SHA256 c072218f1f31ca54afd20813ff5f41a88d1a211b842afd78f47678bd3f7b9aeb
MD5 a5c2f532e353d0517111e8f82261fccd
BLAKE2b-256 87e55a421e697450ff9c7d9072ddf3eb6f455c326855ff675fd8dae1f15df2e9

See more details on using hashes here.

File details

Details for the file market_trading_hours-7.7.7-py3-none-any.whl.

File metadata

File hashes

Hashes for market_trading_hours-7.7.7-py3-none-any.whl
Algorithm Hash digest
SHA256 e3148a43ea11620ebcfd2688543f5e331b7d424ade1f67a94e0418b219de19b9
MD5 c968895ca60413189a595b4ca6c8c71f
BLAKE2b-256 3ebe42a3cce3ae3021682c314c717ca260e7e3cbf38e7ad8e6c180355b4b44b0

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page