openseries 1.5.2__py3-none-any.whl → 1.5.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/_common_model.py +72 -3
- openseries/_risk.py +1 -0
- openseries/datefixer.py +1 -0
- openseries/frame.py +16 -13
- openseries/load_plotly.py +5 -3
- openseries/series.py +1 -0
- openseries/simulation.py +27 -17
- openseries/types.py +2 -0
- {openseries-1.5.2.dist-info → openseries-1.5.4.dist-info}/METADATA +6 -4
- openseries-1.5.4.dist-info/RECORD +15 -0
- openseries-1.5.2.dist-info/RECORD +0 -15
- {openseries-1.5.2.dist-info → openseries-1.5.4.dist-info}/LICENSE.md +0 -0
- {openseries-1.5.2.dist-info → openseries-1.5.4.dist-info}/WHEEL +0 -0
openseries/_common_model.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
"""Defining the _CommonModel class."""
|
2
|
+
|
2
3
|
from __future__ import annotations
|
3
4
|
|
4
5
|
import datetime as dt
|
@@ -162,7 +163,7 @@ class _CommonModel(BaseModel):
|
|
162
163
|
return Series(
|
163
164
|
data=mddc,
|
164
165
|
index=self.tsdf.columns,
|
165
|
-
name="Max
|
166
|
+
name="Max drawdown in cal yr",
|
166
167
|
dtype="float64",
|
167
168
|
)
|
168
169
|
|
@@ -274,6 +275,20 @@ class _CommonModel(BaseModel):
|
|
274
275
|
min_accepted_return=minimum_accepted_return,
|
275
276
|
)
|
276
277
|
|
278
|
+
@property
|
279
|
+
def omega_ratio(self: Self) -> Union[float, Series[float]]:
|
280
|
+
"""
|
281
|
+
https://en.wikipedia.org/wiki/Omega_ratio.
|
282
|
+
|
283
|
+
Returns
|
284
|
+
-------
|
285
|
+
Union[float, Pandas.Series[float]]
|
286
|
+
Omega ratio calculation
|
287
|
+
|
288
|
+
"""
|
289
|
+
minimum_accepted_return: float = 0.0
|
290
|
+
return self.omega_ratio_func(min_accepted_return=minimum_accepted_return)
|
291
|
+
|
277
292
|
@property
|
278
293
|
def z_score(self: Self) -> Union[float, Series[float]]:
|
279
294
|
"""
|
@@ -1678,7 +1693,7 @@ class _CommonModel(BaseModel):
|
|
1678
1693
|
return Series(
|
1679
1694
|
data=result,
|
1680
1695
|
index=self.tsdf.columns,
|
1681
|
-
name="Max
|
1696
|
+
name="Max drawdown",
|
1682
1697
|
dtype="float64",
|
1683
1698
|
)
|
1684
1699
|
|
@@ -1734,7 +1749,7 @@ class _CommonModel(BaseModel):
|
|
1734
1749
|
return Series(
|
1735
1750
|
data=share,
|
1736
1751
|
index=self.tsdf.columns,
|
1737
|
-
name="Positive
|
1752
|
+
name="Positive share",
|
1738
1753
|
dtype="float64",
|
1739
1754
|
)
|
1740
1755
|
|
@@ -1868,6 +1883,60 @@ class _CommonModel(BaseModel):
|
|
1868
1883
|
dtype="float64",
|
1869
1884
|
)
|
1870
1885
|
|
1886
|
+
def omega_ratio_func(
|
1887
|
+
self: Self,
|
1888
|
+
min_accepted_return: float = 0.0,
|
1889
|
+
months_from_last: Optional[int] = None,
|
1890
|
+
from_date: Optional[dt.date] = None,
|
1891
|
+
to_date: Optional[dt.date] = None,
|
1892
|
+
) -> Union[float, Series[float]]:
|
1893
|
+
"""
|
1894
|
+
Omega Ratio.
|
1895
|
+
|
1896
|
+
The Omega Ratio compares returns above a certain target level
|
1897
|
+
(often referred to as the “minimum acceptable return” or “MAR”)
|
1898
|
+
to the total downside risk below that same threshold.
|
1899
|
+
https://en.wikipedia.org/wiki/Omega_ratio.
|
1900
|
+
|
1901
|
+
Parameters
|
1902
|
+
----------
|
1903
|
+
min_accepted_return : float, optional
|
1904
|
+
The annualized Minimum Accepted Return (MAR)
|
1905
|
+
months_from_last : int, optional
|
1906
|
+
number of months offset as positive integer. Overrides use of from_date
|
1907
|
+
and to_date
|
1908
|
+
from_date : datetime.date, optional
|
1909
|
+
Specific from date
|
1910
|
+
to_date : datetime.date, optional
|
1911
|
+
Specific to date
|
1912
|
+
|
1913
|
+
Returns
|
1914
|
+
-------
|
1915
|
+
Union[float, Pandas.Series[float]]
|
1916
|
+
Omega ratio calculation
|
1917
|
+
|
1918
|
+
"""
|
1919
|
+
earlier, later = self.calc_range(
|
1920
|
+
months_offset=months_from_last,
|
1921
|
+
from_dt=from_date,
|
1922
|
+
to_dt=to_date,
|
1923
|
+
)
|
1924
|
+
retdf = self.tsdf.loc[cast(int, earlier) : cast(int, later)].pct_change(
|
1925
|
+
fill_method=cast(str, None),
|
1926
|
+
)
|
1927
|
+
pos = retdf[retdf > min_accepted_return].sub(min_accepted_return).sum()
|
1928
|
+
neg = retdf[retdf < min_accepted_return].sub(min_accepted_return).sum()
|
1929
|
+
ratio = pos / -neg
|
1930
|
+
|
1931
|
+
if self.tsdf.shape[1] == 1:
|
1932
|
+
return float(cast(float64, ratio.iloc[0]))
|
1933
|
+
return Series(
|
1934
|
+
data=ratio,
|
1935
|
+
index=self.tsdf.columns,
|
1936
|
+
name="Omega ratio",
|
1937
|
+
dtype="float64",
|
1938
|
+
)
|
1939
|
+
|
1871
1940
|
def value_ret_func(
|
1872
1941
|
self: Self,
|
1873
1942
|
months_from_last: Optional[int] = None,
|
openseries/_risk.py
CHANGED
openseries/datefixer.py
CHANGED
openseries/frame.py
CHANGED
@@ -1934,8 +1934,9 @@ def efficient_frontier( # noqa: C901
|
|
1934
1934
|
limit_small = 0.0001
|
1935
1935
|
line_df = line_df.mask(line_df.abs() < limit_small, 0.0)
|
1936
1936
|
line_df["text"] = line_df.apply(
|
1937
|
-
lambda c: "<br>"
|
1938
|
-
|
1937
|
+
lambda c: "<br><br>Weights:<br>"
|
1938
|
+
+ "<br>".join(
|
1939
|
+
[f"{c[nm]:.1%} {nm}" for nm in eframe.columns_lvl_zero],
|
1939
1940
|
),
|
1940
1941
|
axis="columns",
|
1941
1942
|
)
|
@@ -2038,9 +2039,9 @@ def prepare_plot_data(
|
|
2038
2039
|
The data prepared with mean returns, volatility and weights
|
2039
2040
|
|
2040
2041
|
"""
|
2041
|
-
txt = "<br>".join(
|
2042
|
+
txt = "<br><br>Weights:<br>" + "<br>".join(
|
2042
2043
|
[
|
2043
|
-
f"{wgt:.1%}
|
2044
|
+
f"{wgt:.1%} {nm}"
|
2044
2045
|
for wgt, nm in zip(
|
2045
2046
|
cast(list[float], assets.weights),
|
2046
2047
|
assets.columns_lvl_zero,
|
@@ -2048,12 +2049,10 @@ def prepare_plot_data(
|
|
2048
2049
|
],
|
2049
2050
|
)
|
2050
2051
|
|
2051
|
-
|
2052
|
-
[
|
2053
|
-
|
2054
|
-
|
2055
|
-
],
|
2056
|
-
)
|
2052
|
+
opt_text_list = [
|
2053
|
+
f"{wgt:.1%} {nm}" for wgt, nm in zip(optimized[3:], assets.columns_lvl_zero)
|
2054
|
+
]
|
2055
|
+
opt_text = "<br><br>Weights:<br>" + "<br>".join(opt_text_list)
|
2057
2056
|
vol: Series[float] = assets.vol
|
2058
2057
|
plotframe = DataFrame(
|
2059
2058
|
data=[
|
@@ -2166,7 +2165,10 @@ def sharpeplot( # noqa: C901
|
|
2166
2165
|
x=line_frame.loc[:, "stdev"],
|
2167
2166
|
y=line_frame.loc[:, "ret"],
|
2168
2167
|
text=line_frame.loc[:, "text"],
|
2169
|
-
|
2168
|
+
xhoverformat=".2%",
|
2169
|
+
yhoverformat=".2%",
|
2170
|
+
hovertemplate="Return %{y}<br>Vol %{x}%{text}",
|
2171
|
+
hoverlabel_align="right",
|
2170
2172
|
line={"width": 2.5, "dash": "solid"},
|
2171
2173
|
mode="lines",
|
2172
2174
|
name="Efficient frontier",
|
@@ -2182,11 +2184,12 @@ def sharpeplot( # noqa: C901
|
|
2182
2184
|
risk.extend([point_frame.loc["stdev", col]])
|
2183
2185
|
figure.add_scatter(
|
2184
2186
|
x=[point_frame.loc["stdev", col]],
|
2185
|
-
xhoverformat=".2%",
|
2186
2187
|
y=[point_frame.loc["ret", col]],
|
2188
|
+
xhoverformat=".2%",
|
2187
2189
|
yhoverformat=".2%",
|
2188
2190
|
hovertext=[point_frame.loc["text", col]],
|
2189
|
-
|
2191
|
+
hovertemplate=("Return %{y}<br>Vol %{x}%{hovertext}"),
|
2192
|
+
hoverlabel_align="right",
|
2190
2193
|
marker={"size": 20, "color": clr},
|
2191
2194
|
mode=point_frame_mode,
|
2192
2195
|
name=col,
|
openseries/load_plotly.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
"""Function to load plotly layout and configuration from local json file."""
|
2
|
+
|
2
3
|
from __future__ import annotations
|
3
4
|
|
4
5
|
from json import load
|
@@ -6,6 +7,7 @@ from logging import warning
|
|
6
7
|
from pathlib import Path
|
7
8
|
|
8
9
|
import requests
|
10
|
+
from requests.exceptions import ConnectionError
|
9
11
|
|
10
12
|
from openseries.types import CaptorLogoType, PlotlyLayoutType
|
11
13
|
|
@@ -31,7 +33,7 @@ def _check_remote_file_existence(url: str) -> bool:
|
|
31
33
|
response = requests.head(url, timeout=30)
|
32
34
|
if response.status_code != ok_code:
|
33
35
|
return False
|
34
|
-
except
|
36
|
+
except ConnectionError:
|
35
37
|
return False
|
36
38
|
return True
|
37
39
|
|
@@ -58,9 +60,9 @@ def load_plotly_dict(
|
|
58
60
|
layoutfile = project_root.joinpath("openseries").joinpath("plotly_layouts.json")
|
59
61
|
logofile = project_root.joinpath("openseries").joinpath("plotly_captor_logo.json")
|
60
62
|
|
61
|
-
with Path.open(layoutfile, encoding="utf-8") as layout_file:
|
63
|
+
with Path.open(layoutfile, mode="r", encoding="utf-8") as layout_file:
|
62
64
|
fig = load(layout_file)
|
63
|
-
with Path.open(logofile, encoding="utf-8") as logo_file:
|
65
|
+
with Path.open(logofile, mode="r", encoding="utf-8") as logo_file:
|
64
66
|
logo = load(logo_file)
|
65
67
|
|
66
68
|
if _check_remote_file_existence(url=logo["source"]) is False:
|
openseries/series.py
CHANGED
openseries/simulation.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
"""Defining the ReturnSimulation class."""
|
2
|
+
|
2
3
|
from __future__ import annotations
|
3
4
|
|
4
5
|
import datetime as dt
|
@@ -76,8 +77,6 @@ class ReturnSimulation(BaseModel):
|
|
76
77
|
This is the average jump size
|
77
78
|
seed: int, optional
|
78
79
|
Seed for random process initiation
|
79
|
-
randomizer: numpy.random.Generator, optional
|
80
|
-
Random process generator
|
81
80
|
|
82
81
|
"""
|
83
82
|
|
@@ -91,7 +90,6 @@ class ReturnSimulation(BaseModel):
|
|
91
90
|
jumps_sigma: NonNegativeFloat = 0.0
|
92
91
|
jumps_mu: float = 0.0
|
93
92
|
seed: Optional[int] = None
|
94
|
-
randomizer: Optional[Generator] = None
|
95
93
|
|
96
94
|
model_config = ConfigDict(
|
97
95
|
arbitrary_types_allowed=True,
|
@@ -159,6 +157,7 @@ class ReturnSimulation(BaseModel):
|
|
159
157
|
trading_days: PositiveInt,
|
160
158
|
seed: int,
|
161
159
|
trading_days_in_year: DaysInYearType = 252,
|
160
|
+
randomizer: Optional[Generator] = None,
|
162
161
|
) -> ReturnSimulation:
|
163
162
|
"""
|
164
163
|
Create a Normal distribution simulation.
|
@@ -178,6 +177,8 @@ class ReturnSimulation(BaseModel):
|
|
178
177
|
trading_days_in_year: DaysInYearType,
|
179
178
|
default: 252
|
180
179
|
Number of trading days used to annualize
|
180
|
+
randomizer: numpy.random.Generator, optional
|
181
|
+
Random process generator
|
181
182
|
|
182
183
|
Returns
|
183
184
|
-------
|
@@ -185,9 +186,10 @@ class ReturnSimulation(BaseModel):
|
|
185
186
|
Normal distribution simulation
|
186
187
|
|
187
188
|
"""
|
188
|
-
|
189
|
+
if not randomizer:
|
190
|
+
randomizer = random_generator(seed=seed)
|
189
191
|
|
190
|
-
returns =
|
192
|
+
returns = randomizer.normal(
|
191
193
|
loc=mean_annual_return / trading_days_in_year,
|
192
194
|
scale=mean_annual_vol / sqrt(trading_days_in_year),
|
193
195
|
size=(number_of_sims, trading_days),
|
@@ -201,7 +203,6 @@ class ReturnSimulation(BaseModel):
|
|
201
203
|
mean_annual_vol=mean_annual_vol,
|
202
204
|
dframe=DataFrame(data=returns, dtype="float64"),
|
203
205
|
seed=seed,
|
204
|
-
randomizer=cls.randomizer,
|
205
206
|
)
|
206
207
|
|
207
208
|
@classmethod
|
@@ -213,6 +214,7 @@ class ReturnSimulation(BaseModel):
|
|
213
214
|
trading_days: PositiveInt,
|
214
215
|
seed: int,
|
215
216
|
trading_days_in_year: DaysInYearType = 252,
|
217
|
+
randomizer: Optional[Generator] = None,
|
216
218
|
) -> ReturnSimulation:
|
217
219
|
"""
|
218
220
|
Create a Lognormal distribution simulation.
|
@@ -232,6 +234,8 @@ class ReturnSimulation(BaseModel):
|
|
232
234
|
trading_days_in_year: DaysInYearType,
|
233
235
|
default: 252
|
234
236
|
Number of trading days used to annualize
|
237
|
+
randomizer: numpy.random.Generator, optional
|
238
|
+
Random process generator
|
235
239
|
|
236
240
|
Returns
|
237
241
|
-------
|
@@ -239,10 +243,11 @@ class ReturnSimulation(BaseModel):
|
|
239
243
|
Lognormal distribution simulation
|
240
244
|
|
241
245
|
"""
|
242
|
-
|
246
|
+
if not randomizer:
|
247
|
+
randomizer = random_generator(seed=seed)
|
243
248
|
|
244
249
|
returns = (
|
245
|
-
|
250
|
+
randomizer.lognormal(
|
246
251
|
mean=mean_annual_return / trading_days_in_year,
|
247
252
|
sigma=mean_annual_vol / sqrt(trading_days_in_year),
|
248
253
|
size=(number_of_sims, trading_days),
|
@@ -258,7 +263,6 @@ class ReturnSimulation(BaseModel):
|
|
258
263
|
mean_annual_vol=mean_annual_vol,
|
259
264
|
dframe=DataFrame(data=returns, dtype="float64"),
|
260
265
|
seed=seed,
|
261
|
-
randomizer=cls.randomizer,
|
262
266
|
)
|
263
267
|
|
264
268
|
@classmethod
|
@@ -270,6 +274,7 @@ class ReturnSimulation(BaseModel):
|
|
270
274
|
trading_days: PositiveInt,
|
271
275
|
seed: int,
|
272
276
|
trading_days_in_year: DaysInYearType = 252,
|
277
|
+
randomizer: Optional[Generator] = None,
|
273
278
|
) -> ReturnSimulation:
|
274
279
|
"""
|
275
280
|
Create a Geometric Brownian Motion simulation.
|
@@ -288,6 +293,8 @@ class ReturnSimulation(BaseModel):
|
|
288
293
|
Seed for random process initiation
|
289
294
|
trading_days_in_year: DaysInYearType, default: 252
|
290
295
|
Number of trading days used to annualize
|
296
|
+
randomizer: numpy.random.Generator, optional
|
297
|
+
Random process generator
|
291
298
|
|
292
299
|
Returns
|
293
300
|
-------
|
@@ -295,14 +302,15 @@ class ReturnSimulation(BaseModel):
|
|
295
302
|
Geometric Brownian Motion simulation
|
296
303
|
|
297
304
|
"""
|
298
|
-
|
305
|
+
if not randomizer:
|
306
|
+
randomizer = random_generator(seed=seed)
|
299
307
|
|
300
308
|
drift = (mean_annual_return - 0.5 * mean_annual_vol**2.0) * (
|
301
309
|
1.0 / trading_days_in_year
|
302
310
|
)
|
303
311
|
|
304
312
|
normal_mean = 0.0
|
305
|
-
wiener =
|
313
|
+
wiener = randomizer.normal(
|
306
314
|
loc=normal_mean,
|
307
315
|
scale=sqrt(1.0 / trading_days_in_year) * mean_annual_vol,
|
308
316
|
size=(number_of_sims, trading_days),
|
@@ -318,7 +326,6 @@ class ReturnSimulation(BaseModel):
|
|
318
326
|
mean_annual_vol=mean_annual_vol,
|
319
327
|
dframe=DataFrame(data=returns, dtype="float64"),
|
320
328
|
seed=seed,
|
321
|
-
randomizer=cls.randomizer,
|
322
329
|
)
|
323
330
|
|
324
331
|
@classmethod
|
@@ -333,6 +340,7 @@ class ReturnSimulation(BaseModel):
|
|
333
340
|
jumps_sigma: NonNegativeFloat = 0.0,
|
334
341
|
jumps_mu: float = 0.0,
|
335
342
|
trading_days_in_year: DaysInYearType = 252,
|
343
|
+
randomizer: Optional[Generator] = None,
|
336
344
|
) -> ReturnSimulation:
|
337
345
|
"""
|
338
346
|
Create a Merton Jump-Diffusion model simulation.
|
@@ -357,6 +365,8 @@ class ReturnSimulation(BaseModel):
|
|
357
365
|
This is the average jump size
|
358
366
|
trading_days_in_year: DaysInYearType, default: 252
|
359
367
|
Number of trading days used to annualize
|
368
|
+
randomizer: numpy.random.Generator, optional
|
369
|
+
Random process generator
|
360
370
|
|
361
371
|
Returns
|
362
372
|
-------
|
@@ -364,21 +374,22 @@ class ReturnSimulation(BaseModel):
|
|
364
374
|
Merton Jump-Diffusion model simulation
|
365
375
|
|
366
376
|
"""
|
367
|
-
|
377
|
+
if not randomizer:
|
378
|
+
randomizer = random_generator(seed=seed)
|
368
379
|
|
369
380
|
normal_mean = 0.0
|
370
|
-
wiener =
|
381
|
+
wiener = randomizer.normal(
|
371
382
|
loc=normal_mean,
|
372
383
|
scale=sqrt(1.0 / trading_days_in_year) * mean_annual_vol,
|
373
384
|
size=(number_of_sims, trading_days),
|
374
385
|
)
|
375
386
|
|
376
387
|
poisson_jumps = multiply(
|
377
|
-
|
388
|
+
randomizer.poisson(
|
378
389
|
lam=jumps_lamda * (1.0 / trading_days_in_year),
|
379
390
|
size=(number_of_sims, trading_days),
|
380
391
|
),
|
381
|
-
|
392
|
+
randomizer.normal(
|
382
393
|
loc=jumps_mu,
|
383
394
|
scale=jumps_sigma,
|
384
395
|
size=(number_of_sims, trading_days),
|
@@ -406,7 +417,6 @@ class ReturnSimulation(BaseModel):
|
|
406
417
|
jumps_mu=jumps_mu,
|
407
418
|
dframe=DataFrame(data=returns, dtype="float64"),
|
408
419
|
seed=seed,
|
409
|
-
randomizer=cls.randomizer,
|
410
420
|
)
|
411
421
|
|
412
422
|
def to_dataframe(
|
openseries/types.py
CHANGED
@@ -220,6 +220,7 @@ class OpenTimeSeriesPropertiesList(list[str]):
|
|
220
220
|
"downside_deviation",
|
221
221
|
"ret_vol_ratio",
|
222
222
|
"sortino_ratio",
|
223
|
+
"omega_ratio",
|
223
224
|
"z_score",
|
224
225
|
"skew",
|
225
226
|
"kurtosis",
|
@@ -276,6 +277,7 @@ class OpenFramePropertiesList(list[str]):
|
|
276
277
|
"downside_deviation",
|
277
278
|
"ret_vol_ratio",
|
278
279
|
"sortino_ratio",
|
280
|
+
"omega_ratio",
|
279
281
|
"z_score",
|
280
282
|
"skew",
|
281
283
|
"kurtosis",
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: openseries
|
3
|
-
Version: 1.5.
|
3
|
+
Version: 1.5.4
|
4
4
|
Summary: Tools for analyzing financial timeseries.
|
5
5
|
Home-page: https://github.com/CaptorAB/openseries
|
6
6
|
License: BSD-3-Clause
|
@@ -25,7 +25,7 @@ Requires-Dist: numpy (>=1.23.2,<=2.0.0)
|
|
25
25
|
Requires-Dist: openpyxl (>=3.1.2,<4.0.0)
|
26
26
|
Requires-Dist: pandas (>=2.1.2,<3.0.0)
|
27
27
|
Requires-Dist: plotly (>=5.18.0,<6.0.0)
|
28
|
-
Requires-Dist: pyarrow (>=14.0.2,<
|
28
|
+
Requires-Dist: pyarrow (>=14.0.2,<17.0.0)
|
29
29
|
Requires-Dist: pydantic (>=2.5.2,<3.0.0)
|
30
30
|
Requires-Dist: python-dateutil (>=2.8.2,<3.0.0)
|
31
31
|
Requires-Dist: requests (>=2.20.0,<3.0.0)
|
@@ -53,7 +53,7 @@ width="81" height="100" align="left" float="right"/><br/>
|
|
53
53
|
[](https://beta.ruff.rs/docs/)
|
54
54
|
[](https://opensource.org/licenses/BSD-3-Clause)
|
55
55
|
|
56
|
-
|
56
|
+
This is a project with tools to analyze financial timeseries of a single
|
57
57
|
asset or a group of assets. It is solely made for daily or less frequent data.
|
58
58
|
|
59
59
|
<span style="font-size:2em;">[CHANGELOG](https://github.com/CaptorAB/openseries/blob/master/CHANGELOG.md)</span>
|
@@ -289,6 +289,7 @@ make lint
|
|
289
289
|
| `rolling_info_ratio` | `OpenFrame` | Returns a pandas.DataFrame with the rolling [information ratio](https://www.investopedia.com/terms/i/informationratio.asp) between two series. |
|
290
290
|
| `rolling_beta` | `OpenFrame` | Returns a pandas.DataFrame with the rolling [Beta](https://www.investopedia.com/terms/b/beta.asp) of an asset relative a market. |
|
291
291
|
| `rolling_corr` | `OpenFrame` | Calculates and adds a series of rolling [correlations](https://www.investopedia.com/terms/c/correlation.asp) between two other series. |
|
292
|
+
| `correl_matrix` | `OpenFrame` | Returns a `pandas.DataFrame` with a correlation matrix. |
|
292
293
|
| `ewma_risk` | `OpenFrame` | Returns a `pandas.DataFrame` with volatility and correlation based on [Exponentially Weighted Moving Average](https://www.investopedia.com/articles/07/ewma.asp). |
|
293
294
|
|
294
295
|
### Methods that apply to both the [OpenTimeSeries](https://github.com/CaptorAB/openseries/blob/master/openseries/series.py) and the [OpenFrame](https://github.com/CaptorAB/openseries/blob/master/openseries/frame.py) class.
|
@@ -328,6 +329,7 @@ make lint
|
|
328
329
|
| `downside_deviation` | `float`, `pandas.Series` | `OpenTimeSeries`, `OpenFrame` | [Downside deviation](https://www.investopedia.com/terms/d/downside-deviation.asp) is the volatility of all negative return observations. Minimum Accepted Return (MAR) set to zero. |
|
329
330
|
| `ret_vol_ratio` | `float`, `pandas.Series` | `OpenTimeSeries`, `OpenFrame` | Ratio of arithmetic mean return and annualized volatility. It is the [Sharpe Ratio](https://www.investopedia.com/terms/s/sharperatio.asp) with the riskfree rate set to zero. |
|
330
331
|
| `sortino_ratio` | `float`, `pandas.Series` | `OpenTimeSeries`, `OpenFrame` | The [Sortino Ratio](https://www.investopedia.com/terms/s/sortinoratio.asp) is the arithmetic mean return divided by the downside deviation. This attribute assumes that the riskfree rate and the MAR are both zero. |
|
332
|
+
| `omega_ratio` | `float`, `pandas.Series` | `OpenTimeSeries`, `OpenFrame` | The [Omega Ratio](https://en.wikipedia.org/wiki/Omega_ratio) compares returns above a certain target level (MAR) to the total downside risk below MAR. |
|
331
333
|
| `var_down` | `float`, `pandas.Series` | `OpenTimeSeries`, `OpenFrame` | Downside 95% [Value At Risk](https://www.investopedia.com/terms/v/var.asp), "VaR". The equivalent of percentile.inc([...], 1-level) over returns in MS Excel. For other confidence levels use the corresponding method. |
|
332
334
|
| `cvar_down` | `float`, `pandas.Series` | `OpenTimeSeries`, `OpenFrame` | Downside 95% [Conditional Value At Risk](https://www.investopedia.com/terms/c/conditional_value_at_risk.asp), "CVaR". For other confidence levels use the corresponding method. |
|
333
335
|
| `worst` | `float`, `pandas.Series` | `OpenTimeSeries`, `OpenFrame` | Most negative percentage change of a single observation. |
|
@@ -339,7 +341,6 @@ make lint
|
|
339
341
|
| `skew` | `float`, `pandas.Series` | `OpenTimeSeries`, `OpenFrame` | [Skew](https://www.investopedia.com/terms/s/skewness.asp) of the return distribution. |
|
340
342
|
| `kurtosis` | `float`, `pandas.Series` | `OpenTimeSeries`, `OpenFrame` | [Kurtosis](https://www.investopedia.com/terms/k/kurtosis.asp) of the return distribution. |
|
341
343
|
| `z_score` | `float`, `pandas.Series` | `OpenTimeSeries`, `OpenFrame` | [Z-score](https://www.investopedia.com/terms/z/zscore.asp) as (last return - mean return) / standard deviation of returns. |
|
342
|
-
| `correl_matrix` | `pandas.DataFrame` | `OpenFrame` | A correlation matrix. |
|
343
344
|
|
344
345
|
### Methods below are identical to the Numerical Properties above.
|
345
346
|
|
@@ -355,6 +356,7 @@ properties for subset periods._
|
|
355
356
|
| `downside_deviation_func` | `float`, `pandas.Series` | `OpenTimeSeries`, `OpenFrame` | [Downside deviation](https://www.investopedia.com/terms/d/downside-deviation.asp) is the volatility of all negative return observations. MAR and riskfree rate can be set. |
|
356
357
|
| `ret_vol_ratio_func` | `float`, `pandas.Series` | `OpenTimeSeries`, `OpenFrame` | Ratio of arithmetic mean return and annualized volatility. It is the [Sharpe Ratio](https://www.investopedia.com/terms/s/sharperatio.asp) with the riskfree rate set to zero. A riskfree rate can be set as a float or a series chosen for the frame function. |
|
357
358
|
| `sortino_ratio_func` | `float`, `pandas.Series` | `OpenTimeSeries`, `OpenFrame` | The [Sortino Ratio](https://www.investopedia.com/terms/s/sortinoratio.asp) is the arithmetic mean return divided by the downside deviation. A riskfree rate can be set as a float or a series chosen for the frame function. MAR is set to zero. |
|
359
|
+
| `omega_ratio_func` | `float`, `pandas.Series` | `OpenTimeSeries`, `OpenFrame` | The [Omega Ratio](https://en.wikipedia.org/wiki/Omega_ratio) compares returns above a certain target level (MAR) to the total downside risk below MAR. |
|
358
360
|
| `var_down_func` | `float`, `pandas.Series` | `OpenTimeSeries`, `OpenFrame` | Downside 95% [Value At Risk](https://www.investopedia.com/terms/v/var.asp), "VaR". The equivalent of percentile.inc([...], 1-level) over returns in MS Excel. Default is 95% confidence level. |
|
359
361
|
| `cvar_down_func` | `float`, `pandas.Series` | `OpenTimeSeries`, `OpenFrame` | Downside 95% [Conditional Value At Risk](https://www.investopedia.com/terms/c/conditional_value_at_risk.asp), "CVaR". Default is 95% confidence level. |
|
360
362
|
| `worst_func` | `float`, `pandas.Series` | `OpenTimeSeries`, `OpenFrame` | Most negative percentage change for a given number of observations (default=1). |
|
@@ -0,0 +1,15 @@
|
|
1
|
+
openseries/__init__.py,sha256=W429Ojwa-wPgHV5PDAOQOBOAzPOR4wrVHRwdZQjRKcQ,41
|
2
|
+
openseries/_common_model.py,sha256=ETr8vueNHrMC5dZGHP2V3DowIg-jzgmhdOwCI_4258M,74705
|
3
|
+
openseries/_risk.py,sha256=4ckiA-0-uuoUOsuc_uElUA_2rLS_U3xJyiva2BX4W1s,3300
|
4
|
+
openseries/datefixer.py,sha256=ZOSPp4kLkMEsZv50GQaSo2vAEDVaXEr9iX3wTO7ZdB4,12378
|
5
|
+
openseries/frame.py,sha256=SH1sPUFoJS71o2uVJBLoDl3rSC8AP7wQZw3baMD9T4U,74019
|
6
|
+
openseries/load_plotly.py,sha256=L4A3Fa5Jk47FY7pcg0NPZ0gm0JD_uCXjVlGC7FWVSJg,1856
|
7
|
+
openseries/plotly_captor_logo.json,sha256=F5nhMzEyxKywtjvQqMTKgKRCJQYMDIiBgDSxdte8Clo,178
|
8
|
+
openseries/plotly_layouts.json,sha256=ahx8-dL4_RPzvHtBOX0SiL0AH7xQJzNRSDhGrSmU-Og,1429
|
9
|
+
openseries/series.py,sha256=pIpiD3v8z7SyIppBatbsPuqOWCf3qI_us2145JnPUkQ,28313
|
10
|
+
openseries/simulation.py,sha256=VYxc-e5VSyC55DdfACpQen-necYbhso-6RMyOhYX-5k,13905
|
11
|
+
openseries/types.py,sha256=fSSg9hzQd9cTY8Q3MVdCOtoSu4zFxX4GSk6778LdCNo,7643
|
12
|
+
openseries-1.5.4.dist-info/LICENSE.md,sha256=cPUabMxJ6-ziqzqS6aLGkR-ilIOKe_s3Qtyp0ioTmo0,1521
|
13
|
+
openseries-1.5.4.dist-info/METADATA,sha256=JhTQclCLTBKzyUE3uD_P-Oa6Ayfu2pAgljK-yODn_YU,44222
|
14
|
+
openseries-1.5.4.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
15
|
+
openseries-1.5.4.dist-info/RECORD,,
|
@@ -1,15 +0,0 @@
|
|
1
|
-
openseries/__init__.py,sha256=W429Ojwa-wPgHV5PDAOQOBOAzPOR4wrVHRwdZQjRKcQ,41
|
2
|
-
openseries/_common_model.py,sha256=PGJDMI305RrxThXaBXSdKrMOvUozjjNprhWilKcp-G0,72468
|
3
|
-
openseries/_risk.py,sha256=JnwAklqs2G3YIp9KTNKbumqs4VgfFIk-eFs0dZ-_jCY,3299
|
4
|
-
openseries/datefixer.py,sha256=3DQz_nUbUVBHCxM5wdqbAQUfdG-9xN3S5yqEX4F_NpI,12377
|
5
|
-
openseries/frame.py,sha256=en_GL0_l9OHsZk6AmYin5Pip7geLyTeLZNAZqIR4xcI,73772
|
6
|
-
openseries/load_plotly.py,sha256=kIjvJ2H1sIXWsjd-mZclLvj7ebh-4Hdb1dwB2gR9b-Y,1807
|
7
|
-
openseries/plotly_captor_logo.json,sha256=F5nhMzEyxKywtjvQqMTKgKRCJQYMDIiBgDSxdte8Clo,178
|
8
|
-
openseries/plotly_layouts.json,sha256=ahx8-dL4_RPzvHtBOX0SiL0AH7xQJzNRSDhGrSmU-Og,1429
|
9
|
-
openseries/series.py,sha256=jHbJkzFUeGokUJZ1Md4Hx1keSwpNMjPq1r_FDCputIE,28312
|
10
|
-
openseries/simulation.py,sha256=y9A_kNuGoIqVlFsQzxA39hBi9Nt9X1yN2VYjShYNhtE,13549
|
11
|
-
openseries/types.py,sha256=qOKWorkGsv22Q0b2RvMW8IS2pkO3PJlbhQfAviRYNts,7597
|
12
|
-
openseries-1.5.2.dist-info/LICENSE.md,sha256=cPUabMxJ6-ziqzqS6aLGkR-ilIOKe_s3Qtyp0ioTmo0,1521
|
13
|
-
openseries-1.5.2.dist-info/METADATA,sha256=5siFdLZ275Ry94LNRRA4VlD--ye9-uafpxC6HjLorjY,43661
|
14
|
-
openseries-1.5.2.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
15
|
-
openseries-1.5.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|