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/load_plotly.py
CHANGED
@@ -1,32 +1,22 @@
|
|
1
|
-
"""
|
2
|
-
|
3
|
-
|
1
|
+
"""Function to load plotly layout and configuration from local json file."""
|
2
|
+
from __future__ import annotations
|
3
|
+
|
4
4
|
from json import load
|
5
5
|
from os.path import abspath, dirname, join
|
6
|
-
|
6
|
+
|
7
|
+
from openseries.types import PlotlyLayoutType
|
7
8
|
|
8
9
|
|
9
10
|
def load_plotly_dict(
|
10
11
|
responsive: bool = True,
|
11
|
-
) ->
|
12
|
-
|
13
|
-
|
14
|
-
Union[
|
15
|
-
str,
|
16
|
-
int,
|
17
|
-
float,
|
18
|
-
bool,
|
19
|
-
list[str],
|
20
|
-
dict[str, Union[str, int, float, bool, list[str]]],
|
21
|
-
],
|
22
|
-
],
|
23
|
-
dict[str, Union[str, float]],
|
24
|
-
]:
|
25
|
-
"""Function to load the plotly defaults
|
12
|
+
) -> PlotlyLayoutType:
|
13
|
+
"""
|
14
|
+
Load Plotly defaults.
|
26
15
|
|
27
16
|
Parameters
|
28
17
|
----------
|
29
18
|
responsive : bool
|
19
|
+
Flag whether to load as responsive
|
30
20
|
|
31
21
|
Returns
|
32
22
|
-------
|
@@ -36,9 +26,9 @@ def load_plotly_dict(
|
|
36
26
|
layoutfile = join(abspath(project_root), "openseries", "plotly_layouts.json")
|
37
27
|
logofile = join(abspath(project_root), "openseries", "plotly_captor_logo.json")
|
38
28
|
|
39
|
-
with open(layoutfile,
|
29
|
+
with open(layoutfile, encoding="utf-8") as layout_file:
|
40
30
|
fig = load(layout_file)
|
41
|
-
with open(logofile,
|
31
|
+
with open(logofile, encoding="utf-8") as logo_file:
|
42
32
|
logo = load(logo_file)
|
43
33
|
|
44
34
|
fig["config"].update({"responsive": responsive})
|
openseries/risk.py
CHANGED
@@ -8,7 +8,8 @@ from __future__ import annotations
|
|
8
8
|
|
9
9
|
import datetime as dt
|
10
10
|
from math import ceil
|
11
|
-
from typing import
|
11
|
+
from typing import Union, cast
|
12
|
+
|
12
13
|
from numpy import (
|
13
14
|
Inf,
|
14
15
|
isnan,
|
@@ -26,13 +27,17 @@ from openseries.types import LiteralQuantileInterp
|
|
26
27
|
|
27
28
|
|
28
29
|
def cvar_down_calc(
|
29
|
-
data: Union[DataFrame, Series, list[float]],
|
30
|
+
data: Union[DataFrame, Series, list[float]],
|
31
|
+
level: float = 0.95,
|
30
32
|
) -> float:
|
31
|
-
"""
|
33
|
+
"""
|
34
|
+
Calculate downside Conditional Value at Risk (CVaR).
|
35
|
+
|
36
|
+
https://www.investopedia.com/terms/c/conditional_value_at_risk.asp.
|
32
37
|
|
33
38
|
Parameters
|
34
39
|
----------
|
35
|
-
data: DataFrame
|
40
|
+
data: Union[DataFrame, Series, list[float]]
|
36
41
|
The data to perform the calculation over
|
37
42
|
level: float, default: 0.95
|
38
43
|
The sought CVaR level
|
@@ -42,7 +47,6 @@ def cvar_down_calc(
|
|
42
47
|
float
|
43
48
|
Downside Conditional Value At Risk "CVaR"
|
44
49
|
"""
|
45
|
-
|
46
50
|
if isinstance(data, DataFrame):
|
47
51
|
clean = nan_to_num(data.iloc[:, 0])
|
48
52
|
else:
|
@@ -57,13 +61,15 @@ def var_down_calc(
|
|
57
61
|
level: float = 0.95,
|
58
62
|
interpolation: LiteralQuantileInterp = "lower",
|
59
63
|
) -> float:
|
60
|
-
"""
|
61
|
-
|
62
|
-
|
64
|
+
"""
|
65
|
+
Calculate downside Value At Risk (VaR).
|
66
|
+
|
67
|
+
The equivalent of percentile.inc([...], 1-level) over returns in MS Excel
|
68
|
+
https://www.investopedia.com/terms/v/var.asp.
|
63
69
|
|
64
70
|
Parameters
|
65
71
|
----------
|
66
|
-
data: DataFrame
|
72
|
+
data: Union[DataFrame, Series, list[float]]
|
67
73
|
The data to perform the calculation over
|
68
74
|
level: float, default: 0.95
|
69
75
|
The sought VaR level
|
@@ -75,7 +81,6 @@ def var_down_calc(
|
|
75
81
|
float
|
76
82
|
Downside Value At Risk
|
77
83
|
"""
|
78
|
-
|
79
84
|
if isinstance(data, DataFrame):
|
80
85
|
clean = nan_to_num(data.iloc[:, 0])
|
81
86
|
else:
|
@@ -85,7 +90,10 @@ def var_down_calc(
|
|
85
90
|
|
86
91
|
|
87
92
|
def drawdown_series(prices: Union[DataFrame, Series]) -> Union[DataFrame, Series]:
|
88
|
-
"""
|
93
|
+
"""
|
94
|
+
Convert series into a maximum drawdown series.
|
95
|
+
|
96
|
+
Calculates https://www.investopedia.com/terms/d/drawdown.asp
|
89
97
|
This returns a series representing a drawdown. When the price is at all-time
|
90
98
|
highs, the drawdown is 0. However, when prices are below high watermarks,
|
91
99
|
the drawdown series = current / hwm - 1 The max drawdown can be obtained by
|
@@ -94,12 +102,12 @@ def drawdown_series(prices: Union[DataFrame, Series]) -> Union[DataFrame, Series
|
|
94
102
|
|
95
103
|
Parameters
|
96
104
|
----------
|
97
|
-
prices: DataFrame
|
105
|
+
prices: Union[DataFrame, Series]
|
98
106
|
A timeserie of dates and values
|
99
107
|
|
100
108
|
Returns
|
101
109
|
-------
|
102
|
-
DataFrame
|
110
|
+
Union[DataFrame, Series]
|
103
111
|
A drawdown timeserie
|
104
112
|
"""
|
105
113
|
drawdown = prices.copy()
|
@@ -111,11 +119,12 @@ def drawdown_series(prices: Union[DataFrame, Series]) -> Union[DataFrame, Series
|
|
111
119
|
|
112
120
|
|
113
121
|
def drawdown_details(prices: Union[DataFrame, Series], min_periods: int = 1) -> Series:
|
114
|
-
"""
|
122
|
+
"""
|
123
|
+
Details of the maximum drawdown.
|
115
124
|
|
116
125
|
Parameters
|
117
126
|
----------
|
118
|
-
prices: DataFrame
|
127
|
+
prices: Union[DataFrame, Series]
|
119
128
|
A timeserie of dates and values
|
120
129
|
min_periods: int, default: 1
|
121
130
|
Smallest number of observations to use to find the maximum drawdown
|
@@ -129,19 +138,28 @@ def drawdown_details(prices: Union[DataFrame, Series], min_periods: int = 1) ->
|
|
129
138
|
Days from start to bottom
|
130
139
|
Average fall per day
|
131
140
|
"""
|
132
|
-
|
133
141
|
mdd_date = (
|
134
|
-
(prices / prices.expanding(min_periods=min_periods).max())
|
142
|
+
(prices / prices.expanding(min_periods=min_periods).max())
|
143
|
+
.idxmin()
|
144
|
+
.to_numpy()[0]
|
145
|
+
)
|
146
|
+
mdate = (
|
147
|
+
dt.datetime.strptime(str(mdd_date)[:10], "%Y-%m-%d")
|
148
|
+
.replace(tzinfo=dt.timezone.utc)
|
149
|
+
.date()
|
135
150
|
)
|
136
|
-
mdate = dt.datetime.strptime(str(mdd_date)[:10], "%Y-%m-%d").date()
|
137
151
|
maxdown = (
|
138
152
|
(prices / prices.expanding(min_periods=min_periods).max()).min() - 1
|
139
153
|
).iloc[0]
|
140
154
|
ddata = prices.copy()
|
141
155
|
drwdwn = drawdown_series(ddata).loc[: cast(int, mdate)]
|
142
|
-
drwdwn.sort_index(ascending=False
|
143
|
-
sdate = drwdwn[drwdwn == 0.0].idxmax().
|
144
|
-
sdate =
|
156
|
+
drwdwn = drwdwn.sort_index(ascending=False)
|
157
|
+
sdate = drwdwn[drwdwn == 0.0].idxmax().to_numpy()[0]
|
158
|
+
sdate = (
|
159
|
+
dt.datetime.strptime(str(sdate)[:10], "%Y-%m-%d")
|
160
|
+
.replace(tzinfo=dt.timezone.utc)
|
161
|
+
.date()
|
162
|
+
)
|
145
163
|
duration = (mdate - sdate).days
|
146
164
|
ret_per_day = maxdown / duration
|
147
165
|
|
@@ -159,9 +177,13 @@ def drawdown_details(prices: Union[DataFrame, Series], min_periods: int = 1) ->
|
|
159
177
|
|
160
178
|
|
161
179
|
def ewma_calc(
|
162
|
-
reeturn: float,
|
180
|
+
reeturn: float,
|
181
|
+
prev_ewma: float,
|
182
|
+
time_factor: float,
|
183
|
+
lmbda: float = 0.94,
|
163
184
|
) -> float:
|
164
|
-
"""
|
185
|
+
"""
|
186
|
+
Calculate Exponentially Weighted Moving Average volatility.
|
165
187
|
|
166
188
|
Parameters
|
167
189
|
----------
|