finance-dates 0.2.0__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {finance_dates-0.2.0 → finance_dates-0.3.0}/Cargo.lock +2 -2
- {finance_dates-0.2.0 → finance_dates-0.3.0}/Cargo.toml +1 -1
- {finance_dates-0.2.0 → finance_dates-0.3.0}/PKG-INFO +3 -5
- {finance_dates-0.2.0 → finance_dates-0.3.0}/README.md +1 -4
- {finance_dates-0.2.0 → finance_dates-0.3.0}/finance_dates/__init__.py +6 -1
- finance_dates-0.3.0/finance_dates/_namespace.py +104 -0
- finance_dates-0.3.0/finance_dates/tests/test_polars_namespace.py +35 -0
- {finance_dates-0.2.0 → finance_dates-0.3.0}/pyproject.toml +4 -3
- {finance_dates-0.2.0 → finance_dates-0.3.0}/rust/Cargo.lock +1 -1
- {finance_dates-0.2.0 → finance_dates-0.3.0}/rust/Cargo.toml +1 -1
- {finance_dates-0.2.0 → finance_dates-0.3.0}/rust/coverage +486 -486
- {finance_dates-0.2.0 → finance_dates-0.3.0}/.gitignore +0 -0
- {finance_dates-0.2.0 → finance_dates-0.3.0}/LICENSE +0 -0
- {finance_dates-0.2.0 → finance_dates-0.3.0}/finance_dates/tests/test_all.py +0 -0
- {finance_dates-0.2.0 → finance_dates-0.3.0}/finance_dates/tests/test_docs.py +0 -0
- {finance_dates-0.2.0 → finance_dates-0.3.0}/rust/.config/nextest.toml +0 -0
- {finance_dates-0.2.0 → finance_dates-0.3.0}/rust/python/lib.rs +0 -0
- {finance_dates-0.2.0 → finance_dates-0.3.0}/rust/src/calendar.rs +0 -0
- {finance_dates-0.2.0 → finance_dates-0.3.0}/rust/src/holiday.rs +0 -0
- {finance_dates-0.2.0 → finance_dates-0.3.0}/rust/src/lib.rs +0 -0
- {finance_dates-0.2.0 → finance_dates-0.3.0}/rust/src/range.rs +0 -0
- {finance_dates-0.2.0 → finance_dates-0.3.0}/rust/src/trading_hours.rs +0 -0
|
@@ -68,7 +68,7 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
|
|
68
68
|
|
|
69
69
|
[[package]]
|
|
70
70
|
name = "finance-dates"
|
|
71
|
-
version = "0.
|
|
71
|
+
version = "0.3.0"
|
|
72
72
|
dependencies = [
|
|
73
73
|
"chrono",
|
|
74
74
|
"chrono-tz",
|
|
@@ -78,7 +78,7 @@ dependencies = [
|
|
|
78
78
|
|
|
79
79
|
[[package]]
|
|
80
80
|
name = "finance_dates_py"
|
|
81
|
-
version = "0.
|
|
81
|
+
version = "0.3.0"
|
|
82
82
|
dependencies = [
|
|
83
83
|
"chrono",
|
|
84
84
|
"finance-dates",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: finance-dates
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Standard financial dates
|
|
5
5
|
Project-URL: Repository, https://github.com/prettygoodcapital/finance-dates
|
|
6
6
|
Project-URL: Homepage, https://github.com/prettygoodcapital/finance-dates
|
|
@@ -20,6 +20,7 @@ Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
|
20
20
|
Classifier: Programming Language :: Rust
|
|
21
21
|
Requires-Python: >=3.10
|
|
22
22
|
Requires-Dist: finance-enums<0.6,>=0.5.1
|
|
23
|
+
Requires-Dist: polars>=1.0
|
|
23
24
|
Provides-Extra: develop
|
|
24
25
|
Requires-Dist: build; extra == 'develop'
|
|
25
26
|
Requires-Dist: bump-my-version; extra == 'develop'
|
|
@@ -155,12 +156,9 @@ The Rust library crate is published as `finance-dates` and imported as
|
|
|
155
156
|
|
|
156
157
|
```toml
|
|
157
158
|
[dependencies]
|
|
158
|
-
finance-dates = "0.
|
|
159
|
+
finance-dates = "0.2.0"
|
|
159
160
|
```
|
|
160
161
|
|
|
161
162
|
```rust
|
|
162
163
|
use finance_dates::{calendar_for_exchange, date_range};
|
|
163
164
|
```
|
|
164
|
-
|
|
165
|
-
> [!NOTE]
|
|
166
|
-
> This library was generated using [copier](https://copier.readthedocs.io/en/stable/) from the [Base Python Project Template repository](https://github.com/python-project-templates/base).
|
|
@@ -113,12 +113,9 @@ The Rust library crate is published as `finance-dates` and imported as
|
|
|
113
113
|
|
|
114
114
|
```toml
|
|
115
115
|
[dependencies]
|
|
116
|
-
finance-dates = "0.
|
|
116
|
+
finance-dates = "0.2.0"
|
|
117
117
|
```
|
|
118
118
|
|
|
119
119
|
```rust
|
|
120
120
|
use finance_dates::{calendar_for_exchange, date_range};
|
|
121
121
|
```
|
|
122
|
-
|
|
123
|
-
> [!NOTE]
|
|
124
|
-
> This library was generated using [copier](https://copier.readthedocs.io/en/stable/) from the [Base Python Project Template repository](https://github.com/python-project-templates/base).
|
|
@@ -25,7 +25,12 @@ except ImportError: # pragma: no cover - sphinx fallback
|
|
|
25
25
|
raise ImportError("finance_dates native extension is not available")
|
|
26
26
|
|
|
27
27
|
|
|
28
|
-
__version__ = "0.
|
|
28
|
+
__version__ = "0.3.0"
|
|
29
|
+
|
|
30
|
+
try: # optional runtime dependency for expression namespace registration
|
|
31
|
+
from . import _namespace as _namespace # noqa: F401
|
|
32
|
+
except ImportError: # pragma: no cover - polars is optional outside expression use
|
|
33
|
+
pass
|
|
29
34
|
|
|
30
35
|
__all__ = [
|
|
31
36
|
"Calendar",
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""Polars ``.fdates`` namespace helpers for finance date operations."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from datetime import date
|
|
6
|
+
from functools import lru_cache
|
|
7
|
+
|
|
8
|
+
import polars as pl
|
|
9
|
+
|
|
10
|
+
from .finance_dates import Calendar
|
|
11
|
+
|
|
12
|
+
__all__ = []
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@lru_cache(maxsize=64)
|
|
16
|
+
def _calendar(exchange: str) -> Calendar:
|
|
17
|
+
return Calendar.from_exchange(exchange)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _shift_business_day_value(value: date | None, n: int, exchange: str) -> date | None:
|
|
21
|
+
if value is None:
|
|
22
|
+
return None
|
|
23
|
+
cal = _calendar(exchange)
|
|
24
|
+
out = value
|
|
25
|
+
step = cal.next_business_day if n >= 0 else cal.previous_business_day
|
|
26
|
+
for _ in range(abs(n)):
|
|
27
|
+
out = step(out)
|
|
28
|
+
return out
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _align_business_day_value(value: date | None, convention: str, exchange: str) -> date | None:
|
|
32
|
+
if value is None:
|
|
33
|
+
return None
|
|
34
|
+
cal = _calendar(exchange)
|
|
35
|
+
if cal.is_business_day(value):
|
|
36
|
+
return value
|
|
37
|
+
normalized = convention.strip().lower().replace("-", "_")
|
|
38
|
+
if normalized == "following":
|
|
39
|
+
return cal.next_business_day(value)
|
|
40
|
+
if normalized == "preceding":
|
|
41
|
+
return cal.previous_business_day(value)
|
|
42
|
+
if normalized == "modified_following":
|
|
43
|
+
following = cal.next_business_day(value)
|
|
44
|
+
return following if following.month == value.month else cal.previous_business_day(value)
|
|
45
|
+
if normalized == "modified_preceding":
|
|
46
|
+
preceding = cal.previous_business_day(value)
|
|
47
|
+
return preceding if preceding.month == value.month else cal.next_business_day(value)
|
|
48
|
+
raise ValueError(f"unsupported business-day convention: {convention!r}")
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _day_count_fraction_value(start: date | None, end: date | None, convention: str) -> float | None:
|
|
52
|
+
if start is None or end is None:
|
|
53
|
+
return None
|
|
54
|
+
normalized = convention.strip().lower().replace("-", "_")
|
|
55
|
+
days = (end - start).days
|
|
56
|
+
if normalized in {"act_360", "actual_360"}:
|
|
57
|
+
return days / 360.0
|
|
58
|
+
if normalized in {"act_365", "act_365f", "actual_365", "actual_365f"}:
|
|
59
|
+
return days / 365.0
|
|
60
|
+
if normalized in {"act_252", "actual_252"}:
|
|
61
|
+
return days / 252.0
|
|
62
|
+
if normalized in {"30_360", "thirty_360", "bond_30_360"}:
|
|
63
|
+
d1 = min(start.day, 30)
|
|
64
|
+
d2 = min(end.day, 30) if d1 == 30 else end.day
|
|
65
|
+
return ((end.year - start.year) * 360 + (end.month - start.month) * 30 + (d2 - d1)) / 360.0
|
|
66
|
+
raise ValueError(f"unsupported day-count convention: {convention!r}")
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@pl.api.register_expr_namespace("fdates")
|
|
70
|
+
class ExprFinanceDates:
|
|
71
|
+
def __init__(self, expr: pl.Expr) -> None:
|
|
72
|
+
self._expr = expr
|
|
73
|
+
|
|
74
|
+
def shift_business_days(self, n: int, *, exchange: str = "XNYS") -> pl.Expr:
|
|
75
|
+
return self._expr.map_elements(lambda value: _shift_business_day_value(value, n, exchange), return_dtype=pl.Date)
|
|
76
|
+
|
|
77
|
+
def align_to_business_day(self, convention: str = "following", *, exchange: str = "XNYS") -> pl.Expr:
|
|
78
|
+
return self._expr.map_elements(lambda value: _align_business_day_value(value, convention, exchange), return_dtype=pl.Date)
|
|
79
|
+
|
|
80
|
+
def day_count_fraction(self, end: pl.Expr, *, convention: str = "act_360") -> pl.Expr:
|
|
81
|
+
return pl.struct([self._expr.alias("start"), end.alias("end")]).map_elements(
|
|
82
|
+
lambda row: _day_count_fraction_value(row["start"], row["end"], convention),
|
|
83
|
+
return_dtype=pl.Float64,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@pl.api.register_series_namespace("fdates")
|
|
88
|
+
class SeriesFinanceDates:
|
|
89
|
+
def __init__(self, series: pl.Series) -> None:
|
|
90
|
+
self._series = series
|
|
91
|
+
|
|
92
|
+
def shift_business_days(self, n: int, *, exchange: str = "XNYS") -> pl.Series:
|
|
93
|
+
return self._series.map_elements(lambda value: _shift_business_day_value(value, n, exchange), return_dtype=pl.Date)
|
|
94
|
+
|
|
95
|
+
def align_to_business_day(self, convention: str = "following", *, exchange: str = "XNYS") -> pl.Series:
|
|
96
|
+
return self._series.map_elements(lambda value: _align_business_day_value(value, convention, exchange), return_dtype=pl.Date)
|
|
97
|
+
|
|
98
|
+
def day_count_fraction(self, end: pl.Series, *, convention: str = "act_360") -> pl.Series:
|
|
99
|
+
if len(self._series) != len(end):
|
|
100
|
+
raise ValueError("start and end series must have the same length")
|
|
101
|
+
values: list[float | None] = []
|
|
102
|
+
for start_value, end_value in zip(self._series, end):
|
|
103
|
+
values.append(_day_count_fraction_value(start_value, end_value, convention))
|
|
104
|
+
return pl.Series(self._series.name, values, dtype=pl.Float64)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from datetime import date
|
|
4
|
+
|
|
5
|
+
import polars as pl
|
|
6
|
+
import pytest
|
|
7
|
+
|
|
8
|
+
import finance_dates # noqa: F401
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_polars_fdates_namespace_business_day_helpers() -> None:
|
|
12
|
+
df = pl.DataFrame(
|
|
13
|
+
{
|
|
14
|
+
"trade_date": [date(2024, 7, 3), date(2024, 7, 5)],
|
|
15
|
+
"settle_date": [date(2024, 7, 8), date(2024, 7, 10)],
|
|
16
|
+
}
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
out = df.with_columns(
|
|
20
|
+
pl.col("trade_date").fdates.shift_business_days(1, exchange="XNYS").alias("next_trade"),
|
|
21
|
+
pl.col("trade_date").fdates.align_to_business_day("following", exchange="XNYS").alias("aligned"),
|
|
22
|
+
pl.col("trade_date").fdates.day_count_fraction(pl.col("settle_date"), convention="act_360").alias("dcf"),
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
assert out["next_trade"].to_list() == [date(2024, 7, 5), date(2024, 7, 8)]
|
|
26
|
+
assert out["aligned"].to_list() == [date(2024, 7, 3), date(2024, 7, 5)]
|
|
27
|
+
assert out["dcf"].to_list() == pytest.approx([5 / 360, 5 / 360])
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def test_polars_fdates_namespace_modified_following() -> None:
|
|
31
|
+
df = pl.DataFrame({"d": [date(2024, 8, 31)]})
|
|
32
|
+
|
|
33
|
+
out = df.with_columns(pl.col("d").fdates.align_to_business_day("modified_following", exchange="XNYS").alias("rolled"))
|
|
34
|
+
|
|
35
|
+
assert out["rolled"].to_list() == [date(2024, 8, 30)]
|
|
@@ -13,7 +13,7 @@ authors = [
|
|
|
13
13
|
description = "Standard financial dates"
|
|
14
14
|
readme = "README.md"
|
|
15
15
|
license = { text = "Apache-2.0" }
|
|
16
|
-
version = "0.
|
|
16
|
+
version = "0.3.0"
|
|
17
17
|
requires-python = ">=3.10"
|
|
18
18
|
keywords = []
|
|
19
19
|
|
|
@@ -33,6 +33,7 @@ classifiers = [
|
|
|
33
33
|
|
|
34
34
|
dependencies = [
|
|
35
35
|
"finance-enums>=0.5.1,<0.6",
|
|
36
|
+
"polars>=1.0",
|
|
36
37
|
]
|
|
37
38
|
|
|
38
39
|
[project.optional-dependencies]
|
|
@@ -63,9 +64,9 @@ Repository = "https://github.com/prettygoodcapital/finance-dates"
|
|
|
63
64
|
Homepage = "https://github.com/prettygoodcapital/finance-dates"
|
|
64
65
|
|
|
65
66
|
[tool.bumpversion]
|
|
66
|
-
current_version = "0.
|
|
67
|
+
current_version = "0.3.0"
|
|
67
68
|
commit = true
|
|
68
|
-
tag =
|
|
69
|
+
tag = false
|
|
69
70
|
commit_args = "-s"
|
|
70
71
|
|
|
71
72
|
[[tool.bumpversion.files]]
|