openseries 1.9.1__tar.gz → 1.9.2__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.3
2
2
  Name: openseries
3
- Version: 1.9.1
3
+ Version: 1.9.2
4
4
  Summary: Tools for analyzing financial timeseries.
5
5
  License: # BSD 3-Clause License
6
6
 
@@ -55,8 +55,8 @@ Requires-Dist: plotly (>=5.18.0,<7.0.0)
55
55
  Requires-Dist: pydantic (>=2.5.2,<3.0.0)
56
56
  Requires-Dist: python-dateutil (>=2.8.2,<4.0.0)
57
57
  Requires-Dist: requests (>=2.20.0,<3.0.0)
58
+ Requires-Dist: scikit-learn (>=1.4.0,<2.0.0)
58
59
  Requires-Dist: scipy (>=1.11.4,<2.0.0)
59
- Requires-Dist: statsmodels (>=0.14.0,!=0.14.2,<1.0.0)
60
60
  Project-URL: Homepage, https://github.com/CaptorAB/openseries
61
61
  Project-URL: Issue Tracker, https://github.com/CaptorAB/openseries/issues
62
62
  Project-URL: Release Notes, https://github.com/CaptorAB/openseries/releases
@@ -74,7 +74,7 @@ Description-Content-Type: text/markdown
74
74
  ![Platform](https://img.shields.io/badge/platforms-Windows%20%7C%20macOS%20%7C%20Linux-blue)
75
75
  [![Python version](https://img.shields.io/pypi/pyversions/openseries.svg)](https://www.python.org/)
76
76
  [![GitHub Action Test Suite](https://github.com/CaptorAB/openseries/actions/workflows/test.yml/badge.svg)](https://github.com/CaptorAB/openseries/actions/workflows/test.yml)
77
- [![codecov](https://img.shields.io/codecov/c/github/CaptorAB/openseries/master)](https://codecov.io/gh/CaptorAB/openseries/branch/master)
77
+ [![codecov](https://img.shields.io/codecov/c/gh/CaptorAB/openseries?logo=codecov)](https://codecov.io/gh/CaptorAB/openseries/branch/master)
78
78
  [![Poetry](https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json)](https://python-poetry.org/)
79
79
  [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://beta.ruff.rs/docs/)
80
80
  [![GitHub License](https://img.shields.io/github/license/CaptorAB/openseries)](https://github.com/CaptorAB/openseries/blob/master/LICENSE.md)
@@ -119,7 +119,7 @@ _,_=series.plot_series()
119
119
 
120
120
  ### Sample output using the report_html() function:
121
121
 
122
- <img src="./captor_plot_image.png" alt="Two Assets Compared" width="1000" />
122
+ <img src="https://raw.githubusercontent.com/CaptorAB/openseries/master/captor_plot_image.png" alt="Two Assets Compared" width="1000" />
123
123
 
124
124
  ## Development Instructions
125
125
 
@@ -9,7 +9,7 @@
9
9
  ![Platform](https://img.shields.io/badge/platforms-Windows%20%7C%20macOS%20%7C%20Linux-blue)
10
10
  [![Python version](https://img.shields.io/pypi/pyversions/openseries.svg)](https://www.python.org/)
11
11
  [![GitHub Action Test Suite](https://github.com/CaptorAB/openseries/actions/workflows/test.yml/badge.svg)](https://github.com/CaptorAB/openseries/actions/workflows/test.yml)
12
- [![codecov](https://img.shields.io/codecov/c/github/CaptorAB/openseries/master)](https://codecov.io/gh/CaptorAB/openseries/branch/master)
12
+ [![codecov](https://img.shields.io/codecov/c/gh/CaptorAB/openseries?logo=codecov)](https://codecov.io/gh/CaptorAB/openseries/branch/master)
13
13
  [![Poetry](https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json)](https://python-poetry.org/)
14
14
  [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://beta.ruff.rs/docs/)
15
15
  [![GitHub License](https://img.shields.io/github/license/CaptorAB/openseries)](https://github.com/CaptorAB/openseries/blob/master/LICENSE.md)
@@ -54,7 +54,7 @@ _,_=series.plot_series()
54
54
 
55
55
  ### Sample output using the report_html() function:
56
56
 
57
- <img src="./captor_plot_image.png" alt="Two Assets Compared" width="1000" />
57
+ <img src="https://raw.githubusercontent.com/CaptorAB/openseries/master/captor_plot_image.png" alt="Two Assets Compared" width="1000" />
58
58
 
59
59
  ## Development Instructions
60
60
 
@@ -18,11 +18,6 @@ from typing import TYPE_CHECKING, cast
18
18
  if TYPE_CHECKING: # pragma: no cover
19
19
  import datetime as dt
20
20
 
21
- from statsmodels.regression.linear_model import ( # type: ignore[import-untyped]
22
- OLSResults,
23
- )
24
-
25
- import statsmodels.api as sm # type: ignore[import-untyped]
26
21
  from numpy import (
27
22
  array,
28
23
  cov,
@@ -44,6 +39,7 @@ from pandas import (
44
39
  merge,
45
40
  )
46
41
  from pydantic import field_validator
42
+ from sklearn.linear_model import LinearRegression
47
43
 
48
44
  from ._common_model import _CommonModel
49
45
  from .datefixer import _do_resample_to_business_period_ends
@@ -54,8 +50,6 @@ from .owntypes import (
54
50
  LiteralCaptureRatio,
55
51
  LiteralFrameProps,
56
52
  LiteralHowMerge,
57
- LiteralOlsFitCovType,
58
- LiteralOlsFitMethod,
59
53
  LiteralPandasReindexMethod,
60
54
  LiteralPortfolioWeightings,
61
55
  LiteralTrunc,
@@ -75,7 +69,7 @@ __all__ = ["OpenFrame"]
75
69
 
76
70
 
77
71
  # noinspection PyUnresolvedReferences,PyTypeChecker
78
- class OpenFrame(_CommonModel):
72
+ class OpenFrame(_CommonModel): # type: ignore[misc]
79
73
  """OpenFrame objects hold OpenTimeSeries in the list constituents.
80
74
 
81
75
  The intended use is to allow comparisons across these timeseries.
@@ -1229,16 +1223,13 @@ class OpenFrame(_CommonModel):
1229
1223
  self: Self,
1230
1224
  y_column: tuple[str, ValueType] | int,
1231
1225
  x_column: tuple[str, ValueType] | int,
1232
- method: LiteralOlsFitMethod = "pinv",
1233
- cov_type: LiteralOlsFitCovType = "nonrobust",
1234
1226
  *,
1235
1227
  fitted_series: bool = True,
1236
- ) -> OLSResults:
1228
+ ) -> dict[str, float]:
1237
1229
  """Ordinary Least Squares fit.
1238
1230
 
1239
1231
  Performs a linear regression and adds a new column with a fitted line
1240
1232
  using Ordinary Least Squares fit
1241
- https://www.statsmodels.org/stable/examples/notebooks/generated/ols.html.
1242
1233
 
1243
1234
  Parameters
1244
1235
  ----------
@@ -1246,50 +1237,50 @@ class OpenFrame(_CommonModel):
1246
1237
  The column level values of the dependent variable y
1247
1238
  x_column: tuple[str, ValueType] | int
1248
1239
  The column level values of the exogenous variable x
1249
- method: LiteralOlsFitMethod, default: pinv
1250
- Method to solve least squares problem
1251
- cov_type: LiteralOlsFitCovType, default: nonrobust
1252
- Covariance estimator
1253
1240
  fitted_series: bool, default: True
1254
1241
  If True the fit is added as a new column in the .tsdf Pandas.DataFrame
1255
1242
 
1256
1243
  Returns:
1257
1244
  -------
1258
- OLSResults
1259
- The Statsmodels regression output
1245
+ dict[str, float]
1246
+ A dictionary with the coefficient, intercept and rsquared outputs.
1260
1247
 
1261
1248
  """
1262
1249
  msg = "y_column should be a tuple[str, ValueType] or an integer."
1263
1250
  if isinstance(y_column, tuple):
1264
- y_value = self.tsdf.loc[:, y_column]
1251
+ y_value = self.tsdf.loc[:, y_column].to_numpy()
1265
1252
  y_label = cast(
1266
1253
  "tuple[str, str]",
1267
1254
  self.tsdf.loc[:, y_column].name,
1268
1255
  )[0]
1269
1256
  elif isinstance(y_column, int):
1270
- y_value = self.tsdf.iloc[:, y_column]
1257
+ y_value = self.tsdf.iloc[:, y_column].to_numpy()
1271
1258
  y_label = cast("tuple[str, str]", self.tsdf.iloc[:, y_column].name)[0]
1272
1259
  else:
1273
1260
  raise TypeError(msg)
1274
1261
 
1275
1262
  msg = "x_column should be a tuple[str, ValueType] or an integer."
1276
1263
  if isinstance(x_column, tuple):
1277
- x_value = self.tsdf.loc[:, x_column]
1264
+ x_value = self.tsdf.loc[:, x_column].to_numpy().reshape(-1, 1)
1278
1265
  x_label = cast(
1279
1266
  "tuple[str, str]",
1280
1267
  self.tsdf.loc[:, x_column].name,
1281
1268
  )[0]
1282
1269
  elif isinstance(x_column, int):
1283
- x_value = self.tsdf.iloc[:, x_column]
1270
+ x_value = self.tsdf.iloc[:, x_column].to_numpy().reshape(-1, 1)
1284
1271
  x_label = cast("tuple[str, str]", self.tsdf.iloc[:, x_column].name)[0]
1285
1272
  else:
1286
1273
  raise TypeError(msg)
1287
1274
 
1288
- results = sm.OLS(y_value, x_value).fit(method=method, cov_type=cov_type)
1275
+ model = LinearRegression(fit_intercept=True)
1276
+ model.fit(x_value, y_value)
1289
1277
  if fitted_series:
1290
- self.tsdf[y_label, x_label] = results.predict(x_value)
1291
-
1292
- return cast("OLSResults", results)
1278
+ self.tsdf[y_label, x_label] = model.predict(x_value)
1279
+ return {
1280
+ "coefficient": model.coef_[0],
1281
+ "intercept": model.intercept_,
1282
+ "rsquared": model.score(x_value, y_value),
1283
+ }
1293
1284
 
1294
1285
  def jensen_alpha(
1295
1286
  self: Self,
@@ -141,21 +141,7 @@ LiteralPlotlyHistogramHistNorm = Literal[
141
141
  "density",
142
142
  "probability density",
143
143
  ]
144
- LiteralOlsFitMethod = Literal["pinv", "qr"]
145
144
  LiteralPortfolioWeightings = Literal["eq_weights", "inv_vol"]
146
- LiteralOlsFitCovType = Literal[
147
- "nonrobust",
148
- "fixed scale",
149
- "HC0",
150
- "HC1",
151
- "HC2",
152
- "HC3",
153
- "HAC",
154
- "hac-panel",
155
- "hac-groupsum",
156
- "cluster",
157
- ]
158
-
159
145
  LiteralMinimizeMethods = Literal[
160
146
  "SLSQP",
161
147
  "Nelder-Mead",
@@ -26,7 +26,7 @@ if TYPE_CHECKING: # pragma: no cover
26
26
  from .owntypes import LiteralPlotlyJSlib, LiteralPlotlyOutput
27
27
 
28
28
 
29
- from pandas import DataFrame, Series, concat
29
+ from pandas import DataFrame, Series, Timestamp, concat
30
30
  from plotly.io import to_html
31
31
  from plotly.offline import plot
32
32
  from plotly.subplots import make_subplots
@@ -73,8 +73,12 @@ def calendar_period_returns(
73
73
  copied.value_to_ret()
74
74
  cldr = copied.tsdf.iloc[1:].copy()
75
75
  if relabel:
76
- if freq == "BYE":
76
+ if freq.upper() == "BYE":
77
77
  cldr.index = [d.year for d in cldr.index]
78
+ elif freq.upper() == "BQE":
79
+ cldr.index = [
80
+ Timestamp(d).to_period("Q").strftime("Q%q %Y") for d in cldr.index
81
+ ]
78
82
  else:
79
83
  cldr.index = [d.strftime("%b %y") for d in cldr.index]
80
84
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "openseries"
3
- version = "1.9.1"
3
+ version = "1.9.2"
4
4
  description = "Tools for analyzing financial timeseries."
5
5
  authors = [
6
6
  { name = "Martin Karrin", email = "martin.karrin@captor.se" },
@@ -50,7 +50,7 @@ dependencies = [
50
50
  "python-dateutil (>=2.8.2,<4.0.0)",
51
51
  "requests (>=2.20.0,<3.0.0)",
52
52
  "scipy (>=1.11.4,<2.0.0)",
53
- "statsmodels (>=0.14.0,!=0.14.2,<1.0.0)"
53
+ "scikit-learn (>=1.4.0,<2.0.0)"
54
54
  ]
55
55
 
56
56
  [project.urls]
@@ -61,12 +61,13 @@ dependencies = [
61
61
 
62
62
  [tool.poetry.group.dev.dependencies]
63
63
  black = ">=24.4.2,<27.0.0"
64
- coverage = ">=7.2.7,<9.0.0"
65
- mypy = "1.16.0"
64
+ mypy = "1.16.1"
66
65
  pandas-stubs = ">=2.1.2,<3.0.0"
67
66
  pre-commit = ">=3.7.1,<6.0.0"
68
67
  pytest = ">=8.2.2,<9.0.0"
69
- ruff = "0.11.13"
68
+ pytest-cov = ">=5.0.0,<7.0.0"
69
+ pytest-xdist = ">=3.3.1,<5.0.0"
70
+ ruff = "0.12.1"
70
71
  types-openpyxl = ">=3.1.2,<5.0.0"
71
72
  types-python-dateutil = ">=2.8.2,<4.0.0"
72
73
  types-requests = ">=2.20.0,<3.0.0"
@@ -78,7 +79,6 @@ build-backend = "poetry.core.masonry.api"
78
79
  [tool.coverage.run]
79
80
  branch = true
80
81
  omit = ["venv/*", "tests/*", "**/__init__.py"]
81
- include = ["openseries/*"]
82
82
 
83
83
  [tool.coverage.report]
84
84
  omit = ["**/__init__.py"]
File without changes