Skip to content

Commit 148a9a1

Browse files
first commit
1 parent f4d9466 commit 148a9a1

File tree

5 files changed

+327
-1
lines changed

5 files changed

+327
-1
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: Python Package
2+
3+
on:
4+
push:
5+
tags: [ '*' ]
6+
branches: [ "main" ]
7+
8+
jobs:
9+
build:
10+
runs-on: ubuntu-latest
11+
strategy:
12+
fail-fast: false
13+
matrix:
14+
python-version: ["3.8", "3.9", "3.10", "3.11"]
15+
16+
steps:
17+
- uses: actions/checkout@v3
18+
19+
- name: Set up Python ${{ matrix.python-version }}
20+
uses: actions/setup-python@v3
21+
with:
22+
python-version: ${{ matrix.python-version }}
23+
24+
- name: Test with doctest
25+
run: |
26+
python -m doctest -v shinny_calendar/*
27+
28+
- name: Build package
29+
run: |
30+
pip install build
31+
python -m build
32+
33+
- name: Publish to Pypi
34+
if: startsWith(github.event.ref, 'refs/tags')
35+
uses: pypa/gh-action-pypi-publish@master
36+
with:
37+
user: __token__
38+
password: ${{ secrets.PYPI_PASSWORD }}

README.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,16 @@
11
# shinny-calendar
2-
期货交易日历工具,不依赖任何第三方库
2+
3+
获取期货交易日的工具,不依赖任何第三方库
4+
5+
默认包含 2003-2025 年的中国节假日信息。
6+
默认交易日切换时间为 20:00。
7+
8+
## 使用示例
9+
10+
```python
11+
from shinny_calendar import CalendarUtility
12+
calendar = CalendarUtility()
13+
print(calendar.today())
14+
print(calendar.now())
15+
print(calendar.trading_day())
16+
```

pyproject.toml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
[build-system]
2+
requires = ["setuptools>=61.0", "wheel"]
3+
build-backend = "setuptools.build_meta"
4+
5+
[project]
6+
name = "shinny-calendar"
7+
version = "0.1.0"
8+
description = "获取期货交易日的工具,不依赖任何第三方库"
9+
readme = "README.md"
10+
requires-python = ">=3.8"
11+
license = {file = "LICENSE"}
12+
authors = [
13+
{name = "Yanqiong Ma", email = "[email protected]"}
14+
]
15+
keywords = ["trading", "calendar", "finance", "futures"]
16+
classifiers = [
17+
"Development Status :: 3 - Alpha",
18+
"Intended Audience :: Developers",
19+
"License :: OSI Approved :: MIT License",
20+
"Programming Language :: Python :: 3",
21+
]
22+
23+
[project.urls]
24+
Homepage = "https://github.com/shinnytech/shinny-calendar"
25+
Repository = "https://github.com/shinnytech/shinny-calendar"
26+
27+
[tool.setuptools]
28+
packages = ["shinny_calendar"]
29+
30+
[tool.setuptools.dynamic]
31+
version = {attr = "shinny_calendar.__version__"}

shinny_calendar/__init__.py

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
"""
2+
Shinny Calendar - 判断交易日的 python 包.
3+
4+
提供交易日、会计日期等日历相关实用工具。
5+
"""
6+
7+
__version__ = "0.1.0"
8+
9+
import datetime
10+
from typing import List, Optional
11+
12+
from shinny_calendar.core import (
13+
_trading_day,
14+
_accounting_day,
15+
_trading_day_end_time
16+
)
17+
18+
19+
__all__ = ['CalendarUtility']
20+
21+
22+
# 默认交易日切换时间
23+
DEFAULT_CHANGE_TRADING_DAY_HOUR = 20
24+
DEFAULT_CHANGE_TRADING_DAY_MINUTE = 0
25+
26+
# 默认节假日列表
27+
_DEFAULT_HOLIDAYS = [
28+
datetime.date.fromisoformat(dt)
29+
for dt in ["2003-01-01", "2003-01-30", "2003-01-31", "2003-02-03", "2003-02-04", "2003-02-05", "2003-02-06", "2003-02-07", "2003-05-01", "2003-05-02", "2003-05-05", "2003-05-06", "2003-05-07", "2003-10-01", "2003-10-02", "2003-10-03", "2003-10-06", "2003-10-07", "2004-01-01", "2004-01-19", "2004-01-20", "2004-01-21", "2004-01-22", "2004-01-23", "2004-01-26", "2004-01-27", "2004-01-28", "2004-05-03", "2004-05-04", "2004-05-05", "2004-05-06", "2004-05-07", "2004-10-01", "2004-10-04", "2004-10-05", "2004-10-06", "2004-10-07", "2005-01-03", "2005-02-07", "2005-02-08", "2005-02-09", "2005-02-10", "2005-02-11", "2005-02-14", "2005-02-15", "2005-05-02", "2005-05-03", "2005-05-04", "2005-05-05", "2005-05-06", "2005-10-03", "2005-10-04", "2005-10-05", "2005-10-06", "2005-10-07", "2006-01-02", "2006-01-03", "2006-01-30", "2006-01-31", "2006-02-01", "2006-02-02", "2006-02-03", "2006-05-01", "2006-05-02", "2006-05-03", "2006-05-04", "2006-05-05", "2006-10-02", "2006-10-03", "2006-10-04", "2006-10-05", "2006-10-06", "2007-01-01", "2007-01-02", "2007-01-03", "2007-02-19", "2007-02-20", "2007-02-21", "2007-02-22", "2007-02-23", "2007-05-01", "2007-05-02", "2007-05-03", "2007-05-04", "2007-05-07", "2007-10-01", "2007-10-02", "2007-10-03", "2007-10-04", "2007-10-05", "2007-12-31", "2008-01-01", "2008-02-06", "2008-02-07", "2008-02-08", "2008-02-11", "2008-02-12", "2008-04-04", "2008-05-01", "2008-05-02", "2008-06-09", "2008-09-15", "2008-09-29", "2008-09-30", "2008-10-01", "2008-10-02", "2008-10-03", "2009-01-01", "2009-01-02", "2009-01-26", "2009-01-27", "2009-01-28", "2009-01-29", "2009-01-30", "2009-04-06", "2009-05-01", "2009-05-28", "2009-05-29", "2009-10-01", "2009-10-02", "2009-10-05", "2009-10-06", "2009-10-07", "2009-10-08", "2010-01-01", "2010-02-15", "2010-02-16", "2010-02-17", "2010-02-18", "2010-02-19", "2010-04-05", "2010-05-03", "2010-06-14", "2010-06-15", "2010-06-16", "2010-09-22", "2010-09-23", "2010-09-24", "2010-10-01", "2010-10-04", "2010-10-05", "2010-10-06", "2010-10-07", "2011-01-03", "2011-02-02", "2011-02-03", "2011-02-04", "2011-02-07", "2011-02-08", "2011-04-04", "2011-04-05", "2011-05-02", "2011-06-06", "2011-09-12", "2011-10-03", "2011-10-04", "2011-10-05", "2011-10-06", "2011-10-07", "2012-01-02", "2012-01-03", "2012-01-23", "2012-01-24", "2012-01-25", "2012-01-26", "2012-01-27", "2012-04-02", "2012-04-03", "2012-04-04", "2012-04-30", "2012-05-01", "2012-06-22", "2012-10-01", "2012-10-02", "2012-10-03", "2012-10-04", "2012-10-05", "2013-01-01", "2013-01-02", "2013-01-03", "2013-02-11", "2013-02-12", "2013-02-13", "2013-02-14", "2013-02-15", "2013-04-04", "2013-04-05", "2013-04-29", "2013-04-30", "2013-05-01", "2013-06-10", "2013-06-11", "2013-06-12", "2013-09-19", "2013-09-20", "2013-10-01", "2013-10-02", "2013-10-03", "2013-10-04", "2013-10-07", "2014-01-01", "2014-01-31", "2014-02-03", "2014-02-04", "2014-02-05", "2014-02-06", "2014-04-07", "2014-05-01", "2014-05-02", "2014-06-02", "2014-09-08", "2014-10-01", "2014-10-02", "2014-10-03", "2014-10-06", "2014-10-07", "2015-01-01", "2015-01-02", "2015-02-18", "2015-02-19", "2015-02-20", "2015-02-23", "2015-02-24", "2015-04-06", "2015-05-01", "2015-06-22", "2015-09-03", "2015-09-04", "2015-10-01", "2015-10-02", "2015-10-05", "2015-10-06", "2015-10-07", "2016-01-01", "2016-02-08", "2016-02-09", "2016-02-10", "2016-02-11", "2016-02-12", "2016-04-04", "2016-05-02", "2016-06-09", "2016-06-10", "2016-09-15", "2016-09-16", "2016-10-03", "2016-10-04", "2016-10-05", "2016-10-06", "2016-10-07", "2017-01-02", "2017-01-27", "2017-01-30", "2017-01-31", "2017-02-01", "2017-02-02", "2017-04-03", "2017-04-04", "2017-05-01", "2017-05-29", "2017-05-30", "2017-10-02", "2017-10-03", "2017-10-04", "2017-10-05", "2017-10-06", "2018-01-01", "2018-02-15", "2018-02-16", "2018-02-19", "2018-02-20", "2018-02-21", "2018-04-05", "2018-04-06", "2018-04-30", "2018-05-01", "2018-06-18", "2018-09-24", "2018-10-01", "2018-10-02", "2018-10-03", "2018-10-04", "2018-10-05", "2018-12-31", "2019-01-01", "2019-02-04", "2019-02-05", "2019-02-06", "2019-02-07", "2019-02-08", "2019-04-05", "2019-05-01", "2019-05-02", "2019-05-03", "2019-06-07", "2019-09-13", "2019-10-01", "2019-10-02", "2019-10-03", "2019-10-04", "2019-10-07", "2020-01-01", "2020-01-24", "2020-01-27", "2020-01-28", "2020-01-29", "2020-01-30", "2020-01-31", "2020-04-06", "2020-05-01", "2020-05-04", "2020-05-05", "2020-06-25", "2020-06-26", "2020-10-01", "2020-10-02", "2020-10-05", "2020-10-06", "2020-10-07", "2020-10-08", "2021-01-01", "2021-02-11", "2021-02-12", "2021-02-15", "2021-02-16", "2021-02-17", "2021-04-05", "2021-05-03", "2021-05-04", "2021-05-05", "2021-06-14", "2021-09-20", "2021-09-21", "2021-10-01", "2021-10-04", "2021-10-05", "2021-10-06", "2021-10-07", "2022-01-03", "2022-01-31", "2022-02-01", "2022-02-02", "2022-02-03", "2022-02-04", "2022-04-04", "2022-04-05", "2022-05-02", "2022-05-03", "2022-05-04", "2022-06-03", "2022-09-12", "2022-10-03", "2022-10-04", "2022-10-05", "2022-10-06", "2022-10-07", "2023-01-02", "2023-01-23", "2023-01-24", "2023-01-25", "2023-01-26", "2023-01-27", "2023-04-05", "2023-05-01", "2023-05-02", "2023-05-03", "2023-06-22", "2023-06-23", "2023-09-29", "2023-10-02", "2023-10-03", "2023-10-04", "2023-10-05", "2023-10-06", "2024-01-01", "2024-02-09", "2024-02-12", "2024-02-13", "2024-02-14", "2024-02-15", "2024-02-16", "2024-04-04", "2024-04-05", "2024-05-01", "2024-05-02", "2024-05-03", "2024-06-10", "2024-09-16", "2024-09-17", "2024-10-01", "2024-10-02", "2024-10-03", "2024-10-04", "2024-10-07", "2025-01-01", "2025-01-28", "2025-01-29", "2025-01-30", "2025-01-31", "2025-02-03", "2025-02-04", "2025-04-04", "2025-05-01", "2025-05-02", "2025-05-05", "2025-06-02", "2025-10-01", "2025-10-02", "2025-10-03", "2025-10-06", "2025-10-07", "2025-10-08"]
30+
]
31+
32+
33+
34+
class CalendarUtility:
35+
"""
36+
提供交易日历相关的实用工具。
37+
38+
主要功能:
39+
- 获取交易日
40+
- 获取会计日期
41+
- 获取当前日期和时间
42+
"""
43+
def __init__(
44+
self,
45+
holidays: Optional[List[datetime.date]] = _DEFAULT_HOLIDAYS,
46+
change_trading_day_hour: int = DEFAULT_CHANGE_TRADING_DAY_HOUR,
47+
change_trading_day_minute: int = DEFAULT_CHANGE_TRADING_DAY_MINUTE
48+
):
49+
"""
50+
初始化 CalendarUtility 实例。
51+
52+
Args:
53+
holidays: 自定义节假日列表,默认为 _DEFAULT_HOLIDAYS
54+
change_trading_day_hour: 交易日切换小时,默认为 20
55+
change_trading_day_minute: 交易日切换分钟,默认为 0
56+
"""
57+
self.holidays = holidays
58+
self.change_trading_day_hour = change_trading_day_hour
59+
self.change_trading_day_minute = change_trading_day_minute
60+
61+
def trading_day(self, dt: Optional[datetime.datetime] = None) -> datetime.date:
62+
"""
63+
获取指定日期的交易日。
64+
65+
Args:
66+
dt: 输入的日期时间,默认为当前时间
67+
68+
Returns:
69+
交易日的日期
70+
71+
Examples:
72+
>>> calendar_utility = CalendarUtility()
73+
>>> calendar_utility.trading_day(datetime.datetime(2025, 1, 1))
74+
datetime.date(2025, 1, 2)
75+
>>> calendar_utility.trading_day(datetime.datetime(2025, 1, 2))
76+
datetime.date(2025, 1, 2)
77+
"""
78+
return _trading_day(dt or self.now(), self.holidays, self.change_trading_day_hour, self.change_trading_day_minute)
79+
80+
def today(self) -> datetime.date:
81+
"""
82+
获取当前日期。
83+
84+
Returns:
85+
今天的日期
86+
"""
87+
return datetime.date.today()
88+
89+
def now(self) -> datetime.datetime:
90+
"""
91+
获取当前日期时间。
92+
93+
Returns:
94+
当前的日期时间
95+
"""
96+
return datetime.datetime.now()
97+
98+
def accounting_day(self, dt: Optional[datetime.datetime] = None) -> datetime.date:
99+
"""
100+
获取指定日期的会计日。
101+
102+
Args:
103+
dt: 输入的日期时间,默认为当前时间
104+
105+
Returns:
106+
会计日的日期
107+
108+
Examples:
109+
>>> calendar_utility = CalendarUtility()
110+
>>> calendar_utility.accounting_day(datetime.datetime(2025, 1, 1))
111+
datetime.date(2025, 1, 1)
112+
>>> calendar_utility.accounting_day(datetime.datetime(2025, 1, 2))
113+
datetime.date(2025, 1, 2)
114+
"""
115+
return _accounting_day(dt or self.now(), self.change_trading_day_hour, self.change_trading_day_minute)
116+
117+
def trading_day_end_time(self, dt: Optional[datetime.date] = None) -> datetime.datetime:
118+
"""
119+
获取指定交易日的结束时间。
120+
121+
Args:
122+
dt: 输入交易日
123+
124+
Returns:
125+
交易日结束时间
126+
127+
Examples:
128+
>>> calendar_utility = CalendarUtility()
129+
>>> calendar_utility.trading_day_end_time(datetime.date(2025, 1, 4))
130+
datetime.datetime(2025, 1, 4, 19, 59, 59, 999999)
131+
"""
132+
return _trading_day_end_time(dt or self.today(), self.change_trading_day_hour, self.change_trading_day_minute)

shinny_calendar/core.py

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# coding: utf-8
2+
import datetime
3+
from typing import List
4+
5+
6+
def _accounting_day(
7+
dt: datetime.datetime, change_trading_day_hour: int, change_trading_day_minute: int
8+
) -> datetime.date:
9+
"""
10+
会计入账日是指从上一个交易日的20点到当天的20点,每个自然日都可以是会计入账日
11+
12+
Args:
13+
dt (datetime.datetime): 输入的日期时间
14+
change_trading_day_hour (int): 交易日切换的小时
15+
change_trading_day_minute (int): 交易日切换的分钟
16+
17+
Returns:
18+
datetime.date: 会计入账日
19+
20+
Examples:
21+
>>> _accounting_day(datetime.datetime(2025, 1, 4, 21, 0), 20, 0)
22+
datetime.date(2025, 1, 5)
23+
>>> _accounting_day(datetime.datetime(2025, 1, 4, 19, 0), 20, 0)
24+
datetime.date(2025, 1, 4)
25+
>>> _accounting_day(datetime.datetime(2025, 1, 4, 20, 0), 20, 0)
26+
datetime.date(2025, 1, 5)
27+
"""
28+
dt_time = dt.replace(hour=change_trading_day_hour, minute=change_trading_day_minute, second=0, microsecond=0)
29+
if dt >= dt_time:
30+
dt = dt_time + datetime.timedelta(days=1)
31+
else:
32+
dt = dt_time
33+
return dt.date()
34+
35+
def _trading_day(
36+
dt: datetime.datetime,
37+
holidays: List[datetime.date],
38+
change_trading_day_hour: int,
39+
change_trading_day_minute: int
40+
) -> datetime.date:
41+
"""
42+
期货交易日
43+
交易日是指从上一个交易日的20点到当天的20点,如果是周六或周日或者节假日,则顺沿到下一个交易日
44+
45+
Args:
46+
dt (datetime.datetime): 输入的日期时间
47+
holidays (List[datetime.date]): 节假日列表
48+
change_trading_day_hour (int): 交易日切换的小时
49+
change_trading_day_minute (int): 交易日切换的分钟
50+
51+
Returns:
52+
datetime.date: 交易日
53+
54+
Examples:
55+
>>> # 测试节假日跳过
56+
>>> example_holidays = [
57+
... datetime.date(2025, 1, 30), datetime.date(2025, 1, 31), datetime.date(2025, 2, 3), datetime.date(2025, 2, 4)
58+
... ]
59+
>>> _trading_day(datetime.datetime(2025, 1, 30), example_holidays, 20, 0)
60+
datetime.date(2025, 2, 5)
61+
62+
>>> # 测试周末跳过
63+
>>> _trading_day(datetime.datetime(2025, 1, 25), example_holidays, 20, 0)
64+
datetime.date(2025, 1, 27)
65+
66+
>>> # 测试交易日切换时间
67+
>>> _trading_day(datetime.datetime(2025, 1, 4, 21, 0), example_holidays, 20, 0)
68+
datetime.date(2025, 1, 6)
69+
"""
70+
# 使用指定的小时和分钟设置交易日切换时间点
71+
dt_time = dt.replace(hour=change_trading_day_hour, minute=change_trading_day_minute, second=0, microsecond=0)
72+
73+
# 如果当前时间在交易日切换时间之后,则使用下一天
74+
if dt >= dt_time:
75+
dt = dt_time + datetime.timedelta(days=1)
76+
else:
77+
dt = dt_time
78+
79+
# 处理节假日和周末
80+
standardized_dt = dt.date()
81+
82+
# 使用提供的节假日列表
83+
holidays = set(holidays)
84+
85+
# 如果提供了节假日列表,则跳过节假日和周末
86+
while standardized_dt in holidays or standardized_dt.weekday() in {5, 6}:
87+
standardized_dt += datetime.timedelta(days=1)
88+
89+
return standardized_dt
90+
91+
def _trading_day_end_time(
92+
dt: datetime.date, change_trading_day_hour: int, change_trading_day_minute: int
93+
) -> datetime.datetime:
94+
"""
95+
输入一个日期,代表某个交易日,返回它的结束时间。
96+
97+
Args:
98+
dt (datetime.date): 输入的日期
99+
change_trading_day_hour (int): 交易日切换的小时
100+
change_trading_day_minute (int): 交易日切换的分钟
101+
102+
Returns:
103+
datetime.datetime: 交易日结束时间
104+
105+
Examples:
106+
>>> _trading_day_end_time(datetime.date(2025, 1, 4), 20, 0)
107+
datetime.datetime(2025, 1, 4, 19, 59, 59, 999999)
108+
>>> _trading_day_end_time(datetime.date(2025, 1, 4), 15, 30)
109+
datetime.datetime(2025, 1, 4, 15, 29, 59, 999999)
110+
"""
111+
return datetime.datetime.combine(dt, datetime.time(change_trading_day_hour, change_trading_day_minute)) + datetime.timedelta(microseconds=-1)

0 commit comments

Comments
 (0)