openseries 1.7.1__tar.gz → 1.7.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.7.1 → openseries-1.7.2}/PKG-INFO +2 -3
- {openseries-1.7.1 → openseries-1.7.2}/README.md +0 -1
- {openseries-1.7.1 → openseries-1.7.2}/openseries/_common_model.py +4 -12
- {openseries-1.7.1 → openseries-1.7.2}/openseries/datefixer.py +4 -10
- {openseries-1.7.1 → openseries-1.7.2}/openseries/frame.py +36 -59
- {openseries-1.7.1 → openseries-1.7.2}/openseries/portfoliotools.py +4 -7
- {openseries-1.7.1 → openseries-1.7.2}/openseries/series.py +9 -9
- {openseries-1.7.1 → openseries-1.7.2}/openseries/types.py +2 -6
- {openseries-1.7.1 → openseries-1.7.2}/pyproject.toml +4 -4
- {openseries-1.7.1 → openseries-1.7.2}/LICENSE.md +0 -0
- {openseries-1.7.1 → openseries-1.7.2}/openseries/__init__.py +0 -0
- {openseries-1.7.1 → openseries-1.7.2}/openseries/_risk.py +0 -0
- {openseries-1.7.1 → openseries-1.7.2}/openseries/load_plotly.py +0 -0
- {openseries-1.7.1 → openseries-1.7.2}/openseries/plotly_captor_logo.json +0 -0
- {openseries-1.7.1 → openseries-1.7.2}/openseries/plotly_layouts.json +0 -0
- {openseries-1.7.1 → openseries-1.7.2}/openseries/simulation.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: openseries
|
3
|
-
Version: 1.7.
|
3
|
+
Version: 1.7.2
|
4
4
|
Summary: Tools for analyzing financial timeseries.
|
5
5
|
Home-page: https://github.com/CaptorAB/openseries
|
6
6
|
License: BSD-3-Clause
|
@@ -28,7 +28,7 @@ Requires-Dist: pyarrow (>=14.0.2,<18.0.0)
|
|
28
28
|
Requires-Dist: pydantic (>=2.5.2,<3.0.0)
|
29
29
|
Requires-Dist: python-dateutil (>=2.8.2,<3.0.0)
|
30
30
|
Requires-Dist: requests (>=2.20.0,<3.0.0)
|
31
|
-
Requires-Dist: scipy (>=1.11.4,<
|
31
|
+
Requires-Dist: scipy (>=1.11.4,<1.14.1)
|
32
32
|
Requires-Dist: statsmodels (>=0.14.0,<1.0.0)
|
33
33
|
Project-URL: Repository, https://github.com/CaptorAB/openseries
|
34
34
|
Description-Content-Type: text/markdown
|
@@ -261,7 +261,6 @@ make lint
|
|
261
261
|
|
262
262
|
| Method | Applies to | Description |
|
263
263
|
|:-------------------------|:-----------------|:-----------------------------------------------------------------------------------------------------------------------------------------------|
|
264
|
-
| `setup_class` | `OpenTimeSeries` | Class method that defines the `domestic` home currency and the `countries` home countries attributes. |
|
265
264
|
| `pandas_df` | `OpenTimeSeries` | Method to create the `tsdf` pandas.DataFrame from the `dates` and `values`. |
|
266
265
|
| `set_new_label` | `OpenTimeSeries` | Method to change the pandas.DataFrame column MultiIndex. |
|
267
266
|
| `running_adjustment` | `OpenTimeSeries` | Adjusts the series performance with a `float` factor. |
|
@@ -226,7 +226,6 @@ make lint
|
|
226
226
|
|
227
227
|
| Method | Applies to | Description |
|
228
228
|
|:-------------------------|:-----------------|:-----------------------------------------------------------------------------------------------------------------------------------------------|
|
229
|
-
| `setup_class` | `OpenTimeSeries` | Class method that defines the `domestic` home currency and the `countries` home countries attributes. |
|
230
229
|
| `pandas_df` | `OpenTimeSeries` | Method to create the `tsdf` pandas.DataFrame from the `dates` and `values`. |
|
231
230
|
| `set_new_label` | `OpenTimeSeries` | Method to change the pandas.DataFrame column MultiIndex. |
|
232
231
|
| `running_adjustment` | `OpenTimeSeries` | Adjusts the series performance with a `float` factor. |
|
@@ -484,9 +484,7 @@ class _CommonModel(BaseModel):
|
|
484
484
|
"Argument months_offset implies start"
|
485
485
|
"date before first date in series."
|
486
486
|
)
|
487
|
-
raise ValueError(
|
488
|
-
msg,
|
489
|
-
)
|
487
|
+
raise ValueError(msg)
|
490
488
|
later = self.last_idx
|
491
489
|
else:
|
492
490
|
if from_dt is not None:
|
@@ -785,9 +783,7 @@ class _CommonModel(BaseModel):
|
|
785
783
|
if labels:
|
786
784
|
if len(labels) != self.tsdf.shape[1]:
|
787
785
|
msg = "Must provide same number of labels as items in frame."
|
788
|
-
raise ValueError(
|
789
|
-
msg,
|
790
|
-
)
|
786
|
+
raise ValueError(msg)
|
791
787
|
else:
|
792
788
|
labels = list(self.tsdf.columns.get_level_values(0))
|
793
789
|
|
@@ -902,9 +898,7 @@ class _CommonModel(BaseModel):
|
|
902
898
|
if labels:
|
903
899
|
if len(labels) != self.tsdf.shape[1]:
|
904
900
|
msg = "Must provide same number of labels as items in frame."
|
905
|
-
raise ValueError(
|
906
|
-
msg,
|
907
|
-
)
|
901
|
+
raise ValueError(msg)
|
908
902
|
else:
|
909
903
|
labels = list(self.tsdf.columns.get_level_values(0))
|
910
904
|
|
@@ -1932,9 +1926,7 @@ class _CommonModel(BaseModel):
|
|
1932
1926
|
"Simple return cannot be calculated due to "
|
1933
1927
|
f"an initial value being zero. ({self.tsdf.head(3)})"
|
1934
1928
|
)
|
1935
|
-
raise ValueError(
|
1936
|
-
msg,
|
1937
|
-
)
|
1929
|
+
raise ValueError(msg)
|
1938
1930
|
|
1939
1931
|
result = self.tsdf.loc[later] / self.tsdf.loc[earlier] - 1
|
1940
1932
|
|
@@ -92,9 +92,7 @@ def holiday_calendar(
|
|
92
92
|
"Argument countries must be a string country code or "
|
93
93
|
"a list of string country codes according to ISO 3166-1 alpha-2."
|
94
94
|
)
|
95
|
-
raise ValueError(
|
96
|
-
msg,
|
97
|
-
)
|
95
|
+
raise ValueError(msg)
|
98
96
|
|
99
97
|
return busdaycalendar(holidays=hols)
|
100
98
|
|
@@ -115,6 +113,7 @@ def date_fix(
|
|
115
113
|
Parsed date
|
116
114
|
|
117
115
|
"""
|
116
|
+
msg = f"Unknown date format {fixerdate!s} of type {type(fixerdate)!s} encountered"
|
118
117
|
if isinstance(fixerdate, (Timestamp, dt.datetime)):
|
119
118
|
return fixerdate.date()
|
120
119
|
if isinstance(fixerdate, dt.date):
|
@@ -125,10 +124,7 @@ def date_fix(
|
|
125
124
|
)
|
126
125
|
if isinstance(fixerdate, str):
|
127
126
|
return dt.datetime.strptime(fixerdate, "%Y-%m-%d").astimezone().date()
|
128
|
-
|
129
|
-
raise TypeError(
|
130
|
-
msg,
|
131
|
-
)
|
127
|
+
raise TypeError(msg)
|
132
128
|
|
133
129
|
|
134
130
|
def date_offset_foll(
|
@@ -372,9 +368,7 @@ def generate_calendar_date_range(
|
|
372
368
|
"Provide one of start or end date, but not both. "
|
373
369
|
"Date range is inferred from number of trading days."
|
374
370
|
)
|
375
|
-
raise ValueError(
|
376
|
-
msg,
|
377
|
-
)
|
371
|
+
raise ValueError(msg)
|
378
372
|
|
379
373
|
|
380
374
|
# noinspection PyUnusedLocal
|
@@ -13,7 +13,6 @@ if TYPE_CHECKING:
|
|
13
13
|
|
14
14
|
import statsmodels.api as sm # type: ignore[import-untyped,unused-ignore]
|
15
15
|
from numpy import (
|
16
|
-
array,
|
17
16
|
cov,
|
18
17
|
cumprod,
|
19
18
|
divide,
|
@@ -777,6 +776,7 @@ class OpenFrame(_CommonModel):
|
|
777
776
|
earlier, later = self.calc_range(months_from_last, from_date, to_date)
|
778
777
|
fraction = (later - earlier).days / 365.25
|
779
778
|
|
779
|
+
msg = "base_column should be a tuple[str, ValueType] or an integer."
|
780
780
|
if isinstance(base_column, tuple):
|
781
781
|
shortdf = self.tsdf.loc[cast(int, earlier) : cast(int, later)].loc[
|
782
782
|
:,
|
@@ -798,10 +798,7 @@ class OpenFrame(_CommonModel):
|
|
798
798
|
].name
|
799
799
|
short_label = cast(tuple[str, str], self.tsdf.iloc[:, base_column].name)[0]
|
800
800
|
else:
|
801
|
-
msg
|
802
|
-
raise TypeError(
|
803
|
-
msg,
|
804
|
-
)
|
801
|
+
raise TypeError(msg)
|
805
802
|
|
806
803
|
if periods_in_a_year_fixed:
|
807
804
|
time_factor = float(periods_in_a_year_fixed)
|
@@ -870,6 +867,7 @@ class OpenFrame(_CommonModel):
|
|
870
867
|
earlier, later = self.calc_range(months_from_last, from_date, to_date)
|
871
868
|
fraction = (later - earlier).days / 365.25
|
872
869
|
|
870
|
+
msg = "base_column should be a tuple[str, ValueType] or an integer."
|
873
871
|
if isinstance(base_column, tuple):
|
874
872
|
shortdf = self.tsdf.loc[cast(int, earlier) : cast(int, later)].loc[
|
875
873
|
:,
|
@@ -891,10 +889,7 @@ class OpenFrame(_CommonModel):
|
|
891
889
|
].name
|
892
890
|
short_label = cast(tuple[str, str], self.tsdf.iloc[:, base_column].name)[0]
|
893
891
|
else:
|
894
|
-
msg
|
895
|
-
raise TypeError(
|
896
|
-
msg,
|
897
|
-
)
|
892
|
+
raise TypeError(msg)
|
898
893
|
|
899
894
|
if periods_in_a_year_fixed:
|
900
895
|
time_factor = float(periods_in_a_year_fixed)
|
@@ -974,6 +969,7 @@ class OpenFrame(_CommonModel):
|
|
974
969
|
earlier, later = self.calc_range(months_from_last, from_date, to_date)
|
975
970
|
fraction = (later - earlier).days / 365.25
|
976
971
|
|
972
|
+
msg = "base_column should be a tuple[str, ValueType] or an integer."
|
977
973
|
if isinstance(base_column, tuple):
|
978
974
|
shortdf = self.tsdf.loc[cast(int, earlier) : cast(int, later)].loc[
|
979
975
|
:,
|
@@ -995,10 +991,7 @@ class OpenFrame(_CommonModel):
|
|
995
991
|
].name
|
996
992
|
short_label = cast(tuple[str, str], self.tsdf.iloc[:, base_column].name)[0]
|
997
993
|
else:
|
998
|
-
msg
|
999
|
-
raise TypeError(
|
1000
|
-
msg,
|
1001
|
-
)
|
994
|
+
raise TypeError(msg)
|
1002
995
|
|
1003
996
|
if periods_in_a_year_fixed:
|
1004
997
|
time_factor = float(periods_in_a_year_fixed)
|
@@ -1014,6 +1007,7 @@ class OpenFrame(_CommonModel):
|
|
1014
1007
|
:,
|
1015
1008
|
item,
|
1016
1009
|
]
|
1010
|
+
msg = "ratio must be one of 'up', 'down' or 'both'."
|
1017
1011
|
if ratio == "up":
|
1018
1012
|
uparray = (
|
1019
1013
|
longdf.pct_change(fill_method=None)[
|
@@ -1109,7 +1103,6 @@ class OpenFrame(_CommonModel):
|
|
1109
1103
|
(up_rtrn / up_idx_return) / (down_return / down_idx_return),
|
1110
1104
|
)
|
1111
1105
|
else:
|
1112
|
-
msg = "ratio must be one of 'up', 'down' or 'both'."
|
1113
1106
|
raise ValueError(msg)
|
1114
1107
|
|
1115
1108
|
if ratio == "up":
|
@@ -1156,25 +1149,23 @@ class OpenFrame(_CommonModel):
|
|
1156
1149
|
x_value == ValueType.RTRN
|
1157
1150
|
for x_value in self.tsdf.columns.get_level_values(1).to_numpy()
|
1158
1151
|
):
|
1152
|
+
msg = "asset should be a tuple[str, ValueType] or an integer."
|
1159
1153
|
if isinstance(asset, tuple):
|
1160
1154
|
y_value = self.tsdf.loc[:, asset]
|
1161
1155
|
elif isinstance(asset, int):
|
1162
1156
|
y_value = self.tsdf.iloc[:, asset]
|
1163
1157
|
else:
|
1164
|
-
msg
|
1165
|
-
|
1166
|
-
|
1167
|
-
)
|
1158
|
+
raise TypeError(msg)
|
1159
|
+
|
1160
|
+
msg = "market should be a tuple[str, ValueType] or an integer."
|
1168
1161
|
if isinstance(market, tuple):
|
1169
1162
|
x_value = self.tsdf.loc[:, market]
|
1170
1163
|
elif isinstance(market, int):
|
1171
1164
|
x_value = self.tsdf.iloc[:, market]
|
1172
1165
|
else:
|
1173
|
-
msg
|
1174
|
-
raise TypeError(
|
1175
|
-
msg,
|
1176
|
-
)
|
1166
|
+
raise TypeError(msg)
|
1177
1167
|
else:
|
1168
|
+
msg = "asset should be a tuple[str, ValueType] or an integer."
|
1178
1169
|
if isinstance(asset, tuple):
|
1179
1170
|
y_value = log(
|
1180
1171
|
self.tsdf.loc[:, asset] / self.tsdf.loc[:, asset].iloc[0],
|
@@ -1184,10 +1175,9 @@ class OpenFrame(_CommonModel):
|
|
1184
1175
|
self.tsdf.iloc[:, asset] / cast(float, self.tsdf.iloc[0, asset]),
|
1185
1176
|
)
|
1186
1177
|
else:
|
1187
|
-
msg
|
1188
|
-
|
1189
|
-
|
1190
|
-
)
|
1178
|
+
raise TypeError(msg)
|
1179
|
+
|
1180
|
+
msg = "market should be a tuple[str, ValueType] or an integer."
|
1191
1181
|
if isinstance(market, tuple):
|
1192
1182
|
x_value = log(
|
1193
1183
|
self.tsdf.loc[:, market] / self.tsdf.loc[:, market].iloc[0],
|
@@ -1197,10 +1187,7 @@ class OpenFrame(_CommonModel):
|
|
1197
1187
|
self.tsdf.iloc[:, market] / cast(float, self.tsdf.iloc[0, market]),
|
1198
1188
|
)
|
1199
1189
|
else:
|
1200
|
-
msg
|
1201
|
-
raise TypeError(
|
1202
|
-
msg,
|
1203
|
-
)
|
1190
|
+
raise TypeError(msg)
|
1204
1191
|
|
1205
1192
|
covariance = cov(y_value, x_value, ddof=dlta_degr_freedms)
|
1206
1193
|
beta = covariance[0, 1] / covariance[1, 1]
|
@@ -1241,6 +1228,7 @@ class OpenFrame(_CommonModel):
|
|
1241
1228
|
The Statsmodels regression output
|
1242
1229
|
|
1243
1230
|
"""
|
1231
|
+
msg = "y_column should be a tuple[str, ValueType] or an integer."
|
1244
1232
|
if isinstance(y_column, tuple):
|
1245
1233
|
y_value = self.tsdf.loc[:, y_column]
|
1246
1234
|
y_label = cast(
|
@@ -1251,11 +1239,9 @@ class OpenFrame(_CommonModel):
|
|
1251
1239
|
y_value = self.tsdf.iloc[:, y_column]
|
1252
1240
|
y_label = cast(tuple[str, str], self.tsdf.iloc[:, y_column].name)[0]
|
1253
1241
|
else:
|
1254
|
-
msg
|
1255
|
-
raise TypeError(
|
1256
|
-
msg,
|
1257
|
-
)
|
1242
|
+
raise TypeError(msg)
|
1258
1243
|
|
1244
|
+
msg = "x_column should be a tuple[str, ValueType] or an integer."
|
1259
1245
|
if isinstance(x_column, tuple):
|
1260
1246
|
x_value = self.tsdf.loc[:, x_column]
|
1261
1247
|
x_label = cast(
|
@@ -1266,10 +1252,7 @@ class OpenFrame(_CommonModel):
|
|
1266
1252
|
x_value = self.tsdf.iloc[:, x_column]
|
1267
1253
|
x_label = cast(tuple[str, str], self.tsdf.iloc[:, x_column].name)[0]
|
1268
1254
|
else:
|
1269
|
-
msg
|
1270
|
-
raise TypeError(
|
1271
|
-
msg,
|
1272
|
-
)
|
1255
|
+
raise TypeError(msg)
|
1273
1256
|
|
1274
1257
|
results = sm.OLS(y_value, x_value).fit(method=method, cov_type=cov_type)
|
1275
1258
|
if fitted_series:
|
@@ -1315,6 +1298,7 @@ class OpenFrame(_CommonModel):
|
|
1315
1298
|
x == ValueType.RTRN
|
1316
1299
|
for x in self.tsdf.columns.get_level_values(1).to_numpy()
|
1317
1300
|
):
|
1301
|
+
msg = "asset should be a tuple[str, ValueType] or an integer."
|
1318
1302
|
if isinstance(asset, tuple):
|
1319
1303
|
asset_log = self.tsdf.loc[:, asset]
|
1320
1304
|
asset_cagr = asset_log.mean()
|
@@ -1322,10 +1306,9 @@ class OpenFrame(_CommonModel):
|
|
1322
1306
|
asset_log = self.tsdf.iloc[:, asset]
|
1323
1307
|
asset_cagr = asset_log.mean()
|
1324
1308
|
else:
|
1325
|
-
msg
|
1326
|
-
|
1327
|
-
|
1328
|
-
)
|
1309
|
+
raise TypeError(msg)
|
1310
|
+
|
1311
|
+
msg = "market should be a tuple[str, ValueType] or an integer."
|
1329
1312
|
if isinstance(market, tuple):
|
1330
1313
|
market_log = self.tsdf.loc[:, market]
|
1331
1314
|
market_cagr = market_log.mean()
|
@@ -1333,11 +1316,9 @@ class OpenFrame(_CommonModel):
|
|
1333
1316
|
market_log = self.tsdf.iloc[:, market]
|
1334
1317
|
market_cagr = market_log.mean()
|
1335
1318
|
else:
|
1336
|
-
msg
|
1337
|
-
raise TypeError(
|
1338
|
-
msg,
|
1339
|
-
)
|
1319
|
+
raise TypeError(msg)
|
1340
1320
|
else:
|
1321
|
+
msg = "asset should be a tuple[str, ValueType] or an integer."
|
1341
1322
|
if isinstance(asset, tuple):
|
1342
1323
|
asset_log = log(
|
1343
1324
|
self.tsdf.loc[:, asset] / self.tsdf.loc[:, asset].iloc[0],
|
@@ -1369,10 +1350,9 @@ class OpenFrame(_CommonModel):
|
|
1369
1350
|
- 1
|
1370
1351
|
)
|
1371
1352
|
else:
|
1372
|
-
msg
|
1373
|
-
|
1374
|
-
|
1375
|
-
)
|
1353
|
+
raise TypeError(msg)
|
1354
|
+
|
1355
|
+
msg = "market should be a tuple[str, ValueType] or an integer."
|
1376
1356
|
if isinstance(market, tuple):
|
1377
1357
|
market_log = log(
|
1378
1358
|
self.tsdf.loc[:, market] / self.tsdf.loc[:, market].iloc[0],
|
@@ -1404,10 +1384,7 @@ class OpenFrame(_CommonModel):
|
|
1404
1384
|
- 1
|
1405
1385
|
)
|
1406
1386
|
else:
|
1407
|
-
msg
|
1408
|
-
raise TypeError(
|
1409
|
-
msg,
|
1410
|
-
)
|
1387
|
+
raise TypeError(msg)
|
1411
1388
|
|
1412
1389
|
covariance = cov(asset_log, market_log, ddof=dlta_degr_freedms)
|
1413
1390
|
beta = covariance[0, 1] / covariance[1, 1]
|
@@ -1439,9 +1416,7 @@ class OpenFrame(_CommonModel):
|
|
1439
1416
|
"OpenFrame weights property must be provided "
|
1440
1417
|
"to run the make_portfolio method."
|
1441
1418
|
)
|
1442
|
-
raise ValueError(
|
1443
|
-
msg,
|
1444
|
-
)
|
1419
|
+
raise ValueError(msg)
|
1445
1420
|
dframe = self.tsdf.copy()
|
1446
1421
|
if not any(
|
1447
1422
|
x == ValueType.RTRN
|
@@ -1449,6 +1424,8 @@ class OpenFrame(_CommonModel):
|
|
1449
1424
|
):
|
1450
1425
|
dframe = dframe.pct_change(fill_method=None)
|
1451
1426
|
dframe.iloc[0] = 0
|
1427
|
+
|
1428
|
+
msg = "Weight strategy not implemented"
|
1452
1429
|
if weight_strat:
|
1453
1430
|
if weight_strat == "eq_weights":
|
1454
1431
|
self.weights = [1.0 / self.item_count] * self.item_count
|
@@ -1457,10 +1434,10 @@ class OpenFrame(_CommonModel):
|
|
1457
1434
|
vol[isinf(vol)] = nan
|
1458
1435
|
self.weights = list(divide(vol, vol.sum()))
|
1459
1436
|
else:
|
1460
|
-
msg = "Weight strategy not implemented"
|
1461
1437
|
raise NotImplementedError(msg)
|
1438
|
+
|
1462
1439
|
return DataFrame(
|
1463
|
-
data=dframe
|
1440
|
+
data=(dframe @ self.weights).add(1.0).cumprod(),
|
1464
1441
|
index=self.tsdf.index,
|
1465
1442
|
columns=[[name], [ValueType.PRICE]],
|
1466
1443
|
dtype="float64",
|
@@ -10,7 +10,6 @@ from typing import TYPE_CHECKING, Callable, cast
|
|
10
10
|
from numpy import (
|
11
11
|
append,
|
12
12
|
array,
|
13
|
-
dot,
|
14
13
|
float64,
|
15
14
|
inf,
|
16
15
|
isnan,
|
@@ -106,11 +105,8 @@ def simulate_portfolios(
|
|
106
105
|
weights = weights / npsum(weights)
|
107
106
|
all_weights[x, :] = weights
|
108
107
|
|
109
|
-
vol_arr[x] = sqrt(
|
110
|
-
|
111
|
-
weights.T,
|
112
|
-
dot(log_ret.cov() * simframe.periods_in_a_year, weights),
|
113
|
-
),
|
108
|
+
vol_arr[x] = sqrt(weights.T @
|
109
|
+
(log_ret.cov() * simframe.periods_in_a_year @ weights),
|
114
110
|
)
|
115
111
|
|
116
112
|
ret_arr[x] = npsum(log_ret.mean() * weights * simframe.periods_in_a_year)
|
@@ -198,7 +194,7 @@ def efficient_frontier( # noqa: C901
|
|
198
194
|
per_in_yr: float,
|
199
195
|
) -> NDArray[float64]:
|
200
196
|
ret = npsum(lg_ret.mean() * weights) * per_in_yr
|
201
|
-
volatility = sqrt(
|
197
|
+
volatility = sqrt(weights.T @ (lg_ret.cov() * per_in_yr @ weights))
|
202
198
|
sr = ret / volatility
|
203
199
|
return cast(NDArray[float64], array([ret, volatility, sr]))
|
204
200
|
|
@@ -288,6 +284,7 @@ def efficient_frontier( # noqa: C901
|
|
288
284
|
frontier_x.append(result["fun"])
|
289
285
|
frontier_weights.append(result["x"])
|
290
286
|
|
287
|
+
# noinspection PyUnreachableCode
|
291
288
|
line_df = concat(
|
292
289
|
[
|
293
290
|
DataFrame(data=frontier_weights, columns=eframe.columns_lvl_zero),
|
@@ -107,20 +107,20 @@ class OpenTimeSeries(_CommonModel):
|
|
107
107
|
|
108
108
|
@field_validator("domestic", mode="before")
|
109
109
|
@classmethod
|
110
|
-
def
|
110
|
+
def _validate_domestic(cls, value: CurrencyStringType) -> CurrencyStringType:
|
111
111
|
"""Pydantic validator to ensure domestic field is validated."""
|
112
112
|
_ = Currency(ccy=value)
|
113
113
|
return value
|
114
114
|
|
115
115
|
@field_validator("countries", mode="before")
|
116
116
|
@classmethod
|
117
|
-
def
|
117
|
+
def _validate_countries(cls, value: CountriesType) -> CountriesType:
|
118
118
|
"""Pydantic validator to ensure countries field is validated."""
|
119
119
|
_ = Countries(countryinput=value)
|
120
120
|
return value
|
121
121
|
|
122
122
|
@model_validator(mode="after") # type: ignore[misc,unused-ignore]
|
123
|
-
def
|
123
|
+
def _dates_and_values_validate(self: Self) -> Self:
|
124
124
|
"""Pydantic validator to ensure dates and values are validated."""
|
125
125
|
values_list_length = len(self.values)
|
126
126
|
dates_list_length = len(self.dates)
|
@@ -233,8 +233,11 @@ class OpenTimeSeries(_CommonModel):
|
|
233
233
|
An OpenTimeSeries object
|
234
234
|
|
235
235
|
"""
|
236
|
-
|
237
|
-
|
236
|
+
msg = "Argument dframe must be pandas Series or DataFrame."
|
237
|
+
if isinstance(dframe, Series): # type: ignore[unreachable,unused-ignore]
|
238
|
+
if isinstance( # type: ignore[unreachable,unused-ignore]
|
239
|
+
dframe.name, tuple,
|
240
|
+
):
|
238
241
|
label, _ = dframe.name
|
239
242
|
else:
|
240
243
|
label = dframe.name
|
@@ -263,7 +266,6 @@ class OpenTimeSeries(_CommonModel):
|
|
263
266
|
else:
|
264
267
|
label = cast(MultiIndex, dframe.columns).to_numpy()[column_nmbr]
|
265
268
|
else:
|
266
|
-
msg = "Argument dframe must be pandas Series or DataFrame."
|
267
269
|
raise TypeError(msg)
|
268
270
|
|
269
271
|
dates = [date_fix(d).strftime("%Y-%m-%d") for d in dframe.index]
|
@@ -337,9 +339,7 @@ class OpenTimeSeries(_CommonModel):
|
|
337
339
|
)
|
338
340
|
elif not isinstance(d_range, DatetimeIndex) and not all([days, end_dt]):
|
339
341
|
msg = "If d_range is not provided both days and end_dt must be."
|
340
|
-
raise ValueError(
|
341
|
-
msg,
|
342
|
-
)
|
342
|
+
raise ValueError(msg)
|
343
343
|
|
344
344
|
deltas = array(
|
345
345
|
[
|
@@ -272,9 +272,7 @@ class OpenTimeSeriesPropertiesList(list[str]):
|
|
272
272
|
msg = (
|
273
273
|
f"Invalid string: {item}. Allowed strings: {self.allowed_strings}"
|
274
274
|
)
|
275
|
-
raise ValueError(
|
276
|
-
msg,
|
277
|
-
)
|
275
|
+
raise ValueError(msg)
|
278
276
|
if item in seen:
|
279
277
|
msg = f"Duplicate string: {item}"
|
280
278
|
raise ValueError(msg)
|
@@ -323,9 +321,7 @@ class OpenFramePropertiesList(list[str]):
|
|
323
321
|
msg = (
|
324
322
|
f"Invalid string: {item}. Allowed strings: {self.allowed_strings}"
|
325
323
|
)
|
326
|
-
raise ValueError(
|
327
|
-
msg,
|
328
|
-
)
|
324
|
+
raise ValueError(msg)
|
329
325
|
if item in seen:
|
330
326
|
msg = f"Duplicate string: {item}"
|
331
327
|
raise ValueError(msg)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[tool.poetry]
|
2
2
|
name = "openseries"
|
3
|
-
version = "1.7.
|
3
|
+
version = "1.7.2"
|
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"
|
@@ -42,7 +42,7 @@ pyarrow = ">=14.0.2,<18.0.0"
|
|
42
42
|
pydantic = ">=2.5.2,<3.0.0"
|
43
43
|
python-dateutil = ">=2.8.2,<3.0.0"
|
44
44
|
requests = ">=2.20.0,<3.0.0"
|
45
|
-
scipy = ">=1.11.4,<
|
45
|
+
scipy = ">=1.11.4,<1.14.1"
|
46
46
|
statsmodels = ">=0.14.0,<1.0.0"
|
47
47
|
|
48
48
|
[tool.poetry.group.dev.dependencies]
|
@@ -53,7 +53,7 @@ mypy = "^1.11.1"
|
|
53
53
|
pandas-stubs = ">=2.1.2,<3.0.0"
|
54
54
|
pre-commit = ">=3.7.1,<4.0.0"
|
55
55
|
pytest = ">=8.2.2,<9.0.0"
|
56
|
-
ruff = "^0.
|
56
|
+
ruff = "^0.6.2"
|
57
57
|
types-openpyxl = ">=3.1.2,<4.0.0"
|
58
58
|
types-python-dateutil = ">=2.8.2,<3.0.0"
|
59
59
|
types-requests = ">=2.20.0,<3.0.0"
|
@@ -79,7 +79,7 @@ output = "coverage.xml"
|
|
79
79
|
exclude = ["venv/*"]
|
80
80
|
strict = true
|
81
81
|
pretty = true
|
82
|
-
warn_unreachable =
|
82
|
+
warn_unreachable = true
|
83
83
|
warn_redundant_casts = true
|
84
84
|
warn_unused_ignores = true
|
85
85
|
disallow_any_generics = true
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|