openseries 1.5.0__py3-none-any.whl → 1.5.1__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/_risk.py CHANGED
@@ -124,9 +124,6 @@ def _calc_inv_vol_weights(returns: DataFrame) -> NDArray[float64]:
124
124
  """
125
125
  Calculate weights proportional to inverse volatility.
126
126
 
127
- Source: https://github.com/pmorissette/ffn.
128
- Function copied here because of FutureWarning from pandas ^2.1.0
129
-
130
127
  Parameters
131
128
  ----------
132
129
  returns: pandas.DataFrame
openseries/frame.py CHANGED
@@ -12,10 +12,6 @@ from pathlib import Path
12
12
  from typing import Callable, Optional, Union, cast
13
13
 
14
14
  import statsmodels.api as sm # type: ignore[import-untyped,unused-ignore]
15
- from ffn.core import ( # type: ignore[import-untyped,unused-ignore]
16
- calc_erc_weights,
17
- calc_mean_var_weights,
18
- )
19
15
  from numpy import (
20
16
  append,
21
17
  array,
@@ -70,7 +66,6 @@ from openseries.types import (
70
66
  DaysInYearType,
71
67
  LiteralBizDayFreq,
72
68
  LiteralCaptureRatio,
73
- LiteralCovMethod,
74
69
  LiteralFrameProps,
75
70
  LiteralHowMerge,
76
71
  LiteralLinePlotMode,
@@ -80,13 +75,13 @@ from openseries.types import (
80
75
  LiteralPlotlyJSlib,
81
76
  LiteralPlotlyOutput,
82
77
  LiteralPortfolioWeightings,
83
- LiteralRiskParityMethod,
84
78
  LiteralTrunc,
85
79
  OpenFramePropertiesList,
86
80
  ValueType,
87
81
  )
88
82
 
89
83
 
84
+ # noinspection PyUnresolvedReferences
90
85
  class OpenFrame(_CommonModel):
91
86
 
92
87
  """
@@ -249,7 +244,7 @@ class OpenFrame(_CommonModel):
249
244
  prop_list = [
250
245
  getattr(self, x) for x in OpenFramePropertiesList.allowed_strings
251
246
  ]
252
- return concat(prop_list, axis="columns").T
247
+ return cast(DataFrame, concat(prop_list, axis="columns").T)
253
248
 
254
249
  @property
255
250
  def lengths_of_items(self: Self) -> Series[int]:
@@ -666,6 +661,7 @@ class OpenFrame(_CommonModel):
666
661
 
667
662
  """
668
663
  self.constituents += [new_series]
664
+ # noinspection PyUnreachableCode
669
665
  self.tsdf = concat([self.tsdf, new_series.tsdf], axis="columns", sort=True)
670
666
  return self
671
667
 
@@ -1476,15 +1472,6 @@ class OpenFrame(_CommonModel):
1476
1472
  self: Self,
1477
1473
  name: str,
1478
1474
  weight_strat: Optional[LiteralPortfolioWeightings] = None,
1479
- initial_weights: Optional[list[float]] = None,
1480
- risk_weights: Optional[list[float]] = None,
1481
- risk_parity_method: LiteralRiskParityMethod = "ccd",
1482
- maximum_iterations: int = 100,
1483
- tolerance: float = 1e-8,
1484
- weight_bounds: tuple[float, float] = (0.0, 1.0),
1485
- riskfree: float = 0.0,
1486
- covar_method: LiteralCovMethod = "ledoit-wolf",
1487
- options: Optional[dict[str, int]] = None,
1488
1475
  ) -> DataFrame:
1489
1476
  """
1490
1477
  Calculate a basket timeseries based on the supplied weights.
@@ -1494,25 +1481,7 @@ class OpenFrame(_CommonModel):
1494
1481
  name: str
1495
1482
  Name of the basket timeseries
1496
1483
  weight_strat: LiteralPortfolioWeightings, optional
1497
- weight calculation from https://github.com/pmorissette/ffn
1498
- initial_weights: list[float], optional
1499
- Starting asset weights, default inverse volatility
1500
- risk_weights: list[float], optional
1501
- Risk target weights, default equal weight
1502
- risk_parity_method: LiteralRiskParityMethod, default: ccd
1503
- Risk parity estimation method
1504
- maximum_iterations: int, default: 100
1505
- Maximum iterations in iterative solutions
1506
- tolerance: float, default: 1e-8
1507
- Tolerance level in iterative solutions
1508
- weight_bounds: tuple[float, float], default: (0.0, 1.0)
1509
- Weigh limits for optimization
1510
- riskfree: float, default: 0.0
1511
- Risk-free rate used in utility calculation
1512
- covar_method: LiteralCovMethod, default: ledoit-wolf
1513
- Covariance matrix estimation method
1514
- options: dict, optional
1515
- options for minimizing, e.g. {'maxiter': 10000 }
1484
+ weight calculation strategies
1516
1485
 
1517
1486
  Returns
1518
1487
  -------
@@ -1538,32 +1507,9 @@ class OpenFrame(_CommonModel):
1538
1507
  if weight_strat:
1539
1508
  if weight_strat == "eq_weights":
1540
1509
  self.weights = [1.0 / self.item_count] * self.item_count
1541
- elif weight_strat == "eq_risk":
1542
- weight_calc = list(
1543
- calc_erc_weights(
1544
- returns=dframe,
1545
- initial_weights=initial_weights,
1546
- risk_weights=risk_weights,
1547
- risk_parity_method=risk_parity_method,
1548
- maximum_iterations=maximum_iterations,
1549
- tolerance=tolerance,
1550
- ),
1551
- )
1552
- self.weights = weight_calc
1553
1510
  elif weight_strat == "inv_vol":
1554
1511
  weight_calc = list(_calc_inv_vol_weights(returns=dframe))
1555
1512
  self.weights = weight_calc
1556
- elif weight_strat == "mean_var":
1557
- weight_calc = list(
1558
- calc_mean_var_weights(
1559
- returns=dframe,
1560
- weight_bounds=weight_bounds,
1561
- rf=riskfree,
1562
- covar_method=covar_method,
1563
- options=options,
1564
- ),
1565
- )
1566
- self.weights = weight_calc
1567
1513
  else:
1568
1514
  msg = "Weight strategy not implemented"
1569
1515
  raise NotImplementedError(msg)
@@ -1809,9 +1755,12 @@ def simulate_portfolios(
1809
1755
 
1810
1756
  sharpe_arr[x] = ret_arr[x] / vol_arr[x]
1811
1757
 
1812
- simdf = DataFrame({"stdev": vol_arr, "ret": ret_arr, "sharpe": sharpe_arr})
1758
+ # noinspection PyUnreachableCode
1813
1759
  simdf = concat(
1814
- [simdf, DataFrame(all_weights, columns=simframe.columns_lvl_zero)],
1760
+ [
1761
+ DataFrame({"stdev": vol_arr, "ret": ret_arr, "sharpe": sharpe_arr}),
1762
+ DataFrame(all_weights, columns=simframe.columns_lvl_zero),
1763
+ ],
1815
1764
  axis="columns",
1816
1765
  )
1817
1766
  simdf = simdf.replace([inf, -inf], nan)
@@ -1878,9 +1827,9 @@ def efficient_frontier( # noqa: C901
1878
1827
  return cast(float64, npsum(weights) - 1)
1879
1828
 
1880
1829
  def _get_ret_vol_sr(
1881
- lg_ret: DataFrame,
1882
- weights: NDArray[float64],
1883
- per_in_yr: float,
1830
+ lg_ret: DataFrame,
1831
+ weights: NDArray[float64],
1832
+ per_in_yr: float,
1884
1833
  ) -> NDArray[float64]:
1885
1834
  ret = npsum(lg_ret.mean() * weights) * per_in_yr
1886
1835
  volatility = sqrt(dot(weights.T, dot(lg_ret.cov() * per_in_yr, weights)))
@@ -1888,10 +1837,10 @@ def efficient_frontier( # noqa: C901
1888
1837
  return cast(NDArray[float64], array([ret, volatility, sr]))
1889
1838
 
1890
1839
  def _diff_return(
1891
- lg_ret: DataFrame,
1892
- weights: NDArray[float64],
1893
- per_in_yr: float,
1894
- poss_return: float,
1840
+ lg_ret: DataFrame,
1841
+ weights: NDArray[float64],
1842
+ per_in_yr: float,
1843
+ poss_return: float,
1895
1844
  ) -> float64:
1896
1845
  return cast(
1897
1846
  float64,
@@ -1972,9 +1921,12 @@ def efficient_frontier( # noqa: C901
1972
1921
  frontier_x.append(result["fun"])
1973
1922
  frontier_weights.append(result["x"])
1974
1923
 
1975
- line_df = DataFrame(data=frontier_weights, columns=eframe.columns_lvl_zero)
1924
+ # noinspection PyUnreachableCode
1976
1925
  line_df = concat(
1977
- [line_df, DataFrame({"stdev": frontier_x, "ret": frontier_y})],
1926
+ [
1927
+ DataFrame(data=frontier_weights, columns=eframe.columns_lvl_zero),
1928
+ DataFrame({"stdev": frontier_x, "ret": frontier_y}),
1929
+ ],
1978
1930
  axis="columns",
1979
1931
  )
1980
1932
  line_df["sharpe"] = line_df.ret / line_df.stdev
openseries/series.py CHANGED
@@ -50,6 +50,7 @@ from openseries.types import (
50
50
  TypeOpenTimeSeries = TypeVar("TypeOpenTimeSeries", bound="OpenTimeSeries")
51
51
 
52
52
 
53
+ # noinspection PyUnresolvedReferences
53
54
  class OpenTimeSeries(_CommonModel):
54
55
 
55
56
  """
openseries/types.py CHANGED
@@ -138,8 +138,6 @@ LiteralPlotlyOutput = Literal["file", "div"]
138
138
  LiteralPlotlyJSlib = Literal[True, False, "cdn"]
139
139
  LiteralOlsFitMethod = Literal["pinv", "qr"]
140
140
  LiteralPortfolioWeightings = Literal["eq_weights", "eq_risk", "inv_vol", "mean_var"]
141
- LiteralCovMethod = Literal["ledoit-wolf", "standard"]
142
- LiteralRiskParityMethod = Literal["ccd", "slsqp"]
143
141
  LiteralOlsFitCovType = Literal[
144
142
  "nonrobust",
145
143
  "fixed scale",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: openseries
3
- Version: 1.5.0
3
+ Version: 1.5.1
4
4
  Summary: Package for analyzing financial timeseries.
5
5
  Home-page: https://github.com/CaptorAB/OpenSeries
6
6
  License: BSD-3-Clause
@@ -20,15 +20,15 @@ Classifier: Programming Language :: Python :: 3.10
20
20
  Classifier: Programming Language :: Python :: 3.11
21
21
  Classifier: Programming Language :: Python :: 3.12
22
22
  Classifier: Topic :: Office/Business :: Financial :: Investment
23
- Requires-Dist: ffn (>=1.0.0,<2.0.0)
24
23
  Requires-Dist: holidays (>=0.30,<1.0)
25
24
  Requires-Dist: numpy (>=1.23.2,<=2.0.0)
26
25
  Requires-Dist: openpyxl (>=3.1.2,<4.0.0)
27
26
  Requires-Dist: pandas (>=2.1.2,<3.0.0)
28
27
  Requires-Dist: plotly (>=5.18.0,<6.0.0)
29
- Requires-Dist: pyarrow (>=14.0.2,<15.0.1)
28
+ Requires-Dist: pyarrow (>=14.0.2,<16.0.0)
30
29
  Requires-Dist: pydantic (>=2.5.2,<3.0.0)
31
30
  Requires-Dist: python-dateutil (>=2.8.2,<3.0.0)
31
+ Requires-Dist: requests (>=2.20.0,<3.0.0)
32
32
  Requires-Dist: scipy (>=1.11.4,<2.0.0)
33
33
  Requires-Dist: statsmodels (>=0.14.0,<1.0.0)
34
34
  Project-URL: Repository, https://github.com/CaptorAB/OpenSeries
@@ -272,24 +272,24 @@ make lint
272
272
 
273
273
  ### Methods that apply only to the [OpenFrame](https://github.com/CaptorAB/OpenSeries/blob/master/openseries/frame.py) class.
274
274
 
275
- | Method | Applies to | Description |
276
- |:------------------------|:------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
277
- | `merge_series` | `OpenFrame` | Merges the Pandas Dataframes of the constituent OpenTimeSeries. |
278
- | `trunc_frame` | `OpenFrame` | Truncates the OpenFrame to a common period. |
279
- | `add_timeseries` | `OpenFrame` | Adds a given OpenTimeSeries to the OpenFrame. |
280
- | `delete_timeseries` | `OpenFrame` | Deletes an OpenTimeSeries from the OpenFrame. |
281
- | `relative` | `OpenFrame` | Calculates a new series that is the relative performance of two others. |
282
- | `make_portfolio` | `OpenFrame` | Calculates a portfolio timeseries based on the series and weights. Weights can be provided as a list, or a weight strategy can be chosen from *equal weights*, *equal risk*, *inverted volatility* or *minimum variance* as defined in the [ffn](https://github.com/pmorissette/ffn) package. |
283
- | `ord_least_squares_fit` | `OpenFrame` | Performs a regression and an [Ordinary Least Squares](https://www.statsmodels.org/stable/examples/notebooks/generated/ols.html) fit. |
284
- | `beta` | `OpenFrame` | Calculates [Beta](https://www.investopedia.com/terms/b/beta.asp) of an asset relative a market. |
285
- | `jensen_alpha` | `OpenFrame` | Calculates [Jensen's Alpha](https://www.investopedia.com/terms/j/jensensmeasure.asp) of an asset relative a market. |
286
- | `tracking_error_func` | `OpenFrame` | Calculates the [tracking errors](https://www.investopedia.com/terms/t/trackingerror.asp) relative to a selected series in the OpenFrame. |
287
- | `info_ratio_func` | `OpenFrame` | Calculates the [information ratios](https://www.investopedia.com/terms/i/informationratio.asp) relative to a selected series in the OpenFrame. |
288
- | `capture_ratio_func` | `OpenFrame` | Calculates up, down and up/down [capture ratios](https://www.investopedia.com/terms/d/down-market-capture-ratio.asp) relative to a selected series. |
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
- | `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
- | `rolling_corr` | `OpenFrame` | Calculates and adds a series of rolling [correlations](https://www.investopedia.com/terms/c/correlation.asp) between two other series. |
292
- | `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). |
275
+ | Method | Applies to | Description |
276
+ |:------------------------|:------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
277
+ | `merge_series` | `OpenFrame` | Merges the Pandas Dataframes of the constituent OpenTimeSeries. |
278
+ | `trunc_frame` | `OpenFrame` | Truncates the OpenFrame to a common period. |
279
+ | `add_timeseries` | `OpenFrame` | Adds a given OpenTimeSeries to the OpenFrame. |
280
+ | `delete_timeseries` | `OpenFrame` | Deletes an OpenTimeSeries from the OpenFrame. |
281
+ | `relative` | `OpenFrame` | Calculates a new series that is the relative performance of two others. |
282
+ | `make_portfolio` | `OpenFrame` | Calculates a portfolio timeseries based on the series and weights. Weights can be provided as a list, or a weight strategy can be set as *equal weights* or *inverted volatility*. |
283
+ | `ord_least_squares_fit` | `OpenFrame` | Performs a regression and an [Ordinary Least Squares](https://www.statsmodels.org/stable/examples/notebooks/generated/ols.html) fit. |
284
+ | `beta` | `OpenFrame` | Calculates [Beta](https://www.investopedia.com/terms/b/beta.asp) of an asset relative a market. |
285
+ | `jensen_alpha` | `OpenFrame` | Calculates [Jensen's Alpha](https://www.investopedia.com/terms/j/jensensmeasure.asp) of an asset relative a market. |
286
+ | `tracking_error_func` | `OpenFrame` | Calculates the [tracking errors](https://www.investopedia.com/terms/t/trackingerror.asp) relative to a selected series in the OpenFrame. |
287
+ | `info_ratio_func` | `OpenFrame` | Calculates the [information ratios](https://www.investopedia.com/terms/i/informationratio.asp) relative to a selected series in the OpenFrame. |
288
+ | `capture_ratio_func` | `OpenFrame` | Calculates up, down and up/down [capture ratios](https://www.investopedia.com/terms/d/down-market-capture-ratio.asp) relative to a selected series. |
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
+ | `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
+ | `rolling_corr` | `OpenFrame` | Calculates and adds a series of rolling [correlations](https://www.investopedia.com/terms/c/correlation.asp) between two other series. |
292
+ | `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
293
 
294
294
  ### 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.
295
295
 
@@ -1,15 +1,15 @@
1
1
  openseries/__init__.py,sha256=hA7I5IFk88EnX6eyBbI1KLT_FGcmPIKF49xa5g3T8Yg,41
2
2
  openseries/_common_model.py,sha256=whzIHppEGjXqv2C5ZBg7c-QTCC6dHWBjNKX40WV_c6g,72469
3
- openseries/_risk.py,sha256=u5-gP673_XVtCB0UAYoE1Ikw0gUjIaVgnwj142rqk1Q,3417
3
+ openseries/_risk.py,sha256=JnwAklqs2G3YIp9KTNKbumqs4VgfFIk-eFs0dZ-_jCY,3299
4
4
  openseries/datefixer.py,sha256=_HNiPR6S3agwOAk8gl3wIdegR6uDbh-00J1Zgo4GMl8,12423
5
- openseries/frame.py,sha256=9KagSKuLd4jtB1rzk1ACq4fiZGIDr_AMPRsUaFe4YCk,76093
5
+ openseries/frame.py,sha256=en_GL0_l9OHsZk6AmYin5Pip7geLyTeLZNAZqIR4xcI,73772
6
6
  openseries/load_plotly.py,sha256=kIjvJ2H1sIXWsjd-mZclLvj7ebh-4Hdb1dwB2gR9b-Y,1807
7
7
  openseries/plotly_captor_logo.json,sha256=F5nhMzEyxKywtjvQqMTKgKRCJQYMDIiBgDSxdte8Clo,178
8
8
  openseries/plotly_layouts.json,sha256=ahx8-dL4_RPzvHtBOX0SiL0AH7xQJzNRSDhGrSmU-Og,1429
9
- openseries/series.py,sha256=ix-kMUy8H1Kuz7ZeqZ_wSOLCq-_zjm2hrJ63Ytadijc,28274
9
+ openseries/series.py,sha256=jHbJkzFUeGokUJZ1Md4Hx1keSwpNMjPq1r_FDCputIE,28312
10
10
  openseries/simulation.py,sha256=_1cYO4VnlRI6khk6Th8ziN5Toz1iry0jFKICHQub3V0,13550
11
- openseries/types.py,sha256=6Sq8tKH5-tIFq7C8K594vT4yZrLCNZ8H6vc6TGPk0r8,7764
12
- openseries-1.5.0.dist-info/LICENSE.md,sha256=cPUabMxJ6-ziqzqS6aLGkR-ilIOKe_s3Qtyp0ioTmo0,1521
13
- openseries-1.5.0.dist-info/METADATA,sha256=geEiuVXcM-jKy_2uHbEkgo8f4wbfm9_eO7CiRSP_zNQ,45585
14
- openseries-1.5.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
15
- openseries-1.5.0.dist-info/RECORD,,
11
+ openseries/types.py,sha256=Qw-ny6IZtdMeuHJF6FvIE0B2stnN3sdqq9fySIKUWK4,7660
12
+ openseries-1.5.1.dist-info/LICENSE.md,sha256=cPUabMxJ6-ziqzqS6aLGkR-ilIOKe_s3Qtyp0ioTmo0,1521
13
+ openseries-1.5.1.dist-info/METADATA,sha256=N1NAZ6l6V2pfc-EZAzF1kVTaLNAg7OrfVr1juoaUPMA,43665
14
+ openseries-1.5.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
15
+ openseries-1.5.1.dist-info/RECORD,,