Skip to main content

Pythonic Business (Trading) Calendar.

Project description

Bizcal – Pythonic Business (Trading) Calendar

Bizcal is a powerful yet simple business calendar package with three unique features:

  • Compatibility: bizcal.Date is a drop-in replacement for datetime.date.
  • Pythonic: intuitive syntax for calendar semantics.
    • yesterday = day - 1
    • next_trading_day = day >> 1
  • Holiday-aware: not just when not trading, but also why.

Bizcal is listed on PyPI.

Compatibility

Bizcal abstracts dates with Date class, a direct subclass of the standard datetime.date, allowing it to seamlessly integrate into legacy codebases as a drop-in replacement for datetime.date.

Additionally, Date includes several convenient methods and properties designed to simplify your code.

Pythonic

Code snippets speak for themselves. Check more in unit tests.

from bizcal import Calendar

cne = Calendar([
    '2023: 0101-2, 0121-29, 0405, 0429-0503, 0622-5, 0929-1008',
    '2024: 0101, 0209-18, 0404-7, 0501-5, 0608-10, 0914-17, 1001-7',
])

day = cne('20240210')

# shift trading day with >> and <<
while not day:
    day = day >> 1
prev_trading_day = day << 1
next_trading_day = day >> 1

# shift calendar day with + and -
yesterday = day - 1
tomorrow = day + 1

# period abstraction
period = cne[20240101, 20240131]
print(len(period), 'trading days')

# whole period
print(sum(1 for d in cne['*'].days if d.open), 'trading days')

# iterate trading days
for day in period:
    print(f'{day} is a trading day')

# iterate calendar days
for day in period.days:
    flag = day and 'trading' or (day.holiday and 'holiday' or 'weekend')
    print(f'{day} is {flag}')

Holiday-aware

Certain exchanges, like SHFE and DCE, adjust their trading hours based on holiday schedules. Bizcal not only identifies business (open) and non-business (closed) days but also specifies if a non-business day is a holiday.

API Reference

Calendar definition

from bizcal import Calendar
cal = Calendar('/path/to/calendar.file')
cal = Calendar([
    '2023: 0101-2, 0121-29, 0405, 0429-0503, 0622-25, 0929-1008',
    '2024: 0101, 0209-18, 0404-7, 0501-5, 0608-10, 0914-17, 1001-7',
])
cal.min # 2023-01-01
cal.max # 2024-12-31

The Calendar(spec) constructor accepts spec as either a string or a list of strings.

  • If spec is a string, it is treated as a path to a calendar definition file. Each line in the file defines the holidays (and potentially weekends) for a specific year.
  • If spec is a list of strings, each string represents a line of calendar definitions for one year.
  • The year line format is YYYY: holidays, holidays, ..., where holidays are specified as date ranges in the format MMDD, MMDD-DD, or MMDD-MMDD.
  • Properties min and max gives lower- and upper-bound of this calendar.

Exclude dates from business days

from bizcal import Calendar
cal = Calendar('2024: 0101, 0209-18, 0404-7, 0501-5, 0608-10, 0914-17, 1001-7')
cal.exclude([20240102, '20240103'])

cal(20240102).open    # False
cal(20240102).holiday # True
  • In some cases, ad-hoc exclusion of special days could be convenient.
  • Excluded dates are treated as holidays.
  • YYYYMMDD string, integer, or a list of them are accepted.

Date creation

Date objects can only be created from a Calendar object using call syntax. Multiple input formats are supported.

cal = Calendar([...])
day = cal(20240501)     # integer
day = cal('20240501')   # YYYYMMDD (string)
day = cal('2024-05-01') # YYYY-MM-DD
day = cal('2024.05.01') # YYYY.MM.DD
day = cal(2024, 5, 1)   # year, month, day
day = cal((2024, 5, 1)) # tuple
day = cal([2024, 5, 1]) # list
day = cal(date)         # date or even Date object
day = cal([2025, 1, 1]) # error, as date is out of calendar scope

Date manipulation

A Date object can be shifted both as calendar days and business days. The + and - operators shift the date as calendar days, while the >> and << operators shift the date as business days.

cal = Calendar([...])
day = cal(20240501)

day + 10   # 2024-05-11
day - 1    # 2024-04-30

day >> 10  # 2024-05-17
day << 10  # 2024-04-17

Date methods and properties

Date is a subclass of datetime.date, so all date methods are supported.

Extra Properties

  • Date.open: Indicates if it is a business day (boolean).
    • Date.__bool__(): Boolean operator, returns if it is a business day.
  • Date.holiday: Indicates if it is a holiday (boolean).
  • Date.num: Returns the date as an YYYYMMDD integer.
  • Date.str: Returns the date as a "YYYYMMDD" string.
  • Date.eom: Indicates if it is the end of the month (boolean).

Extra Methods

  • Date.spec(sep=''): Returns the date as a YYYY{sep}MM{sep}DD string.
  • Date.shift(days): Performs an explicit business day shift.

Period definition

A period of dates can be defined using the indexing (brackets) syntax.

cal = Calendar([...])
period = cal[20240101, 20240131]
jan = cal['20240101-31']
q1 = cal['202401-3']
h1 = cal['202401-06']
years = cal['2023-4']

period = cal[cal('20240101'), cal(2024, 1, 1) + 30]

print(len(jan))  # count trading days
print(jan.spec)  # period spec string

The length of a period (len(period)) is the number of business days in that period.

Period iteration

The primary use case of a period is date iteration. Two generator properties, bizdays and days, are implemented for business day and calendar day iteration, respectively. The default iteration method (__iter__) is for business days.

# iterate business days
for day in cal['202401']:
    print(f'{day} is a trading day')

# iterate calendar days
for day in cal['20240215-20'].days:
    flag = day and 'trading' or (day.holiday and 'holiday' or 'weekend')
    print(f'{day} is {flag}')

Date span parsing

Static method Calendar.span(spec: str) parses a string spec into (beg, end) tuple of dates. datetime.date objects are returned.

from bizcal import Calendar

beg, end = Calendar.span('202402')

Project details


Download files

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

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

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

bizcal-0.4.0-py3-none-any.whl (6.9 kB view details)

Uploaded Python 3

File details

Details for the file bizcal-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: bizcal-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 6.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for bizcal-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1b205619c677aaf673d7459a1da0007b89a0977d0c5e4d4f19870bf8cccb4f6e
MD5 9a7bc50e87dbdd26d09a407dbb3b9cae
BLAKE2b-256 7232db30cbabad7a04c9cab24f5202de0d8d1ff6377c8170d0aff55682228456

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