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.
- {openseries-1.9.1 → openseries-1.9.2}/PKG-INFO +4 -4
- {openseries-1.9.1 → openseries-1.9.2}/README.md +2 -2
- {openseries-1.9.1 → openseries-1.9.2}/openseries/frame.py +17 -26
- {openseries-1.9.1 → openseries-1.9.2}/openseries/owntypes.py +0 -14
- {openseries-1.9.1 → openseries-1.9.2}/openseries/report.py +6 -2
- {openseries-1.9.1 → openseries-1.9.2}/pyproject.toml +6 -6
- {openseries-1.9.1 → openseries-1.9.2}/LICENSE.md +0 -0
- {openseries-1.9.1 → openseries-1.9.2}/openseries/__init__.py +0 -0
- {openseries-1.9.1 → openseries-1.9.2}/openseries/_common_model.py +0 -0
- {openseries-1.9.1 → openseries-1.9.2}/openseries/_risk.py +0 -0
- {openseries-1.9.1 → openseries-1.9.2}/openseries/datefixer.py +0 -0
- {openseries-1.9.1 → openseries-1.9.2}/openseries/load_plotly.py +0 -0
- {openseries-1.9.1 → openseries-1.9.2}/openseries/plotly_captor_logo.json +0 -0
- {openseries-1.9.1 → openseries-1.9.2}/openseries/plotly_layouts.json +0 -0
- {openseries-1.9.1 → openseries-1.9.2}/openseries/portfoliotools.py +0 -0
- {openseries-1.9.1 → openseries-1.9.2}/openseries/series.py +0 -0
- {openseries-1.9.1 → openseries-1.9.2}/openseries/simulation.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: openseries
|
3
|
-
Version: 1.9.
|
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
|

|
75
75
|
[](https://www.python.org/)
|
76
76
|
[](https://github.com/CaptorAB/openseries/actions/workflows/test.yml)
|
77
|
-
[](https://codecov.io/gh/CaptorAB/openseries/branch/master)
|
78
78
|
[](https://python-poetry.org/)
|
79
79
|
[](https://beta.ruff.rs/docs/)
|
80
80
|
[](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="
|
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
|

|
10
10
|
[](https://www.python.org/)
|
11
11
|
[](https://github.com/CaptorAB/openseries/actions/workflows/test.yml)
|
12
|
-
[](https://codecov.io/gh/CaptorAB/openseries/branch/master)
|
13
13
|
[](https://python-poetry.org/)
|
14
14
|
[](https://beta.ruff.rs/docs/)
|
15
15
|
[](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="
|
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
|
-
) ->
|
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
|
-
|
1259
|
-
|
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
|
-
|
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] =
|
1291
|
-
|
1292
|
-
|
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.
|
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
|
-
"
|
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
|
-
|
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
|
-
|
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
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|