openseries 1.5.3__py3-none-any.whl → 1.5.5__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 +92 -11
- openseries/load_plotly.py +4 -3
- openseries/types.py +3 -0
- {openseries-1.5.3.dist-info → openseries-1.5.5.dist-info}/METADATA +4 -2
- {openseries-1.5.3.dist-info → openseries-1.5.5.dist-info}/RECORD +7 -7
- {openseries-1.5.3.dist-info → openseries-1.5.5.dist-info}/LICENSE.md +0 -0
- {openseries-1.5.3.dist-info → openseries-1.5.5.dist-info}/WHEEL +0 -0
openseries/_common_model.py
CHANGED
@@ -38,6 +38,7 @@ from openseries.types import (
|
|
38
38
|
CountriesType,
|
39
39
|
DaysInYearType,
|
40
40
|
LiteralBarPlotMode,
|
41
|
+
LiteralJsonOutput,
|
41
42
|
LiteralLinePlotMode,
|
42
43
|
LiteralNanMethod,
|
43
44
|
LiteralPlotlyJSlib,
|
@@ -163,7 +164,7 @@ class _CommonModel(BaseModel):
|
|
163
164
|
return Series(
|
164
165
|
data=mddc,
|
165
166
|
index=self.tsdf.columns,
|
166
|
-
name="Max
|
167
|
+
name="Max drawdown in cal yr",
|
167
168
|
dtype="float64",
|
168
169
|
)
|
169
170
|
|
@@ -275,6 +276,20 @@ class _CommonModel(BaseModel):
|
|
275
276
|
min_accepted_return=minimum_accepted_return,
|
276
277
|
)
|
277
278
|
|
279
|
+
@property
|
280
|
+
def omega_ratio(self: Self) -> Union[float, Series[float]]:
|
281
|
+
"""
|
282
|
+
https://en.wikipedia.org/wiki/Omega_ratio.
|
283
|
+
|
284
|
+
Returns
|
285
|
+
-------
|
286
|
+
Union[float, Pandas.Series[float]]
|
287
|
+
Omega ratio calculation
|
288
|
+
|
289
|
+
"""
|
290
|
+
minimum_accepted_return: float = 0.0
|
291
|
+
return self.omega_ratio_func(min_accepted_return=minimum_accepted_return)
|
292
|
+
|
278
293
|
@property
|
279
294
|
def z_score(self: Self) -> Union[float, Series[float]]:
|
280
295
|
"""
|
@@ -637,16 +652,18 @@ class _CommonModel(BaseModel):
|
|
637
652
|
|
638
653
|
def to_json(
|
639
654
|
self: Self,
|
655
|
+
what_output: LiteralJsonOutput,
|
640
656
|
filename: str,
|
641
657
|
directory: Optional[DirectoryPath] = None,
|
642
658
|
) -> list[dict[str, Union[str, bool, ValueType, list[str], list[float]]]]:
|
643
659
|
"""
|
644
660
|
Dump timeseries data into a json file.
|
645
661
|
|
646
|
-
The label and tsdf parameters are deleted before the json file is saved
|
647
|
-
|
648
662
|
Parameters
|
649
663
|
----------
|
664
|
+
what_output: LiteralJsonOutput
|
665
|
+
Choice on whether the raw values or the tsdf Dataframe values are
|
666
|
+
returned as json and exported as json file.
|
650
667
|
filename: str
|
651
668
|
Filename including filetype
|
652
669
|
directory: DirectoryPath, optional
|
@@ -655,7 +672,7 @@ class _CommonModel(BaseModel):
|
|
655
672
|
Returns
|
656
673
|
-------
|
657
674
|
list[Dict[str, Union[str, bool, ValueType, list[str], list[float]]]]
|
658
|
-
A list of dictionaries with the
|
675
|
+
A list of dictionaries with the data of the series
|
659
676
|
|
660
677
|
"""
|
661
678
|
if directory:
|
@@ -669,21 +686,31 @@ class _CommonModel(BaseModel):
|
|
669
686
|
data = dict(self.__dict__)
|
670
687
|
output = []
|
671
688
|
if "label" in data:
|
689
|
+
if what_output == "tsdf":
|
690
|
+
values = self.tsdf.iloc[:, 0].tolist()
|
691
|
+
else:
|
692
|
+
values = list(cast(list[float], data.get("values")))
|
672
693
|
for item in cleaner_list:
|
673
694
|
data.pop(item)
|
695
|
+
valuetype = cast(ValueType, data.get("valuetype")).value
|
696
|
+
data.update({"valuetype": valuetype})
|
697
|
+
data.update({"values": values})
|
674
698
|
output.append(dict(data))
|
675
699
|
else:
|
676
700
|
for serie in cast(list[Any], data.get("constituents")):
|
701
|
+
if what_output == "tsdf":
|
702
|
+
values = serie.tsdf.iloc[:, 0].tolist()
|
703
|
+
else:
|
704
|
+
values = list(serie.values)
|
677
705
|
itemdata = dict(serie.__dict__)
|
678
706
|
for item in cleaner_list:
|
679
707
|
itemdata.pop(item)
|
708
|
+
valuetype = cast(ValueType, itemdata["valuetype"]).value
|
709
|
+
itemdata.update({"valuetype": valuetype})
|
710
|
+
itemdata.update({"values": values})
|
680
711
|
output.append(dict(itemdata))
|
681
712
|
|
682
|
-
with
|
683
|
-
dirpath.joinpath(filename),
|
684
|
-
"w",
|
685
|
-
encoding="utf-8",
|
686
|
-
) as jsonfile:
|
713
|
+
with dirpath.joinpath(filename).open(mode="w", encoding="utf-8") as jsonfile:
|
687
714
|
dump(output, jsonfile, indent=2, sort_keys=False)
|
688
715
|
|
689
716
|
return output
|
@@ -1679,7 +1706,7 @@ class _CommonModel(BaseModel):
|
|
1679
1706
|
return Series(
|
1680
1707
|
data=result,
|
1681
1708
|
index=self.tsdf.columns,
|
1682
|
-
name="Max
|
1709
|
+
name="Max drawdown",
|
1683
1710
|
dtype="float64",
|
1684
1711
|
)
|
1685
1712
|
|
@@ -1735,7 +1762,7 @@ class _CommonModel(BaseModel):
|
|
1735
1762
|
return Series(
|
1736
1763
|
data=share,
|
1737
1764
|
index=self.tsdf.columns,
|
1738
|
-
name="Positive
|
1765
|
+
name="Positive share",
|
1739
1766
|
dtype="float64",
|
1740
1767
|
)
|
1741
1768
|
|
@@ -1869,6 +1896,60 @@ class _CommonModel(BaseModel):
|
|
1869
1896
|
dtype="float64",
|
1870
1897
|
)
|
1871
1898
|
|
1899
|
+
def omega_ratio_func(
|
1900
|
+
self: Self,
|
1901
|
+
min_accepted_return: float = 0.0,
|
1902
|
+
months_from_last: Optional[int] = None,
|
1903
|
+
from_date: Optional[dt.date] = None,
|
1904
|
+
to_date: Optional[dt.date] = None,
|
1905
|
+
) -> Union[float, Series[float]]:
|
1906
|
+
"""
|
1907
|
+
Omega Ratio.
|
1908
|
+
|
1909
|
+
The Omega Ratio compares returns above a certain target level
|
1910
|
+
(often referred to as the “minimum acceptable return” or “MAR”)
|
1911
|
+
to the total downside risk below that same threshold.
|
1912
|
+
https://en.wikipedia.org/wiki/Omega_ratio.
|
1913
|
+
|
1914
|
+
Parameters
|
1915
|
+
----------
|
1916
|
+
min_accepted_return : float, optional
|
1917
|
+
The annualized Minimum Accepted Return (MAR)
|
1918
|
+
months_from_last : int, optional
|
1919
|
+
number of months offset as positive integer. Overrides use of from_date
|
1920
|
+
and to_date
|
1921
|
+
from_date : datetime.date, optional
|
1922
|
+
Specific from date
|
1923
|
+
to_date : datetime.date, optional
|
1924
|
+
Specific to date
|
1925
|
+
|
1926
|
+
Returns
|
1927
|
+
-------
|
1928
|
+
Union[float, Pandas.Series[float]]
|
1929
|
+
Omega ratio calculation
|
1930
|
+
|
1931
|
+
"""
|
1932
|
+
earlier, later = self.calc_range(
|
1933
|
+
months_offset=months_from_last,
|
1934
|
+
from_dt=from_date,
|
1935
|
+
to_dt=to_date,
|
1936
|
+
)
|
1937
|
+
retdf = self.tsdf.loc[cast(int, earlier) : cast(int, later)].pct_change(
|
1938
|
+
fill_method=cast(str, None),
|
1939
|
+
)
|
1940
|
+
pos = retdf[retdf > min_accepted_return].sub(min_accepted_return).sum()
|
1941
|
+
neg = retdf[retdf < min_accepted_return].sub(min_accepted_return).sum()
|
1942
|
+
ratio = pos / -neg
|
1943
|
+
|
1944
|
+
if self.tsdf.shape[1] == 1:
|
1945
|
+
return float(cast(float64, ratio.iloc[0]))
|
1946
|
+
return Series(
|
1947
|
+
data=ratio,
|
1948
|
+
index=self.tsdf.columns,
|
1949
|
+
name="Omega ratio",
|
1950
|
+
dtype="float64",
|
1951
|
+
)
|
1952
|
+
|
1872
1953
|
def value_ret_func(
|
1873
1954
|
self: Self,
|
1874
1955
|
months_from_last: Optional[int] = None,
|
openseries/load_plotly.py
CHANGED
@@ -7,6 +7,7 @@ from logging import warning
|
|
7
7
|
from pathlib import Path
|
8
8
|
|
9
9
|
import requests
|
10
|
+
from requests.exceptions import ConnectionError
|
10
11
|
|
11
12
|
from openseries.types import CaptorLogoType, PlotlyLayoutType
|
12
13
|
|
@@ -32,7 +33,7 @@ def _check_remote_file_existence(url: str) -> bool:
|
|
32
33
|
response = requests.head(url, timeout=30)
|
33
34
|
if response.status_code != ok_code:
|
34
35
|
return False
|
35
|
-
except
|
36
|
+
except ConnectionError:
|
36
37
|
return False
|
37
38
|
return True
|
38
39
|
|
@@ -59,9 +60,9 @@ def load_plotly_dict(
|
|
59
60
|
layoutfile = project_root.joinpath("openseries").joinpath("plotly_layouts.json")
|
60
61
|
logofile = project_root.joinpath("openseries").joinpath("plotly_captor_logo.json")
|
61
62
|
|
62
|
-
with Path.open(layoutfile, encoding="utf-8") as layout_file:
|
63
|
+
with Path.open(layoutfile, mode="r", encoding="utf-8") as layout_file:
|
63
64
|
fig = load(layout_file)
|
64
|
-
with Path.open(logofile, encoding="utf-8") as logo_file:
|
65
|
+
with Path.open(logofile, mode="r", encoding="utf-8") as logo_file:
|
65
66
|
logo = load(logo_file)
|
66
67
|
|
67
68
|
if _check_remote_file_existence(url=logo["source"]) is False:
|
openseries/types.py
CHANGED
@@ -113,6 +113,7 @@ PlotlyLayoutType = dict[
|
|
113
113
|
|
114
114
|
CaptorLogoType = dict[str, Union[str, float]]
|
115
115
|
|
116
|
+
LiteralJsonOutput = Literal["values", "tsdf"]
|
116
117
|
LiteralTrunc = Literal["before", "after", "both"]
|
117
118
|
LiteralLinePlotMode = Literal[
|
118
119
|
"lines",
|
@@ -220,6 +221,7 @@ class OpenTimeSeriesPropertiesList(list[str]):
|
|
220
221
|
"downside_deviation",
|
221
222
|
"ret_vol_ratio",
|
222
223
|
"sortino_ratio",
|
224
|
+
"omega_ratio",
|
223
225
|
"z_score",
|
224
226
|
"skew",
|
225
227
|
"kurtosis",
|
@@ -276,6 +278,7 @@ class OpenFramePropertiesList(list[str]):
|
|
276
278
|
"downside_deviation",
|
277
279
|
"ret_vol_ratio",
|
278
280
|
"sortino_ratio",
|
281
|
+
"omega_ratio",
|
279
282
|
"z_score",
|
280
283
|
"skew",
|
281
284
|
"kurtosis",
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: openseries
|
3
|
-
Version: 1.5.
|
3
|
+
Version: 1.5.5
|
4
4
|
Summary: Tools for analyzing financial timeseries.
|
5
5
|
Home-page: https://github.com/CaptorAB/openseries
|
6
6
|
License: BSD-3-Clause
|
@@ -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>
|
@@ -329,6 +329,7 @@ make lint
|
|
329
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. |
|
330
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. |
|
331
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. |
|
332
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. |
|
333
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. |
|
334
335
|
| `worst` | `float`, `pandas.Series` | `OpenTimeSeries`, `OpenFrame` | Most negative percentage change of a single observation. |
|
@@ -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). |
|
@@ -1,15 +1,15 @@
|
|
1
1
|
openseries/__init__.py,sha256=W429Ojwa-wPgHV5PDAOQOBOAzPOR4wrVHRwdZQjRKcQ,41
|
2
|
-
openseries/_common_model.py,sha256=
|
2
|
+
openseries/_common_model.py,sha256=gHJfvxsOjrjGnuoTm62LRYho_VeEhRKmbY9xM6tiRUk,75497
|
3
3
|
openseries/_risk.py,sha256=4ckiA-0-uuoUOsuc_uElUA_2rLS_U3xJyiva2BX4W1s,3300
|
4
4
|
openseries/datefixer.py,sha256=ZOSPp4kLkMEsZv50GQaSo2vAEDVaXEr9iX3wTO7ZdB4,12378
|
5
5
|
openseries/frame.py,sha256=SH1sPUFoJS71o2uVJBLoDl3rSC8AP7wQZw3baMD9T4U,74019
|
6
|
-
openseries/load_plotly.py,sha256=
|
6
|
+
openseries/load_plotly.py,sha256=L4A3Fa5Jk47FY7pcg0NPZ0gm0JD_uCXjVlGC7FWVSJg,1856
|
7
7
|
openseries/plotly_captor_logo.json,sha256=F5nhMzEyxKywtjvQqMTKgKRCJQYMDIiBgDSxdte8Clo,178
|
8
8
|
openseries/plotly_layouts.json,sha256=ahx8-dL4_RPzvHtBOX0SiL0AH7xQJzNRSDhGrSmU-Og,1429
|
9
9
|
openseries/series.py,sha256=pIpiD3v8z7SyIppBatbsPuqOWCf3qI_us2145JnPUkQ,28313
|
10
10
|
openseries/simulation.py,sha256=VYxc-e5VSyC55DdfACpQen-necYbhso-6RMyOhYX-5k,13905
|
11
|
-
openseries/types.py,sha256=
|
12
|
-
openseries-1.5.
|
13
|
-
openseries-1.5.
|
14
|
-
openseries-1.5.
|
15
|
-
openseries-1.5.
|
11
|
+
openseries/types.py,sha256=yJmGZcBFwvMQQEaRVb0vhVMP463xu7MSydjWr12X38M,7689
|
12
|
+
openseries-1.5.5.dist-info/LICENSE.md,sha256=cPUabMxJ6-ziqzqS6aLGkR-ilIOKe_s3Qtyp0ioTmo0,1521
|
13
|
+
openseries-1.5.5.dist-info/METADATA,sha256=Z02qlvCsz6z2bJU9u0q66e3u0EPm6HPqr1AHJZoBH44,44222
|
14
|
+
openseries-1.5.5.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
15
|
+
openseries-1.5.5.dist-info/RECORD,,
|
File without changes
|
File without changes
|