openseries 1.2.2__py3-none-any.whl → 1.2.4__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 +1 -0
- openseries/common_model.py +265 -171
- openseries/datefixer.py +94 -111
- openseries/frame.py +252 -160
- openseries/load_plotly.py +11 -21
- openseries/risk.py +45 -23
- openseries/series.py +135 -110
- openseries/simulation.py +157 -109
- openseries/types.py +88 -21
- {openseries-1.2.2.dist-info → openseries-1.2.4.dist-info}/METADATA +11 -12
- openseries-1.2.4.dist-info/RECORD +15 -0
- {openseries-1.2.2.dist-info → openseries-1.2.4.dist-info}/WHEEL +1 -1
- openseries-1.2.2.dist-info/RECORD +0 -15
- {openseries-1.2.2.dist-info → openseries-1.2.4.dist-info}/LICENSE.md +0 -0
openseries/datefixer.py
CHANGED
@@ -1,20 +1,22 @@
|
|
1
|
-
"""
|
2
|
-
Date related utilities
|
3
|
-
"""
|
1
|
+
"""Date related utilities."""
|
4
2
|
from __future__ import annotations
|
3
|
+
|
5
4
|
import datetime as dt
|
6
|
-
from typing import Optional, Union
|
5
|
+
from typing import Optional, Union, cast
|
6
|
+
|
7
7
|
from dateutil.relativedelta import relativedelta
|
8
8
|
from holidays import country_holidays, list_supported_countries
|
9
|
-
from numpy import array, busdaycalendar, datetime64, is_busday, where
|
10
|
-
from pandas import DataFrame,
|
9
|
+
from numpy import array, busdaycalendar, datetime64, is_busday, where
|
10
|
+
from pandas import DataFrame, DatetimeIndex, Series, Timestamp, concat, date_range
|
11
11
|
from pandas.tseries.offsets import CustomBusinessDay
|
12
12
|
|
13
13
|
from openseries.types import (
|
14
14
|
CountriesType,
|
15
|
-
|
15
|
+
DateType,
|
16
|
+
HolidayType,
|
16
17
|
LiteralBizDayFreq,
|
17
18
|
LiteralPandasResampleConvention,
|
19
|
+
TradingDaysType,
|
18
20
|
)
|
19
21
|
|
20
22
|
|
@@ -22,15 +24,10 @@ def holiday_calendar(
|
|
22
24
|
startyear: int,
|
23
25
|
endyear: int,
|
24
26
|
countries: CountriesType = "SE",
|
25
|
-
custom_holidays: Optional[
|
26
|
-
Union[
|
27
|
-
dict[Union[dt.date, dt.datetime, str, float, int], str],
|
28
|
-
list[Union[dt.date, dt.datetime, str, float, int]],
|
29
|
-
Union[dt.date, dt.datetime, str, float, int],
|
30
|
-
]
|
31
|
-
] = None,
|
27
|
+
custom_holidays: Optional[HolidayType] = None,
|
32
28
|
) -> busdaycalendar:
|
33
|
-
"""
|
29
|
+
"""
|
30
|
+
Generate a business calendar.
|
34
31
|
|
35
32
|
Parameters
|
36
33
|
----------
|
@@ -38,19 +35,16 @@ def holiday_calendar(
|
|
38
35
|
First year in date range generated
|
39
36
|
endyear: int
|
40
37
|
Last year in date range generated
|
41
|
-
countries:
|
38
|
+
countries: CountriesType, default: "SE"
|
42
39
|
(List of) country code(s) according to ISO 3166-1 alpha-2
|
43
|
-
custom_holidays:
|
44
|
-
dict[Union[dt.date, dt.datetime, str, float, int], str],
|
45
|
-
list[Union[dt.date, dt.datetime, str, float, int]],
|
46
|
-
Union[dt.date, dt.datetime, str, float, int]], optional
|
40
|
+
custom_holidays: HolidayType, optional
|
47
41
|
Argument where missing holidays can be added as
|
48
42
|
{"2021-02-12": "Jack's birthday"} or ["2021-02-12"]
|
49
43
|
|
50
44
|
Returns
|
51
45
|
-------
|
52
46
|
numpy.busdaycalendar
|
53
|
-
|
47
|
+
Generate a business calendar
|
54
48
|
"""
|
55
49
|
startyear -= 1
|
56
50
|
endyear += 1
|
@@ -73,25 +67,25 @@ def holiday_calendar(
|
|
73
67
|
if i == 0 and custom_holidays is not None:
|
74
68
|
staging.update(custom_holidays)
|
75
69
|
countryholidays += list(staging)
|
76
|
-
hols = array(sorted(
|
70
|
+
hols = array(sorted(set(countryholidays)), dtype="datetime64[D]")
|
77
71
|
else:
|
78
72
|
raise ValueError(
|
79
73
|
"Argument countries must be a string country code or a list "
|
80
|
-
"of string country codes according to ISO 3166-1 alpha-2."
|
74
|
+
"of string country codes according to ISO 3166-1 alpha-2.",
|
81
75
|
)
|
82
76
|
|
83
77
|
return busdaycalendar(holidays=hols)
|
84
78
|
|
85
79
|
|
86
80
|
def date_fix(
|
87
|
-
fixerdate:
|
81
|
+
fixerdate: DateType,
|
88
82
|
) -> dt.date:
|
89
|
-
"""
|
83
|
+
"""
|
84
|
+
Parse different date formats into datetime.date.
|
90
85
|
|
91
86
|
Parameters
|
92
87
|
----------
|
93
|
-
fixerdate:
|
94
|
-
numpy.datetime64 | pandas.Timestamp
|
88
|
+
fixerdate: DateType
|
95
89
|
The data item to parse
|
96
90
|
|
97
91
|
Returns
|
@@ -99,44 +93,42 @@ def date_fix(
|
|
99
93
|
datetime.date
|
100
94
|
Parsed date
|
101
95
|
"""
|
102
|
-
|
103
96
|
if isinstance(fixerdate, (Timestamp, dt.datetime)):
|
104
97
|
return fixerdate.date()
|
105
98
|
if isinstance(fixerdate, dt.date):
|
106
99
|
return fixerdate
|
107
100
|
if isinstance(fixerdate, datetime64):
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
101
|
+
return (
|
102
|
+
dt.datetime.strptime(str(fixerdate)[:10], "%Y-%m-%d")
|
103
|
+
.replace(tzinfo=dt.timezone.utc)
|
104
|
+
.date()
|
105
|
+
)
|
112
106
|
if isinstance(fixerdate, str):
|
113
|
-
return
|
107
|
+
return (
|
108
|
+
dt.datetime.strptime(fixerdate, "%Y-%m-%d")
|
109
|
+
.replace(tzinfo=dt.timezone.utc)
|
110
|
+
.date()
|
111
|
+
)
|
114
112
|
raise TypeError(
|
115
|
-
f"Unknown date format {
|
116
|
-
f"type {
|
113
|
+
f"Unknown date format {fixerdate!s} of "
|
114
|
+
f"type {type(fixerdate)!s} encountered",
|
117
115
|
)
|
118
116
|
|
119
117
|
|
120
118
|
def date_offset_foll(
|
121
|
-
raw_date:
|
119
|
+
raw_date: DateType,
|
122
120
|
months_offset: int = 12,
|
123
121
|
adjust: bool = False,
|
124
122
|
following: bool = True,
|
125
123
|
countries: CountriesType = "SE",
|
126
|
-
custom_holidays: Optional[
|
127
|
-
Union[
|
128
|
-
dict[Union[dt.date, dt.datetime, str, float, int], str],
|
129
|
-
list[Union[dt.date, dt.datetime, str, float, int]],
|
130
|
-
Union[dt.date, dt.datetime, str, float, int],
|
131
|
-
]
|
132
|
-
] = None,
|
124
|
+
custom_holidays: Optional[HolidayType] = None,
|
133
125
|
) -> dt.date:
|
134
|
-
"""
|
126
|
+
"""
|
127
|
+
Offset dates according to a given calendar.
|
135
128
|
|
136
129
|
Parameters
|
137
130
|
----------
|
138
|
-
raw_date:
|
139
|
-
pandas.Timestamp
|
131
|
+
raw_date: DateType
|
140
132
|
The date to offset from
|
141
133
|
months_offset: int, default: 12
|
142
134
|
Number of months as integer
|
@@ -144,12 +136,9 @@ def date_offset_foll(
|
|
144
136
|
Determines if offset should adjust for business days
|
145
137
|
following: bool, default: True
|
146
138
|
Determines if days should be offset forward (following) or backward
|
147
|
-
countries:
|
139
|
+
countries: CountriesType, default: "SE"
|
148
140
|
(List of) country code(s) according to ISO 3166-1 alpha-2
|
149
|
-
custom_holidays:
|
150
|
-
dict[Union[dt.date, dt.datetime, str, float, int], str],
|
151
|
-
list[Union[dt.date, dt.datetime, str, float, int]],
|
152
|
-
Union[dt.date, dt.datetime, str, float, int]], optional
|
141
|
+
custom_holidays: HolidayType, optional
|
153
142
|
Argument where missing holidays can be added as
|
154
143
|
{"2021-02-12": "Jack's birthday"} or ["2021-02-12"]
|
155
144
|
|
@@ -158,7 +147,6 @@ def date_offset_foll(
|
|
158
147
|
datetime.date
|
159
148
|
Off-set date
|
160
149
|
"""
|
161
|
-
|
162
150
|
raw_date = date_fix(raw_date)
|
163
151
|
month_delta = relativedelta(months=months_offset)
|
164
152
|
|
@@ -187,26 +175,18 @@ def date_offset_foll(
|
|
187
175
|
def get_previous_business_day_before_today(
|
188
176
|
today: Optional[dt.date] = None,
|
189
177
|
countries: CountriesType = "SE",
|
190
|
-
custom_holidays: Optional[
|
191
|
-
Union[
|
192
|
-
dict[Union[dt.date, dt.datetime, str, float, int], str],
|
193
|
-
list[Union[dt.date, dt.datetime, str, float, int]],
|
194
|
-
Union[dt.date, dt.datetime, str, float, int],
|
195
|
-
]
|
196
|
-
] = None,
|
178
|
+
custom_holidays: Optional[HolidayType] = None,
|
197
179
|
) -> dt.date:
|
198
|
-
"""
|
180
|
+
"""
|
181
|
+
Bump date backwards to find the previous business day.
|
199
182
|
|
200
183
|
Parameters
|
201
184
|
----------
|
202
185
|
today: datetime.date, optional
|
203
186
|
Manual input of the day from where the previous business day is found
|
204
|
-
countries:
|
187
|
+
countries: CountriesType, default: "SE"
|
205
188
|
(List of) country code(s) according to ISO 3166-1 alpha-2
|
206
|
-
custom_holidays:
|
207
|
-
dict[Union[dt.date, dt.datetime, str, float, int], str],
|
208
|
-
list[Union[dt.date, dt.datetime, str, float, int]],
|
209
|
-
Union[dt.date, dt.datetime, str, float, int]], optional
|
189
|
+
custom_holidays: HolidayType, optional
|
210
190
|
Argument where missing holidays can be added as
|
211
191
|
{"2021-02-12": "Jack's birthday"} or ["2021-02-12"]
|
212
192
|
|
@@ -215,9 +195,8 @@ def get_previous_business_day_before_today(
|
|
215
195
|
datetime.date
|
216
196
|
The previous business day
|
217
197
|
"""
|
218
|
-
|
219
198
|
if today is None:
|
220
|
-
today = dt.
|
199
|
+
today = dt.datetime.now(tz=dt.timezone.utc).date()
|
221
200
|
|
222
201
|
return date_offset_foll(
|
223
202
|
today - dt.timedelta(days=1),
|
@@ -233,17 +212,13 @@ def offset_business_days(
|
|
233
212
|
ddate: dt.date,
|
234
213
|
days: int,
|
235
214
|
countries: CountriesType = "SE",
|
236
|
-
custom_holidays: Optional[
|
237
|
-
Union[
|
238
|
-
dict[Union[dt.date, dt.datetime, str, float, int], str],
|
239
|
-
list[Union[dt.date, dt.datetime, str, float, int]],
|
240
|
-
Union[dt.date, dt.datetime, str, float, int],
|
241
|
-
]
|
242
|
-
] = None,
|
215
|
+
custom_holidays: Optional[HolidayType] = None,
|
243
216
|
) -> dt.date:
|
244
|
-
"""
|
217
|
+
"""
|
218
|
+
Bump date by business days.
|
219
|
+
|
245
220
|
It first adjusts to a valid business day and then bumps with given
|
246
|
-
number of business days from there
|
221
|
+
number of business days from there.
|
247
222
|
|
248
223
|
Parameters
|
249
224
|
----------
|
@@ -252,12 +227,9 @@ def offset_business_days(
|
|
252
227
|
days: int
|
253
228
|
The number of business days to offset from the business day that is
|
254
229
|
the closest preceding the day given
|
255
|
-
countries:
|
230
|
+
countries: CountriesType, default: "SE"
|
256
231
|
(List of) country code(s) according to ISO 3166-1 alpha-2
|
257
|
-
custom_holidays:
|
258
|
-
dict[Union[dt.date, dt.datetime, str, float, int], str],
|
259
|
-
list[Union[dt.date, dt.datetime, str, float, int]],
|
260
|
-
Union[dt.date, dt.datetime, str, float, int]], optional
|
232
|
+
custom_holidays: HolidayType, optional
|
261
233
|
Argument where missing holidays can be added as
|
262
234
|
{"2021-02-12": "Jack's birthday"} or ["2021-02-12"]
|
263
235
|
|
@@ -309,7 +281,7 @@ def offset_business_days(
|
|
309
281
|
|
310
282
|
idx = where(array(local_bdays) == ddate)[0]
|
311
283
|
|
312
|
-
return
|
284
|
+
return cast(dt.date, local_bdays[idx[0] + days])
|
313
285
|
|
314
286
|
|
315
287
|
def generate_calender_date_range(
|
@@ -318,18 +290,19 @@ def generate_calender_date_range(
|
|
318
290
|
end: Optional[dt.date] = None,
|
319
291
|
countries: CountriesType = "SE",
|
320
292
|
) -> list[dt.date]:
|
321
|
-
"""
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
293
|
+
"""
|
294
|
+
Generate a list of business day calender dates.
|
295
|
+
|
296
|
+
Parameters
|
297
|
+
----------
|
298
|
+
trading_days: TradingDaysType
|
299
|
+
Number of days to generate
|
300
|
+
start: datetime.date, optional
|
301
|
+
Date when the range starts
|
302
|
+
end: datetime.date, optional
|
303
|
+
Date when the range ends
|
304
|
+
countries: CountriesType, default: "SE"
|
305
|
+
(List of) country code(s) according to ISO 3166-1 alpha-2
|
333
306
|
|
334
307
|
Returns
|
335
308
|
-------
|
@@ -338,10 +311,14 @@ def generate_calender_date_range(
|
|
338
311
|
"""
|
339
312
|
if start and not end:
|
340
313
|
tmp_range = date_range(
|
341
|
-
start=start,
|
314
|
+
start=start,
|
315
|
+
periods=trading_days * 365 // 252,
|
316
|
+
freq="D",
|
342
317
|
)
|
343
318
|
calendar = holiday_calendar(
|
344
|
-
startyear=start.year,
|
319
|
+
startyear=start.year,
|
320
|
+
endyear=tmp_range[-1].year,
|
321
|
+
countries=countries,
|
345
322
|
)
|
346
323
|
return [
|
347
324
|
d.date()
|
@@ -355,7 +332,9 @@ def generate_calender_date_range(
|
|
355
332
|
if end and not start:
|
356
333
|
tmp_range = date_range(end=end, periods=trading_days * 365 // 252, freq="D")
|
357
334
|
calendar = holiday_calendar(
|
358
|
-
startyear=tmp_range[0].year,
|
335
|
+
startyear=tmp_range[0].year,
|
336
|
+
endyear=end.year,
|
337
|
+
countries=countries,
|
359
338
|
)
|
360
339
|
return [
|
361
340
|
d.date()
|
@@ -368,21 +347,22 @@ def generate_calender_date_range(
|
|
368
347
|
|
369
348
|
raise ValueError(
|
370
349
|
"Provide one of start or end date, but not both. "
|
371
|
-
"Date range is inferred from number of trading days."
|
350
|
+
"Date range is inferred from number of trading days.",
|
372
351
|
)
|
373
352
|
|
374
353
|
|
375
354
|
def align_dataframe_to_local_cdays(
|
376
|
-
data: DataFrame,
|
355
|
+
data: DataFrame,
|
356
|
+
countries: CountriesType = "SE",
|
377
357
|
) -> DataFrame:
|
378
|
-
"""
|
379
|
-
local calendar business days
|
358
|
+
"""
|
359
|
+
Align the index .tsdf with local calendar business days.
|
380
360
|
|
381
361
|
Parameters
|
382
362
|
----------
|
383
363
|
data: pandas.DataFrame
|
384
364
|
The timeseries data
|
385
|
-
countries:
|
365
|
+
countries: CountriesType, default: "SE"
|
386
366
|
(List of) country code(s) according to ISO 3166-1 alpha-2
|
387
367
|
|
388
368
|
Returns
|
@@ -393,7 +373,9 @@ def align_dataframe_to_local_cdays(
|
|
393
373
|
startyear = data.index[0].year
|
394
374
|
endyear = data.index[-1].year
|
395
375
|
calendar = holiday_calendar(
|
396
|
-
startyear=startyear,
|
376
|
+
startyear=startyear,
|
377
|
+
endyear=endyear,
|
378
|
+
countries=countries,
|
397
379
|
)
|
398
380
|
|
399
381
|
d_range = [
|
@@ -415,9 +397,10 @@ def do_resample_to_business_period_ends(
|
|
415
397
|
countries: CountriesType,
|
416
398
|
convention: LiteralPandasResampleConvention,
|
417
399
|
) -> DatetimeIndex:
|
418
|
-
"""
|
419
|
-
|
420
|
-
|
400
|
+
"""
|
401
|
+
Resample timeseries frequency to business calendar month end dates.
|
402
|
+
|
403
|
+
Stubs left in place. Stubs will be aligned to the shortest stub.
|
421
404
|
|
422
405
|
Parameters
|
423
406
|
----------
|
@@ -440,12 +423,11 @@ def do_resample_to_business_period_ends(
|
|
440
423
|
Pandas.DatetimeIndex
|
441
424
|
A date range aligned to business period ends
|
442
425
|
"""
|
443
|
-
|
444
426
|
head = head.to_frame().T
|
445
427
|
tail = tail.to_frame().T
|
446
428
|
data.index = DatetimeIndex(data.index)
|
447
429
|
data = data.resample(rule=freq, convention=convention).last()
|
448
|
-
data.drop(index=data.index[-1]
|
430
|
+
data = data.drop(index=data.index[-1])
|
449
431
|
data.index = [d.date() for d in DatetimeIndex(data.index)]
|
450
432
|
|
451
433
|
if head.index[0] not in data.index:
|
@@ -454,7 +436,7 @@ def do_resample_to_business_period_ends(
|
|
454
436
|
if tail.index[0] not in data.index:
|
455
437
|
data = concat([data, tail])
|
456
438
|
|
457
|
-
data.sort_index(
|
439
|
+
data = data.sort_index()
|
458
440
|
|
459
441
|
dates = DatetimeIndex(
|
460
442
|
[data.index[0]]
|
@@ -470,7 +452,7 @@ def do_resample_to_business_period_ends(
|
|
470
452
|
)
|
471
453
|
for d in data.index[1:-1]
|
472
454
|
]
|
473
|
-
+ [data.index[-1]]
|
455
|
+
+ [data.index[-1]],
|
474
456
|
)
|
475
457
|
dates = dates.drop_duplicates()
|
476
458
|
return dates
|
@@ -482,7 +464,8 @@ def get_calc_range(
|
|
482
464
|
from_dt: Optional[dt.date] = None,
|
483
465
|
to_dt: Optional[dt.date] = None,
|
484
466
|
) -> tuple[dt.date, dt.date]:
|
485
|
-
"""
|
467
|
+
"""
|
468
|
+
Create user defined date range.
|
486
469
|
|
487
470
|
Parameters
|
488
471
|
----------
|