openseries 1.9.6__py3-none-any.whl → 2.0.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 +1 -8
- openseries/_common_model.py +375 -224
- openseries/_risk.py +3 -10
- openseries/datefixer.py +9 -16
- openseries/frame.py +100 -117
- openseries/load_plotly.py +3 -10
- openseries/owntypes.py +3 -10
- openseries/portfoliotools.py +19 -41
- openseries/py.typed +0 -0
- openseries/report.py +6 -12
- openseries/series.py +36 -54
- openseries/simulation.py +104 -39
- openseries-2.0.0.dist-info/METADATA +126 -0
- openseries-2.0.0.dist-info/RECORD +18 -0
- {openseries-1.9.6.dist-info → openseries-2.0.0.dist-info}/WHEEL +1 -1
- openseries-1.9.6.dist-info/METADATA +0 -369
- openseries-1.9.6.dist-info/RECORD +0 -17
- {openseries-1.9.6.dist-info → openseries-2.0.0.dist-info}/licenses/LICENSE.md +0 -0
openseries/_risk.py
CHANGED
@@ -1,11 +1,4 @@
|
|
1
|
-
"""
|
2
|
-
|
3
|
-
Copyright (c) Captor Fund Management AB. This file is part of the openseries project.
|
4
|
-
|
5
|
-
Licensed under the BSD 3-Clause License. You may obtain a copy of the License at:
|
6
|
-
https://github.com/CaptorAB/openseries/blob/master/LICENSE.md
|
7
|
-
SPDX-License-Identifier: BSD-3-Clause
|
8
|
-
"""
|
1
|
+
"""Functions caclculating risk measures."""
|
9
2
|
|
10
3
|
from __future__ import annotations
|
11
4
|
|
@@ -40,7 +33,7 @@ def _cvar_down_calc(
|
|
40
33
|
The sought CVaR level
|
41
34
|
|
42
35
|
Returns:
|
43
|
-
|
36
|
+
--------
|
44
37
|
float
|
45
38
|
Downside Conditional Value At Risk "CVaR"
|
46
39
|
|
@@ -74,7 +67,7 @@ def _var_down_calc(
|
|
74
67
|
type of interpolation in Pandas.DataFrame.quantile() function.
|
75
68
|
|
76
69
|
Returns:
|
77
|
-
|
70
|
+
--------
|
78
71
|
float
|
79
72
|
Downside Value At Risk
|
80
73
|
|
openseries/datefixer.py
CHANGED
@@ -1,11 +1,4 @@
|
|
1
|
-
"""Date related utilities.
|
2
|
-
|
3
|
-
Copyright (c) Captor Fund Management AB. This file is part of the openseries project.
|
4
|
-
|
5
|
-
Licensed under the BSD 3-Clause License. You may obtain a copy of the License at:
|
6
|
-
https://github.com/CaptorAB/openseries/blob/master/LICENSE.md
|
7
|
-
SPDX-License-Identifier: BSD-3-Clause
|
8
|
-
"""
|
1
|
+
"""Date related utilities."""
|
9
2
|
|
10
3
|
from __future__ import annotations
|
11
4
|
|
@@ -70,7 +63,7 @@ def market_holidays(
|
|
70
63
|
String or list of market codes supported by pandas_market_calendars.
|
71
64
|
|
72
65
|
Returns:
|
73
|
-
|
66
|
+
--------
|
74
67
|
list[str]
|
75
68
|
list of holiday dates.
|
76
69
|
"""
|
@@ -122,7 +115,7 @@ def holiday_calendar(
|
|
122
115
|
Argument where missing holidays can be added
|
123
116
|
|
124
117
|
Returns:
|
125
|
-
|
118
|
+
--------
|
126
119
|
numpy.busdaycalendar
|
127
120
|
Generate a business calendar
|
128
121
|
|
@@ -183,7 +176,7 @@ def date_fix(
|
|
183
176
|
The data item to parse
|
184
177
|
|
185
178
|
Returns:
|
186
|
-
|
179
|
+
--------
|
187
180
|
datetime.date
|
188
181
|
Parsed date
|
189
182
|
|
@@ -232,7 +225,7 @@ def date_offset_foll(
|
|
232
225
|
Determines if days should be offset forward (following) or backward
|
233
226
|
|
234
227
|
Returns:
|
235
|
-
|
228
|
+
--------
|
236
229
|
datetime.date
|
237
230
|
Off-set date
|
238
231
|
|
@@ -280,7 +273,7 @@ def get_previous_business_day_before_today(
|
|
280
273
|
Argument where missing holidays can be added
|
281
274
|
|
282
275
|
Returns:
|
283
|
-
|
276
|
+
--------
|
284
277
|
datetime.date
|
285
278
|
The previous business day
|
286
279
|
|
@@ -326,7 +319,7 @@ def offset_business_days(
|
|
326
319
|
Argument where missing holidays can be added
|
327
320
|
|
328
321
|
Returns:
|
329
|
-
|
322
|
+
--------
|
330
323
|
datetime.date
|
331
324
|
The new offset business day
|
332
325
|
|
@@ -410,7 +403,7 @@ def generate_calendar_date_range(
|
|
410
403
|
Argument where missing holidays can be added
|
411
404
|
|
412
405
|
Returns:
|
413
|
-
|
406
|
+
--------
|
414
407
|
list[dt.date]
|
415
408
|
List of business day calendar dates
|
416
409
|
|
@@ -491,7 +484,7 @@ def _do_resample_to_business_period_ends(
|
|
491
484
|
Argument where missing holidays can be added
|
492
485
|
|
493
486
|
Returns:
|
494
|
-
|
487
|
+
--------
|
495
488
|
Pandas.DatetimeIndex
|
496
489
|
A date range aligned to business period ends
|
497
490
|
|
openseries/frame.py
CHANGED
@@ -1,11 +1,4 @@
|
|
1
|
-
"""
|
2
|
-
|
3
|
-
Copyright (c) Captor Fund Management AB. This file is part of the openseries project.
|
4
|
-
|
5
|
-
Licensed under the BSD 3-Clause License. You may obtain a copy of the License at:
|
6
|
-
https://github.com/CaptorAB/openseries/blob/master/LICENSE.md
|
7
|
-
SPDX-License-Identifier: BSD-3-Clause
|
8
|
-
"""
|
1
|
+
"""The OpenFrame class."""
|
9
2
|
|
10
3
|
from __future__ import annotations
|
11
4
|
|
@@ -16,11 +9,16 @@ from typing import TYPE_CHECKING, Any, cast
|
|
16
9
|
|
17
10
|
from numpy import (
|
18
11
|
array,
|
12
|
+
asarray,
|
19
13
|
concatenate,
|
14
|
+
corrcoef,
|
20
15
|
cov,
|
21
16
|
diff,
|
22
17
|
divide,
|
18
|
+
float64,
|
23
19
|
isinf,
|
20
|
+
isnan,
|
21
|
+
linalg,
|
24
22
|
log,
|
25
23
|
nan,
|
26
24
|
sqrt,
|
@@ -39,6 +37,7 @@ from pandas import (
|
|
39
37
|
if TYPE_CHECKING: # pragma: no cover
|
40
38
|
import datetime as dt
|
41
39
|
|
40
|
+
from numpy.typing import NDArray
|
42
41
|
from pandas import Series as _Series
|
43
42
|
from pandas import Timestamp
|
44
43
|
|
@@ -49,7 +48,7 @@ else:
|
|
49
48
|
from pydantic import field_validator
|
50
49
|
from sklearn.linear_model import LinearRegression # type: ignore[import-untyped]
|
51
50
|
|
52
|
-
from ._common_model import _CommonModel
|
51
|
+
from ._common_model import _calculate_time_factor, _CommonModel, _get_base_column_data
|
53
52
|
from .datefixer import _do_resample_to_business_period_ends
|
54
53
|
from .owntypes import (
|
55
54
|
DaysInYearType,
|
@@ -77,7 +76,6 @@ logger = getLogger(__name__)
|
|
77
76
|
__all__ = ["OpenFrame"]
|
78
77
|
|
79
78
|
|
80
|
-
# noinspection PyUnresolvedReferences,PyTypeChecker
|
81
79
|
class OpenFrame(_CommonModel[SeriesFloat]):
|
82
80
|
"""OpenFrame objects hold OpenTimeSeries in the list constituents.
|
83
81
|
|
@@ -91,7 +89,7 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
91
89
|
List of weights in float format.
|
92
90
|
|
93
91
|
Returns:
|
94
|
-
|
92
|
+
--------
|
95
93
|
OpenFrame
|
96
94
|
Object of the class OpenFrame
|
97
95
|
|
@@ -101,7 +99,6 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
101
99
|
tsdf: DataFrame = DataFrame(dtype="float64")
|
102
100
|
weights: list[float] | None = None
|
103
101
|
|
104
|
-
# noinspection PyMethodParameters
|
105
102
|
@field_validator("constituents")
|
106
103
|
def _check_labels_unique(
|
107
104
|
cls: type[OpenFrame], # noqa: N805
|
@@ -131,7 +128,7 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
131
128
|
List of weights in float format.
|
132
129
|
|
133
130
|
Returns:
|
134
|
-
|
131
|
+
--------
|
135
132
|
OpenFrame
|
136
133
|
Object of the class OpenFrame
|
137
134
|
|
@@ -150,10 +147,12 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
150
147
|
def _set_tsdf(self: Self) -> None:
|
151
148
|
"""Set the tsdf DataFrame."""
|
152
149
|
if self.constituents is not None and len(self.constituents) != 0:
|
153
|
-
self.
|
154
|
-
|
155
|
-
|
156
|
-
|
150
|
+
if len(self.constituents) == 1:
|
151
|
+
self.tsdf = self.constituents[0].tsdf.copy()
|
152
|
+
else:
|
153
|
+
self.tsdf = concat(
|
154
|
+
[x.tsdf for x in self.constituents], axis="columns", sort=True
|
155
|
+
)
|
157
156
|
else:
|
158
157
|
logger.warning("OpenFrame() was passed an empty list.")
|
159
158
|
|
@@ -161,7 +160,7 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
161
160
|
"""Create copy of the OpenFrame object.
|
162
161
|
|
163
162
|
Returns:
|
164
|
-
|
163
|
+
--------
|
165
164
|
OpenFrame
|
166
165
|
An OpenFrame object
|
167
166
|
|
@@ -180,7 +179,7 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
180
179
|
The Pandas merge method.
|
181
180
|
|
182
181
|
Returns:
|
183
|
-
|
182
|
+
--------
|
184
183
|
OpenFrame
|
185
184
|
An OpenFrame object
|
186
185
|
|
@@ -224,7 +223,7 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
224
223
|
The properties to calculate. Defaults to calculating all available.
|
225
224
|
|
226
225
|
Returns:
|
227
|
-
|
226
|
+
--------
|
228
227
|
pandas.DataFrame
|
229
228
|
Properties of the contituent OpenTimeSeries
|
230
229
|
|
@@ -243,7 +242,7 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
243
242
|
"""Number of observations of all constituents.
|
244
243
|
|
245
244
|
Returns:
|
246
|
-
|
245
|
+
--------
|
247
246
|
Pandas.Series[int]
|
248
247
|
Number of observations of all constituents
|
249
248
|
|
@@ -259,7 +258,7 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
259
258
|
"""Number of constituents.
|
260
259
|
|
261
260
|
Returns:
|
262
|
-
|
261
|
+
--------
|
263
262
|
int
|
264
263
|
Number of constituents
|
265
264
|
|
@@ -271,7 +270,7 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
271
270
|
"""Level 0 values of the MultiIndex columns in the .tsdf DataFrame.
|
272
271
|
|
273
272
|
Returns:
|
274
|
-
|
273
|
+
--------
|
275
274
|
list[str]
|
276
275
|
Level 0 values of the MultiIndex columns in the .tsdf DataFrame
|
277
276
|
|
@@ -283,7 +282,7 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
283
282
|
"""Level 1 values of the MultiIndex columns in the .tsdf DataFrame.
|
284
283
|
|
285
284
|
Returns:
|
286
|
-
|
285
|
+
--------
|
287
286
|
list[ValueType]
|
288
287
|
Level 1 values of the MultiIndex columns in the .tsdf DataFrame
|
289
288
|
|
@@ -295,7 +294,7 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
295
294
|
"""The first dates in the timeseries of all constituents.
|
296
295
|
|
297
296
|
Returns:
|
298
|
-
|
297
|
+
--------
|
299
298
|
Pandas.Series[dt.date]
|
300
299
|
The first dates in the timeseries of all constituents
|
301
300
|
|
@@ -312,7 +311,7 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
312
311
|
"""The last dates in the timeseries of all constituents.
|
313
312
|
|
314
313
|
Returns:
|
315
|
-
|
314
|
+
--------
|
316
315
|
Pandas.Series[dt.date]
|
317
316
|
The last dates in the timeseries of all constituents
|
318
317
|
|
@@ -329,7 +328,7 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
329
328
|
"""Number of days from the first date to the last for all items in the frame.
|
330
329
|
|
331
330
|
Returns:
|
332
|
-
|
331
|
+
--------
|
333
332
|
Pandas.Series[int]
|
334
333
|
Number of days from the first date to the last for all
|
335
334
|
items in the frame.
|
@@ -345,7 +344,7 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
345
344
|
"""Convert series of values into series of returns.
|
346
345
|
|
347
346
|
Returns:
|
348
|
-
|
347
|
+
--------
|
349
348
|
OpenFrame
|
350
349
|
The returns of the values in the series
|
351
350
|
|
@@ -371,7 +370,7 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
371
370
|
is calculated
|
372
371
|
|
373
372
|
Returns:
|
374
|
-
|
373
|
+
--------
|
375
374
|
OpenFrame
|
376
375
|
An OpenFrame object
|
377
376
|
|
@@ -390,7 +389,7 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
390
389
|
"""Convert series of returns into cumulative series of values.
|
391
390
|
|
392
391
|
Returns:
|
393
|
-
|
392
|
+
--------
|
394
393
|
OpenFrame
|
395
394
|
An OpenFrame object
|
396
395
|
|
@@ -429,7 +428,7 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
429
428
|
The date offset string that sets the resampled frequency
|
430
429
|
|
431
430
|
Returns:
|
432
|
-
|
431
|
+
--------
|
433
432
|
OpenFrame
|
434
433
|
An OpenFrame object
|
435
434
|
|
@@ -478,7 +477,7 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
478
477
|
Controls the method used to align values across columns
|
479
478
|
|
480
479
|
Returns:
|
481
|
-
|
480
|
+
--------
|
482
481
|
OpenFrame
|
483
482
|
An OpenFrame object
|
484
483
|
|
@@ -559,7 +558,7 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
559
558
|
comparisons
|
560
559
|
|
561
560
|
Returns:
|
562
|
-
|
561
|
+
--------
|
563
562
|
Pandas.DataFrame
|
564
563
|
Series volatilities and correlation
|
565
564
|
|
@@ -610,13 +609,12 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
610
609
|
.std(ddof=dlta_degr_freedms)
|
611
610
|
* sqrt(time_factor),
|
612
611
|
]
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
]
|
612
|
+
rm = data[(cols[0], ValueType.RTRN)].iloc[1:day_chunk]
|
613
|
+
m: NDArray[float64] = asarray(rm, dtype=float64)
|
614
|
+
ry = data[(cols[1], ValueType.RTRN)].iloc[1:day_chunk]
|
615
|
+
y: NDArray[float64] = asarray(ry, dtype=float64)
|
616
|
+
|
617
|
+
raw_cov = [cov(m=m, y=y, ddof=dlta_degr_freedms)[0][1]]
|
620
618
|
|
621
619
|
r1 = data[(cols[0], ValueType.RTRN)]
|
622
620
|
r2 = data[(cols[1], ValueType.RTRN)]
|
@@ -656,10 +654,13 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
656
654
|
def correl_matrix(self: Self) -> DataFrame:
|
657
655
|
"""Correlation matrix.
|
658
656
|
|
657
|
+
This property returns the correlation matrix of the time series
|
658
|
+
in the frame.
|
659
|
+
|
659
660
|
Returns:
|
660
|
-
|
661
|
-
|
662
|
-
Correlation matrix
|
661
|
+
--------
|
662
|
+
pandas.DataFrame
|
663
|
+
Correlation matrix of the time series in the frame.
|
663
664
|
|
664
665
|
"""
|
665
666
|
corr_matrix = (
|
@@ -687,7 +688,7 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
687
688
|
The timeseries to add
|
688
689
|
|
689
690
|
Returns:
|
690
|
-
|
691
|
+
--------
|
691
692
|
OpenFrame
|
692
693
|
An OpenFrame object
|
693
694
|
|
@@ -705,7 +706,7 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
705
706
|
The .tsdf column level 0 value of the timeseries to delete
|
706
707
|
|
707
708
|
Returns:
|
708
|
-
|
709
|
+
--------
|
709
710
|
OpenFrame
|
710
711
|
An OpenFrame object
|
711
712
|
|
@@ -744,7 +745,7 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
744
745
|
or end_cut is None.
|
745
746
|
|
746
747
|
Returns:
|
747
|
-
|
748
|
+
--------
|
748
749
|
OpenFrame
|
749
750
|
An OpenFrame object
|
750
751
|
|
@@ -845,7 +846,7 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
845
846
|
comparisons
|
846
847
|
|
847
848
|
Returns:
|
848
|
-
|
849
|
+
--------
|
849
850
|
Pandas.Series[float]
|
850
851
|
Tracking Errors
|
851
852
|
|
@@ -855,36 +856,20 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
855
856
|
from_dt=from_date,
|
856
857
|
to_dt=to_date,
|
857
858
|
)
|
858
|
-
fraction: float = (later - earlier).days / 365.25
|
859
859
|
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
short_label = cast(
|
867
|
-
"tuple[str, ValueType]",
|
868
|
-
self.tsdf[base_column].name,
|
869
|
-
)[0]
|
870
|
-
elif isinstance(base_column, int):
|
871
|
-
shortdf = self.tsdf.loc[
|
872
|
-
cast("Timestamp", earlier) : cast("Timestamp", later)
|
873
|
-
].iloc[:, base_column]
|
874
|
-
short_item = cast(
|
875
|
-
"tuple[str, ValueType]",
|
876
|
-
self.tsdf.iloc[:, base_column].name,
|
877
|
-
)
|
878
|
-
short_label = cast("tuple[str, str]", self.tsdf.iloc[:, base_column].name)[
|
879
|
-
0
|
880
|
-
]
|
881
|
-
else:
|
882
|
-
raise TypeError(msg)
|
860
|
+
shortdf, short_item, short_label = _get_base_column_data(
|
861
|
+
self=self,
|
862
|
+
base_column=base_column,
|
863
|
+
earlier=earlier,
|
864
|
+
later=later,
|
865
|
+
)
|
883
866
|
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
867
|
+
time_factor = _calculate_time_factor(
|
868
|
+
data=shortdf,
|
869
|
+
earlier=earlier,
|
870
|
+
later=later,
|
871
|
+
periods_in_a_year_fixed=periods_in_a_year_fixed,
|
872
|
+
)
|
888
873
|
|
889
874
|
terrors = []
|
890
875
|
for item in self.tsdf:
|
@@ -936,7 +921,7 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
936
921
|
comparisons
|
937
922
|
|
938
923
|
Returns:
|
939
|
-
|
924
|
+
--------
|
940
925
|
Pandas.Series[float]
|
941
926
|
Information Ratios
|
942
927
|
|
@@ -946,39 +931,20 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
946
931
|
from_dt=from_date,
|
947
932
|
to_dt=to_date,
|
948
933
|
)
|
949
|
-
fraction: float = (later - earlier).days / 365.25
|
950
934
|
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
short_label = cast(
|
958
|
-
"tuple[str, str]",
|
959
|
-
self.tsdf[base_column].name,
|
960
|
-
)[0]
|
961
|
-
elif isinstance(base_column, int):
|
962
|
-
shortdf = self.tsdf.loc[
|
963
|
-
cast("Timestamp", earlier) : cast("Timestamp", later)
|
964
|
-
].iloc[:, base_column]
|
965
|
-
short_item = cast(
|
966
|
-
"tuple[str, ValueType]",
|
967
|
-
self.tsdf.iloc[
|
968
|
-
:,
|
969
|
-
base_column,
|
970
|
-
].name,
|
971
|
-
)
|
972
|
-
short_label = cast("tuple[str, str]", self.tsdf.iloc[:, base_column].name)[
|
973
|
-
0
|
974
|
-
]
|
975
|
-
else:
|
976
|
-
raise TypeError(msg)
|
935
|
+
shortdf, short_item, short_label = _get_base_column_data(
|
936
|
+
self=self,
|
937
|
+
base_column=base_column,
|
938
|
+
earlier=earlier,
|
939
|
+
later=later,
|
940
|
+
)
|
977
941
|
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
942
|
+
time_factor = _calculate_time_factor(
|
943
|
+
data=shortdf,
|
944
|
+
earlier=earlier,
|
945
|
+
later=later,
|
946
|
+
periods_in_a_year_fixed=periods_in_a_year_fixed,
|
947
|
+
)
|
982
948
|
|
983
949
|
ratios = []
|
984
950
|
for item in self.tsdf:
|
@@ -1038,7 +1004,7 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
1038
1004
|
comparisons
|
1039
1005
|
|
1040
1006
|
Returns:
|
1041
|
-
|
1007
|
+
--------
|
1042
1008
|
Pandas.Series[float]
|
1043
1009
|
Capture Ratios
|
1044
1010
|
|
@@ -1224,7 +1190,7 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
1224
1190
|
Variance bias factor taking the value 0 or 1.
|
1225
1191
|
|
1226
1192
|
Returns:
|
1227
|
-
|
1193
|
+
--------
|
1228
1194
|
float
|
1229
1195
|
Beta as Co-variance of x & y divided by Variance of x
|
1230
1196
|
|
@@ -1293,7 +1259,7 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
1293
1259
|
If True the fit is added as a new column in the .tsdf Pandas.DataFrame
|
1294
1260
|
|
1295
1261
|
Returns:
|
1296
|
-
|
1262
|
+
--------
|
1297
1263
|
dict[str, float]
|
1298
1264
|
A dictionary with the coefficient, intercept and rsquared outputs.
|
1299
1265
|
|
@@ -1362,7 +1328,7 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
1362
1328
|
Variance bias factor taking the value 0 or 1.
|
1363
1329
|
|
1364
1330
|
Returns:
|
1365
|
-
|
1331
|
+
--------
|
1366
1332
|
float
|
1367
1333
|
Jensen's alpha
|
1368
1334
|
|
@@ -1434,7 +1400,7 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
1434
1400
|
weight calculation strategies
|
1435
1401
|
|
1436
1402
|
Returns:
|
1437
|
-
|
1403
|
+
--------
|
1438
1404
|
Pandas.DataFrame
|
1439
1405
|
A basket timeseries
|
1440
1406
|
|
@@ -1451,7 +1417,7 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
1451
1417
|
returns = self.tsdf.ffill().pct_change()
|
1452
1418
|
returns.iloc[0] = 0
|
1453
1419
|
elif all(vtypes):
|
1454
|
-
returns = self.tsdf
|
1420
|
+
returns = self.tsdf
|
1455
1421
|
else:
|
1456
1422
|
msg = "Mix of series types will give inconsistent results"
|
1457
1423
|
raise MixedValuetypesError(msg)
|
@@ -1464,6 +1430,23 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
1464
1430
|
vol = divide(1.0, std(returns, axis=0, ddof=1))
|
1465
1431
|
vol[isinf(vol)] = nan
|
1466
1432
|
self.weights = list(divide(vol, vol.sum()))
|
1433
|
+
elif weight_strat == "max_div":
|
1434
|
+
corr_matrix = corrcoef(returns.T)
|
1435
|
+
corr_matrix[isinf(corr_matrix)] = nan
|
1436
|
+
corr_matrix[isnan(corr_matrix)] = nan
|
1437
|
+
try:
|
1438
|
+
inv_corr_sum = linalg.inv(corr_matrix).sum(axis=1)
|
1439
|
+
self.weights = list(divide(inv_corr_sum, inv_corr_sum.sum()))
|
1440
|
+
except linalg.LinAlgError:
|
1441
|
+
self.weights = [1.0 / self.item_count] * self.item_count
|
1442
|
+
elif weight_strat == "target_risk":
|
1443
|
+
vols = std(returns, axis=0, ddof=1)
|
1444
|
+
min_vol_idx = vols.argmin()
|
1445
|
+
min_vol_weight = 0.6
|
1446
|
+
remaining_weight = 0.4
|
1447
|
+
weights = [remaining_weight / (self.item_count - 1)] * self.item_count
|
1448
|
+
weights[min_vol_idx] = min_vol_weight
|
1449
|
+
self.weights = weights
|
1467
1450
|
else:
|
1468
1451
|
raise NotImplementedError(msg)
|
1469
1452
|
|
@@ -1499,7 +1482,7 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
1499
1482
|
Allows locking the periods-in-a-year to simplify test cases and comparisons
|
1500
1483
|
|
1501
1484
|
Returns:
|
1502
|
-
|
1485
|
+
--------
|
1503
1486
|
Pandas.DataFrame
|
1504
1487
|
Rolling Information Ratios
|
1505
1488
|
|
@@ -1565,7 +1548,7 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
1565
1548
|
Variance bias factor taking the value 0 or 1.
|
1566
1549
|
|
1567
1550
|
Returns:
|
1568
|
-
|
1551
|
+
--------
|
1569
1552
|
Pandas.DataFrame
|
1570
1553
|
Rolling Betas
|
1571
1554
|
|
@@ -1625,7 +1608,7 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
1625
1608
|
The length of the rolling window to use is set as number of observations
|
1626
1609
|
|
1627
1610
|
Returns:
|
1628
|
-
|
1611
|
+
--------
|
1629
1612
|
Pandas.DataFrame
|
1630
1613
|
Rolling Correlations
|
1631
1614
|
|
@@ -1670,7 +1653,7 @@ class OpenFrame(_CommonModel[SeriesFloat]):
|
|
1670
1653
|
to use as the dependent variable
|
1671
1654
|
|
1672
1655
|
Returns:
|
1673
|
-
|
1656
|
+
--------
|
1674
1657
|
tuple[pandas.DataFrame, OpenTimeSeries]
|
1675
1658
|
- A DataFrame with the R-squared, the intercept
|
1676
1659
|
and the regression coefficients
|
openseries/load_plotly.py
CHANGED
@@ -1,11 +1,4 @@
|
|
1
|
-
"""Function to load plotly layout and configuration from local json file.
|
2
|
-
|
3
|
-
Copyright (c) Captor Fund Management AB. This file is part of the openseries project.
|
4
|
-
|
5
|
-
Licensed under the BSD 3-Clause License. You may obtain a copy of the License at:
|
6
|
-
https://github.com/CaptorAB/openseries/blob/master/LICENSE.md
|
7
|
-
SPDX-License-Identifier: BSD-3-Clause
|
8
|
-
"""
|
1
|
+
"""Function to load plotly layout and configuration from local json file."""
|
9
2
|
|
10
3
|
from __future__ import annotations
|
11
4
|
|
@@ -34,7 +27,7 @@ def _check_remote_file_existence(url: str) -> bool:
|
|
34
27
|
Path to remote file
|
35
28
|
|
36
29
|
Returns:
|
37
|
-
|
30
|
+
--------
|
38
31
|
bool
|
39
32
|
True if url is valid and False otherwise
|
40
33
|
|
@@ -62,7 +55,7 @@ def load_plotly_dict(
|
|
62
55
|
Flag whether to load as responsive
|
63
56
|
|
64
57
|
Returns:
|
65
|
-
|
58
|
+
--------
|
66
59
|
tuple[PlotlyLayoutType, CaptorLogoType]
|
67
60
|
A dictionary with the Plotly config and layout template
|
68
61
|
|
openseries/owntypes.py
CHANGED
@@ -1,11 +1,4 @@
|
|
1
|
-
"""Declaring types used throughout the project.
|
2
|
-
|
3
|
-
Copyright (c) Captor Fund Management AB. This file is part of the openseries project.
|
4
|
-
|
5
|
-
Licensed under the BSD 3-Clause License. You may obtain a copy of the License at:
|
6
|
-
https://github.com/CaptorAB/openseries/blob/master/LICENSE.md
|
7
|
-
SPDX-License-Identifier: BSD-3-Clause
|
8
|
-
"""
|
1
|
+
"""Declaring types used throughout the project."""
|
9
2
|
|
10
3
|
from __future__ import annotations
|
11
4
|
|
@@ -35,7 +28,7 @@ except ImportError: # pragma: no cover
|
|
35
28
|
__all__ = ["Self", "ValueType"]
|
36
29
|
|
37
30
|
|
38
|
-
|
31
|
+
SeriesOrFloat_co = TypeVar("SeriesOrFloat_co", float, SeriesFloat, covariant=True)
|
39
32
|
|
40
33
|
|
41
34
|
CountryStringType = Annotated[
|
@@ -142,7 +135,7 @@ LiteralPlotlyHistogramHistNorm = Literal[
|
|
142
135
|
"density",
|
143
136
|
"probability density",
|
144
137
|
]
|
145
|
-
LiteralPortfolioWeightings = Literal["eq_weights", "inv_vol"]
|
138
|
+
LiteralPortfolioWeightings = Literal["eq_weights", "inv_vol", "max_div", "target_risk"]
|
146
139
|
LiteralMinimizeMethods = Literal[
|
147
140
|
"SLSQP",
|
148
141
|
"Nelder-Mead",
|