openseries 1.5.7__py3-none-any.whl → 1.7.0__py3-none-any.whl
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.
- openseries/__init__.py +43 -0
- openseries/_common_model.py +237 -295
- openseries/_risk.py +9 -10
- openseries/datefixer.py +41 -36
- openseries/frame.py +120 -721
- openseries/load_plotly.py +10 -8
- openseries/portfoliotools.py +612 -0
- openseries/series.py +46 -64
- openseries/simulation.py +31 -38
- openseries/types.py +37 -24
- {openseries-1.5.7.dist-info → openseries-1.7.0.dist-info}/LICENSE.md +1 -1
- {openseries-1.5.7.dist-info → openseries-1.7.0.dist-info}/METADATA +4 -5
- openseries-1.7.0.dist-info/RECORD +16 -0
- openseries-1.5.7.dist-info/RECORD +0 -15
- {openseries-1.5.7.dist-info → openseries-1.7.0.dist-info}/WHEEL +0 -0
openseries/_risk.py
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
from __future__ import annotations
|
4
4
|
|
5
5
|
from math import ceil
|
6
|
-
from typing import
|
6
|
+
from typing import TYPE_CHECKING, cast
|
7
7
|
|
8
8
|
from numpy import (
|
9
9
|
mean,
|
@@ -13,21 +13,21 @@ from numpy import (
|
|
13
13
|
)
|
14
14
|
from pandas import DataFrame, Series
|
15
15
|
|
16
|
-
|
16
|
+
if TYPE_CHECKING:
|
17
|
+
from .types import LiteralQuantileInterp # pragma: no cover
|
17
18
|
|
18
19
|
|
19
20
|
def _cvar_down_calc(
|
20
|
-
data:
|
21
|
+
data: DataFrame | Series[float] | list[float],
|
21
22
|
level: float = 0.95,
|
22
23
|
) -> float:
|
23
|
-
"""
|
24
|
-
Calculate downside Conditional Value at Risk (CVaR).
|
24
|
+
"""Calculate downside Conditional Value at Risk (CVaR).
|
25
25
|
|
26
26
|
https://www.investopedia.com/terms/c/conditional_value_at_risk.asp.
|
27
27
|
|
28
28
|
Parameters
|
29
29
|
----------
|
30
|
-
data:
|
30
|
+
data: DataFrame | Series[float] | list[float]
|
31
31
|
The data to perform the calculation over
|
32
32
|
level: float, default: 0.95
|
33
33
|
The sought CVaR level
|
@@ -48,19 +48,18 @@ def _cvar_down_calc(
|
|
48
48
|
|
49
49
|
|
50
50
|
def _var_down_calc(
|
51
|
-
data:
|
51
|
+
data: DataFrame | Series[float] | list[float],
|
52
52
|
level: float = 0.95,
|
53
53
|
interpolation: LiteralQuantileInterp = "lower",
|
54
54
|
) -> float:
|
55
|
-
"""
|
56
|
-
Calculate downside Value At Risk (VaR).
|
55
|
+
"""Calculate downside Value At Risk (VaR).
|
57
56
|
|
58
57
|
The equivalent of percentile.inc([...], 1-level) over returns in MS Excel
|
59
58
|
https://www.investopedia.com/terms/v/var.asp.
|
60
59
|
|
61
60
|
Parameters
|
62
61
|
----------
|
63
|
-
data:
|
62
|
+
data: DataFrame | Series[float] | list[float]
|
64
63
|
The data to perform the calculation over
|
65
64
|
level: float, default: 0.95
|
66
65
|
The sought VaR level
|
openseries/datefixer.py
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
from __future__ import annotations
|
4
4
|
|
5
5
|
import datetime as dt
|
6
|
-
from typing import
|
6
|
+
from typing import TYPE_CHECKING, cast
|
7
7
|
|
8
8
|
from dateutil.relativedelta import relativedelta
|
9
9
|
from holidays import (
|
@@ -21,24 +21,33 @@ from pandas import (
|
|
21
21
|
date_range,
|
22
22
|
)
|
23
23
|
from pandas.tseries.offsets import CustomBusinessDay
|
24
|
-
from pydantic import PositiveInt
|
25
24
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
25
|
+
if TYPE_CHECKING: # pragma: no cover
|
26
|
+
from .types import (
|
27
|
+
CountriesType,
|
28
|
+
DateType,
|
29
|
+
HolidayType,
|
30
|
+
LiteralBizDayFreq,
|
31
|
+
)
|
32
|
+
|
33
|
+
__all__ = [
|
34
|
+
"date_fix",
|
35
|
+
"date_offset_foll",
|
36
|
+
"do_resample_to_business_period_ends",
|
37
|
+
"generate_calendar_date_range",
|
38
|
+
"get_previous_business_day_before_today",
|
39
|
+
"holiday_calendar",
|
40
|
+
"offset_business_days",
|
41
|
+
]
|
32
42
|
|
33
43
|
|
34
44
|
def holiday_calendar(
|
35
45
|
startyear: int,
|
36
46
|
endyear: int,
|
37
47
|
countries: CountriesType = "SE",
|
38
|
-
custom_holidays:
|
48
|
+
custom_holidays: HolidayType | None = None,
|
39
49
|
) -> busdaycalendar:
|
40
|
-
"""
|
41
|
-
Generate a business calendar.
|
50
|
+
"""Generate a business calendar.
|
42
51
|
|
43
52
|
Parameters
|
44
53
|
----------
|
@@ -73,7 +82,7 @@ def holiday_calendar(
|
|
73
82
|
country in list_supported_countries() for country in countries
|
74
83
|
):
|
75
84
|
country: str
|
76
|
-
countryholidays: list[
|
85
|
+
countryholidays: list[dt.date | str] = []
|
77
86
|
for i, country in enumerate(countries):
|
78
87
|
staging = country_holidays(country=country, years=years)
|
79
88
|
if i == 0 and custom_holidays is not None:
|
@@ -95,8 +104,7 @@ def holiday_calendar(
|
|
95
104
|
def date_fix(
|
96
105
|
fixerdate: DateType,
|
97
106
|
) -> dt.date:
|
98
|
-
"""
|
99
|
-
Parse different date formats into datetime.date.
|
107
|
+
"""Parse different date formats into datetime.date.
|
100
108
|
|
101
109
|
Parameters
|
102
110
|
----------
|
@@ -115,9 +123,7 @@ def date_fix(
|
|
115
123
|
return fixerdate
|
116
124
|
if isinstance(fixerdate, datetime64):
|
117
125
|
return (
|
118
|
-
dt.datetime.strptime(str(fixerdate)[:10], "%Y-%m-%d")
|
119
|
-
.astimezone()
|
120
|
-
.date()
|
126
|
+
dt.datetime.strptime(str(fixerdate)[:10], "%Y-%m-%d").astimezone().date()
|
121
127
|
)
|
122
128
|
if isinstance(fixerdate, str):
|
123
129
|
return dt.datetime.strptime(fixerdate, "%Y-%m-%d").astimezone().date()
|
@@ -131,13 +137,12 @@ def date_offset_foll(
|
|
131
137
|
raw_date: DateType,
|
132
138
|
months_offset: int = 12,
|
133
139
|
countries: CountriesType = "SE",
|
134
|
-
custom_holidays:
|
140
|
+
custom_holidays: HolidayType | None = None,
|
135
141
|
*,
|
136
142
|
adjust: bool = False,
|
137
143
|
following: bool = True,
|
138
144
|
) -> dt.date:
|
139
|
-
"""
|
140
|
-
Offset dates according to a given calendar.
|
145
|
+
"""Offset dates according to a given calendar.
|
141
146
|
|
142
147
|
Parameters
|
143
148
|
----------
|
@@ -184,12 +189,11 @@ def date_offset_foll(
|
|
184
189
|
|
185
190
|
|
186
191
|
def get_previous_business_day_before_today(
|
187
|
-
today:
|
192
|
+
today: dt.date | None = None,
|
188
193
|
countries: CountriesType = "SE",
|
189
|
-
custom_holidays:
|
194
|
+
custom_holidays: HolidayType | None = None,
|
190
195
|
) -> dt.date:
|
191
|
-
"""
|
192
|
-
Bump date backwards to find the previous business day.
|
196
|
+
"""Bump date backwards to find the previous business day.
|
193
197
|
|
194
198
|
Parameters
|
195
199
|
----------
|
@@ -224,10 +228,9 @@ def offset_business_days(
|
|
224
228
|
ddate: dt.date,
|
225
229
|
days: int,
|
226
230
|
countries: CountriesType = "SE",
|
227
|
-
custom_holidays:
|
231
|
+
custom_holidays: HolidayType | None = None,
|
228
232
|
) -> dt.date:
|
229
|
-
"""
|
230
|
-
Bump date by business days.
|
233
|
+
"""Bump date by business days.
|
231
234
|
|
232
235
|
It first adjusts to a valid business day and then bumps with given
|
233
236
|
number of business days from there.
|
@@ -303,18 +306,17 @@ def offset_business_days(
|
|
303
306
|
|
304
307
|
|
305
308
|
def generate_calendar_date_range(
|
306
|
-
trading_days:
|
307
|
-
start:
|
308
|
-
end:
|
309
|
+
trading_days: int,
|
310
|
+
start: dt.date | None = None,
|
311
|
+
end: dt.date | None = None,
|
309
312
|
countries: CountriesType = "SE",
|
310
313
|
) -> list[dt.date]:
|
311
|
-
"""
|
312
|
-
Generate a list of business day calendar dates.
|
314
|
+
"""Generate a list of business day calendar dates.
|
313
315
|
|
314
316
|
Parameters
|
315
317
|
----------
|
316
|
-
trading_days:
|
317
|
-
Number of days to generate
|
318
|
+
trading_days: int
|
319
|
+
Number of days to generate. Must be greater than zero
|
318
320
|
start: datetime.date, optional
|
319
321
|
Date when the range starts
|
320
322
|
end: datetime.date, optional
|
@@ -328,6 +330,10 @@ def generate_calendar_date_range(
|
|
328
330
|
List of business day calendar dates
|
329
331
|
|
330
332
|
"""
|
333
|
+
if trading_days < 1:
|
334
|
+
msg = "Argument trading_days must be greater than zero."
|
335
|
+
raise ValueError(msg)
|
336
|
+
|
331
337
|
if start and not end:
|
332
338
|
tmp_range = date_range(
|
333
339
|
start=start,
|
@@ -380,8 +386,7 @@ def do_resample_to_business_period_ends(
|
|
380
386
|
freq: LiteralBizDayFreq,
|
381
387
|
countries: CountriesType,
|
382
388
|
) -> DatetimeIndex:
|
383
|
-
"""
|
384
|
-
Resample timeseries frequency to business calendar month end dates.
|
389
|
+
"""Resample timeseries frequency to business calendar month end dates.
|
385
390
|
|
386
391
|
Stubs left in place. Stubs will be aligned to the shortest stub.
|
387
392
|
|