openseries 1.5.3__tar.gz → 1.5.5__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: openseries
3
- Version: 1.5.3
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
  [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://beta.ruff.rs/docs/)
54
54
  [![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
55
55
 
56
- `openseries` is a project with tools to analyse financial timeseries of a single
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). |
@@ -17,7 +17,7 @@ width="81" height="100" align="left" float="right"/><br/>
17
17
  [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://beta.ruff.rs/docs/)
18
18
  [![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
19
19
 
20
- `openseries` is a project with tools to analyse financial timeseries of a single
20
+ This is a project with tools to analyze financial timeseries of a single
21
21
  asset or a group of assets. It is solely made for daily or less frequent data.
22
22
 
23
23
  <span style="font-size:2em;">[CHANGELOG](https://github.com/CaptorAB/openseries/blob/master/CHANGELOG.md)</span>
@@ -293,6 +293,7 @@ make lint
293
293
  | `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. |
294
294
  | `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. |
295
295
  | `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. |
296
+ | `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. |
296
297
  | `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. |
297
298
  | `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. |
298
299
  | `worst` | `float`, `pandas.Series` | `OpenTimeSeries`, `OpenFrame` | Most negative percentage change of a single observation. |
@@ -319,6 +320,7 @@ properties for subset periods._
319
320
  | `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. |
320
321
  | `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. |
321
322
  | `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. |
323
+ | `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. |
322
324
  | `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. |
323
325
  | `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. |
324
326
  | `worst_func` | `float`, `pandas.Series` | `OpenTimeSeries`, `OpenFrame` | Most negative percentage change for a given number of observations (default=1). |
@@ -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 Drawdown in cal yr",
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 raw original data of the series
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 Path.open(
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 Drawdown",
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 Share",
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,
@@ -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 requests.exceptions.ConnectionError:
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:
@@ -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
  [tool.poetry]
2
2
  name = "openseries"
3
- version = "1.5.3"
3
+ version = "1.5.5"
4
4
  description = "Tools for analyzing financial timeseries."
5
5
  authors = ["Martin Karrin <martin.karrin@captor.se>"]
6
6
  repository = "https://github.com/CaptorAB/openseries"
@@ -47,19 +47,19 @@ scipy = ">=1.11.4,<2.0.0"
47
47
  statsmodels = ">=0.14.0,<1.0.0"
48
48
 
49
49
  [tool.poetry.group.dev.dependencies]
50
- coverage = "^7.5.0"
50
+ coverage = "^7.5.1"
51
51
  coverage-badge = "^1.1.1"
52
52
  mypy = "^1.10.0"
53
- pandas-stubs = "^2.2.1.240316"
54
- pre-commit = "^3.7.0"
55
- pytest = "^8.2.0"
56
- ruff = "^0.4.2"
53
+ pandas-stubs = "^2.2.2.240514"
54
+ pre-commit = "^3.7.1"
55
+ pytest = "^8.2.1"
56
+ ruff = "^0.4.5"
57
57
  types-openpyxl = "^3.1.0.20240428"
58
58
  types-python-dateutil = "^2.9.0.20240316"
59
- types-requests = "^2.31.0.20240406"
59
+ types-requests = "^2.32.0.20240523"
60
60
 
61
61
  [build-system]
62
- requires = ["poetry-core>=1.8.2"]
62
+ requires = ["poetry-core>=1.8.3"]
63
63
  build-backend = "poetry.core.masonry.api"
64
64
 
65
65
  [tool.pytest.ini_options]
File without changes