openseries 1.7.4__tar.gz → 1.7.6__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.4 → openseries-1.7.6}/PKG-INFO +4 -4
- {openseries-1.7.4 → openseries-1.7.6}/openseries/_common_model.py +48 -10
- {openseries-1.7.4 → openseries-1.7.6}/openseries/frame.py +48 -28
- {openseries-1.7.4 → openseries-1.7.6}/openseries/portfoliotools.py +1 -1
- {openseries-1.7.4 → openseries-1.7.6}/openseries/series.py +1 -1
- {openseries-1.7.4 → openseries-1.7.6}/openseries/simulation.py +7 -4
- {openseries-1.7.4 → openseries-1.7.6}/pyproject.toml +8 -8
- {openseries-1.7.4 → openseries-1.7.6}/LICENSE.md +0 -0
- {openseries-1.7.4 → openseries-1.7.6}/README.md +0 -0
- {openseries-1.7.4 → openseries-1.7.6}/openseries/__init__.py +0 -0
- {openseries-1.7.4 → openseries-1.7.6}/openseries/_risk.py +0 -0
- {openseries-1.7.4 → openseries-1.7.6}/openseries/datefixer.py +0 -0
- {openseries-1.7.4 → openseries-1.7.6}/openseries/load_plotly.py +0 -0
- {openseries-1.7.4 → openseries-1.7.6}/openseries/plotly_captor_logo.json +0 -0
- {openseries-1.7.4 → openseries-1.7.6}/openseries/plotly_layouts.json +0 -0
- {openseries-1.7.4 → openseries-1.7.6}/openseries/types.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.6
|
4
4
|
Summary: Tools for analyzing financial timeseries.
|
5
5
|
Home-page: https://github.com/CaptorAB/openseries
|
6
6
|
License: BSD-3-Clause
|
@@ -20,16 +20,16 @@ Classifier: Programming Language :: Python :: 3.11
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.12
|
21
21
|
Classifier: Topic :: Office/Business :: Financial :: Investment
|
22
22
|
Requires-Dist: holidays (>=0.30,<1.0)
|
23
|
-
Requires-Dist: numpy (>=1.23.2
|
23
|
+
Requires-Dist: numpy (>=1.23.2,<3.0.0)
|
24
24
|
Requires-Dist: openpyxl (>=3.1.2,<4.0.0)
|
25
25
|
Requires-Dist: pandas (>=2.1.2,<3.0.0)
|
26
26
|
Requires-Dist: plotly (>=5.18.0,<6.0.0)
|
27
|
-
Requires-Dist: pyarrow (>=14.0.2,<
|
27
|
+
Requires-Dist: pyarrow (>=14.0.2,<19.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
31
|
Requires-Dist: scipy (>=1.11.4,<2.0.0)
|
32
|
-
Requires-Dist: statsmodels (>=0.14.0,<1.0.0)
|
32
|
+
Requires-Dist: statsmodels (>=0.14.0,!=0.14.2,<1.0.0)
|
33
33
|
Project-URL: Repository, https://github.com/CaptorAB/openseries
|
34
34
|
Description-Content-Type: text/markdown
|
35
35
|
|
@@ -43,7 +43,11 @@ from ._risk import (
|
|
43
43
|
_cvar_down_calc,
|
44
44
|
_var_down_calc,
|
45
45
|
)
|
46
|
-
from .datefixer import
|
46
|
+
from .datefixer import (
|
47
|
+
_do_resample_to_business_period_ends,
|
48
|
+
date_offset_foll,
|
49
|
+
holiday_calendar,
|
50
|
+
)
|
47
51
|
from .load_plotly import load_plotly_dict
|
48
52
|
from .types import (
|
49
53
|
CountriesType,
|
@@ -52,6 +56,7 @@ from .types import (
|
|
52
56
|
LiteralJsonOutput,
|
53
57
|
LiteralLinePlotMode,
|
54
58
|
LiteralNanMethod,
|
59
|
+
LiteralPandasReindexMethod,
|
55
60
|
LiteralPlotlyJSlib,
|
56
61
|
LiteralPlotlyOutput,
|
57
62
|
LiteralQuantileInterp,
|
@@ -358,9 +363,17 @@ class _CommonModel(BaseModel):
|
|
358
363
|
Most negative month
|
359
364
|
|
360
365
|
"""
|
366
|
+
method: LiteralPandasReindexMethod = "nearest"
|
367
|
+
countries = "SE"
|
361
368
|
wmdf = self.tsdf.copy()
|
369
|
+
dates = _do_resample_to_business_period_ends(
|
370
|
+
data=wmdf,
|
371
|
+
freq="BME",
|
372
|
+
countries=countries,
|
373
|
+
)
|
374
|
+
wmdf = wmdf.reindex(index=[deyt.date() for deyt in dates], method=method)
|
362
375
|
wmdf.index = DatetimeIndex(wmdf.index)
|
363
|
-
result = wmdf.
|
376
|
+
result = wmdf.ffill().pct_change().min()
|
364
377
|
|
365
378
|
if self.tsdf.shape[1] == 1:
|
366
379
|
return float(result.iloc[0])
|
@@ -1285,19 +1298,24 @@ class _CommonModel(BaseModel):
|
|
1285
1298
|
if drift_adjust:
|
1286
1299
|
imp_vol = (-sqrt(time_factor) / norm.ppf(level)) * (
|
1287
1300
|
self.tsdf.loc[cast(int, earlier) : cast(int, later)]
|
1301
|
+
.ffill()
|
1288
1302
|
.pct_change()
|
1289
1303
|
.quantile(1 - level, interpolation=interpolation)
|
1290
1304
|
- self.tsdf.loc[cast(int, earlier) : cast(int, later)]
|
1305
|
+
.ffill()
|
1291
1306
|
.pct_change()
|
1292
1307
|
.sum()
|
1293
1308
|
/ len(
|
1294
|
-
self.tsdf.loc[cast(int, earlier) : cast(int, later)]
|
1309
|
+
self.tsdf.loc[cast(int, earlier) : cast(int, later)]
|
1310
|
+
.ffill()
|
1311
|
+
.pct_change(),
|
1295
1312
|
)
|
1296
1313
|
)
|
1297
1314
|
else:
|
1298
1315
|
imp_vol = (
|
1299
1316
|
-sqrt(time_factor)
|
1300
1317
|
* self.tsdf.loc[cast(int, earlier) : cast(int, later)]
|
1318
|
+
.ffill()
|
1301
1319
|
.pct_change()
|
1302
1320
|
.quantile(1 - level, interpolation=interpolation)
|
1303
1321
|
/ norm.ppf(level)
|
@@ -1361,6 +1379,7 @@ class _CommonModel(BaseModel):
|
|
1361
1379
|
cvar_df = self.tsdf.loc[cast(int, earlier) : cast(int, later)].copy(deep=True)
|
1362
1380
|
result = [
|
1363
1381
|
cvar_df.loc[:, x] # type: ignore[call-overload,index]
|
1382
|
+
.ffill()
|
1364
1383
|
.pct_change()
|
1365
1384
|
.sort_values()
|
1366
1385
|
.iloc[
|
@@ -1368,6 +1387,7 @@ class _CommonModel(BaseModel):
|
|
1368
1387
|
ceil(
|
1369
1388
|
(1 - level)
|
1370
1389
|
* cvar_df.loc[:, x] # type: ignore[index]
|
1390
|
+
.ffill()
|
1371
1391
|
.pct_change()
|
1372
1392
|
.count(),
|
1373
1393
|
),
|
@@ -1428,6 +1448,7 @@ class _CommonModel(BaseModel):
|
|
1428
1448
|
)
|
1429
1449
|
how_many = (
|
1430
1450
|
self.tsdf.loc[cast(int, earlier) : cast(int, later)]
|
1451
|
+
.ffill()
|
1431
1452
|
.pct_change()
|
1432
1453
|
.count(numeric_only=True)
|
1433
1454
|
)
|
@@ -1443,6 +1464,7 @@ class _CommonModel(BaseModel):
|
|
1443
1464
|
|
1444
1465
|
dddf = (
|
1445
1466
|
self.tsdf.loc[cast(int, earlier) : cast(int, later)]
|
1467
|
+
.ffill()
|
1446
1468
|
.pct_change()
|
1447
1469
|
.sub(min_accepted_return / time_factor)
|
1448
1470
|
)
|
@@ -1546,6 +1568,7 @@ class _CommonModel(BaseModel):
|
|
1546
1568
|
)
|
1547
1569
|
result: NDArray[float64] = skew(
|
1548
1570
|
a=self.tsdf.loc[cast(int, earlier) : cast(int, later)]
|
1571
|
+
.ffill()
|
1549
1572
|
.pct_change()
|
1550
1573
|
.to_numpy(),
|
1551
1574
|
bias=True,
|
@@ -1593,7 +1616,7 @@ class _CommonModel(BaseModel):
|
|
1593
1616
|
to_dt=to_date,
|
1594
1617
|
)
|
1595
1618
|
result: NDArray[float64] = kurtosis(
|
1596
|
-
self.tsdf.loc[cast(int, earlier) : cast(int, later)].pct_change(),
|
1619
|
+
self.tsdf.loc[cast(int, earlier) : cast(int, later)].ffill().pct_change(),
|
1597
1620
|
fisher=True,
|
1598
1621
|
bias=True,
|
1599
1622
|
nan_policy="omit",
|
@@ -1689,13 +1712,21 @@ class _CommonModel(BaseModel):
|
|
1689
1712
|
)
|
1690
1713
|
pos = (
|
1691
1714
|
self.tsdf.loc[cast(int, earlier) : cast(int, later)]
|
1715
|
+
.ffill()
|
1692
1716
|
.pct_change()[1:][
|
1693
|
-
self.tsdf.loc[cast(int, earlier) : cast(int, later)]
|
1717
|
+
self.tsdf.loc[cast(int, earlier) : cast(int, later)]
|
1718
|
+
.ffill()
|
1719
|
+
.pct_change()[1:]
|
1694
1720
|
> zero
|
1695
1721
|
]
|
1696
1722
|
.count()
|
1697
1723
|
)
|
1698
|
-
tot =
|
1724
|
+
tot = (
|
1725
|
+
self.tsdf.loc[cast(int, earlier) : cast(int, later)]
|
1726
|
+
.ffill()
|
1727
|
+
.pct_change()
|
1728
|
+
.count()
|
1729
|
+
)
|
1699
1730
|
share = pos / tot
|
1700
1731
|
if self.tsdf.shape[1] == 1:
|
1701
1732
|
return float(share.iloc[0])
|
@@ -1871,7 +1902,9 @@ class _CommonModel(BaseModel):
|
|
1871
1902
|
from_dt=from_date,
|
1872
1903
|
to_dt=to_date,
|
1873
1904
|
)
|
1874
|
-
retdf =
|
1905
|
+
retdf = (
|
1906
|
+
self.tsdf.loc[cast(int, earlier) : cast(int, later)].ffill().pct_change()
|
1907
|
+
)
|
1875
1908
|
pos = retdf[retdf > min_accepted_return].sub(min_accepted_return).sum()
|
1876
1909
|
neg = retdf[retdf < min_accepted_return].sub(min_accepted_return).sum()
|
1877
1910
|
ratio = pos / -neg
|
@@ -1959,7 +1992,7 @@ class _CommonModel(BaseModel):
|
|
1959
1992
|
period = "-".join([str(year), str(month).zfill(2)])
|
1960
1993
|
vrdf = self.tsdf.copy()
|
1961
1994
|
vrdf.index = DatetimeIndex(vrdf.index)
|
1962
|
-
resultdf = DataFrame(vrdf.pct_change())
|
1995
|
+
resultdf = DataFrame(vrdf.ffill().pct_change())
|
1963
1996
|
result = resultdf.loc[period] + 1
|
1964
1997
|
cal_period = result.cumprod(axis="index").iloc[-1] - 1
|
1965
1998
|
if self.tsdf.shape[1] == 1:
|
@@ -2011,6 +2044,7 @@ class _CommonModel(BaseModel):
|
|
2011
2044
|
)
|
2012
2045
|
result = (
|
2013
2046
|
self.tsdf.loc[cast(int, earlier) : cast(int, later)]
|
2047
|
+
.ffill()
|
2014
2048
|
.pct_change()
|
2015
2049
|
.quantile(1 - level, interpolation=interpolation)
|
2016
2050
|
)
|
@@ -2059,6 +2093,7 @@ class _CommonModel(BaseModel):
|
|
2059
2093
|
)
|
2060
2094
|
result = (
|
2061
2095
|
self.tsdf.loc[cast(int, earlier) : cast(int, later)]
|
2096
|
+
.ffill()
|
2062
2097
|
.pct_change()
|
2063
2098
|
.rolling(observations, min_periods=observations)
|
2064
2099
|
.sum()
|
@@ -2105,7 +2140,9 @@ class _CommonModel(BaseModel):
|
|
2105
2140
|
from_dt=from_date,
|
2106
2141
|
to_dt=to_date,
|
2107
2142
|
)
|
2108
|
-
zscframe =
|
2143
|
+
zscframe = (
|
2144
|
+
self.tsdf.loc[cast(int, earlier) : cast(int, later)].ffill().pct_change()
|
2145
|
+
)
|
2109
2146
|
result = (zscframe.iloc[-1] - zscframe.mean()) / zscframe.std()
|
2110
2147
|
|
2111
2148
|
if self.tsdf.shape[1] == 1:
|
@@ -2174,6 +2211,7 @@ class _CommonModel(BaseModel):
|
|
2174
2211
|
ret_label = cast(tuple[str], self.tsdf.iloc[:, column].name)[0]
|
2175
2212
|
retseries = (
|
2176
2213
|
self.tsdf.iloc[:, column]
|
2214
|
+
.ffill()
|
2177
2215
|
.pct_change()
|
2178
2216
|
.rolling(observations, min_periods=observations)
|
2179
2217
|
.sum()
|
@@ -2251,7 +2289,7 @@ class _CommonModel(BaseModel):
|
|
2251
2289
|
else:
|
2252
2290
|
time_factor = self.periods_in_a_year
|
2253
2291
|
vol_label = cast(tuple[str, ValueType], self.tsdf.iloc[:, column].name)[0]
|
2254
|
-
dframe = self.tsdf.iloc[:, column].pct_change()
|
2292
|
+
dframe = self.tsdf.iloc[:, column].ffill().pct_change()
|
2255
2293
|
volseries = dframe.rolling(
|
2256
2294
|
observations,
|
2257
2295
|
min_periods=observations,
|
@@ -602,9 +602,13 @@ class OpenFrame(_CommonModel):
|
|
602
602
|
Correlation matrix
|
603
603
|
|
604
604
|
"""
|
605
|
-
corr_matrix =
|
606
|
-
|
607
|
-
|
605
|
+
corr_matrix = (
|
606
|
+
self.tsdf.ffill()
|
607
|
+
.pct_change()
|
608
|
+
.corr(
|
609
|
+
method="pearson",
|
610
|
+
min_periods=1,
|
611
|
+
)
|
608
612
|
)
|
609
613
|
corr_matrix.columns = corr_matrix.columns.droplevel(level=1)
|
610
614
|
corr_matrix.index = corr_matrix.index.droplevel(level=1)
|
@@ -829,7 +833,7 @@ class OpenFrame(_CommonModel):
|
|
829
833
|
]
|
830
834
|
relative = 1.0 + longdf - shortdf
|
831
835
|
vol = float(
|
832
|
-
relative.pct_change().std() * sqrt(time_factor),
|
836
|
+
relative.ffill().pct_change().std() * sqrt(time_factor),
|
833
837
|
)
|
834
838
|
terrors.append(vol)
|
835
839
|
|
@@ -919,10 +923,10 @@ class OpenFrame(_CommonModel):
|
|
919
923
|
]
|
920
924
|
relative = 1.0 + longdf - shortdf
|
921
925
|
ret = float(
|
922
|
-
relative.pct_change().mean() * time_factor,
|
926
|
+
relative.ffill().pct_change().mean() * time_factor,
|
923
927
|
)
|
924
928
|
vol = float(
|
925
|
-
relative.pct_change().std() * sqrt(time_factor),
|
929
|
+
relative.ffill().pct_change().std() * sqrt(time_factor),
|
926
930
|
)
|
927
931
|
ratios.append(ret / vol)
|
928
932
|
|
@@ -1021,16 +1025,18 @@ class OpenFrame(_CommonModel):
|
|
1021
1025
|
msg = "ratio must be one of 'up', 'down' or 'both'."
|
1022
1026
|
if ratio == "up":
|
1023
1027
|
uparray = (
|
1024
|
-
longdf.
|
1025
|
-
|
1028
|
+
longdf.ffill()
|
1029
|
+
.pct_change()[
|
1030
|
+
shortdf.ffill().pct_change().to_numpy() > loss_limit
|
1026
1031
|
]
|
1027
1032
|
.add(1)
|
1028
1033
|
.to_numpy()
|
1029
1034
|
)
|
1030
1035
|
up_rtrn = uparray.prod() ** (1 / (len(uparray) / time_factor)) - 1
|
1031
1036
|
upidxarray = (
|
1032
|
-
shortdf.
|
1033
|
-
|
1037
|
+
shortdf.ffill()
|
1038
|
+
.pct_change()[
|
1039
|
+
shortdf.ffill().pct_change().to_numpy() > loss_limit
|
1034
1040
|
]
|
1035
1041
|
.add(1)
|
1036
1042
|
.to_numpy()
|
@@ -1041,8 +1047,9 @@ class OpenFrame(_CommonModel):
|
|
1041
1047
|
ratios.append(up_rtrn / up_idx_return)
|
1042
1048
|
elif ratio == "down":
|
1043
1049
|
downarray = (
|
1044
|
-
longdf.
|
1045
|
-
|
1050
|
+
longdf.ffill()
|
1051
|
+
.pct_change()[
|
1052
|
+
shortdf.ffill().pct_change().to_numpy() < loss_limit
|
1046
1053
|
]
|
1047
1054
|
.add(1)
|
1048
1055
|
.to_numpy()
|
@@ -1051,8 +1058,9 @@ class OpenFrame(_CommonModel):
|
|
1051
1058
|
downarray.prod() ** (1 / (len(downarray) / time_factor)) - 1
|
1052
1059
|
)
|
1053
1060
|
downidxarray = (
|
1054
|
-
shortdf.
|
1055
|
-
|
1061
|
+
shortdf.ffill()
|
1062
|
+
.pct_change()[
|
1063
|
+
shortdf.ffill().pct_change().to_numpy() < loss_limit
|
1056
1064
|
]
|
1057
1065
|
.add(1)
|
1058
1066
|
.to_numpy()
|
@@ -1064,16 +1072,18 @@ class OpenFrame(_CommonModel):
|
|
1064
1072
|
ratios.append(down_return / down_idx_return)
|
1065
1073
|
elif ratio == "both":
|
1066
1074
|
uparray = (
|
1067
|
-
longdf.
|
1068
|
-
|
1075
|
+
longdf.ffill()
|
1076
|
+
.pct_change()[
|
1077
|
+
shortdf.ffill().pct_change().to_numpy() > loss_limit
|
1069
1078
|
]
|
1070
1079
|
.add(1)
|
1071
1080
|
.to_numpy()
|
1072
1081
|
)
|
1073
1082
|
up_rtrn = uparray.prod() ** (1 / (len(uparray) / time_factor)) - 1
|
1074
1083
|
upidxarray = (
|
1075
|
-
shortdf.
|
1076
|
-
|
1084
|
+
shortdf.ffill()
|
1085
|
+
.pct_change()[
|
1086
|
+
shortdf.ffill().pct_change().to_numpy() > loss_limit
|
1077
1087
|
]
|
1078
1088
|
.add(1)
|
1079
1089
|
.to_numpy()
|
@@ -1082,8 +1092,9 @@ class OpenFrame(_CommonModel):
|
|
1082
1092
|
upidxarray.prod() ** (1 / (len(upidxarray) / time_factor)) - 1
|
1083
1093
|
)
|
1084
1094
|
downarray = (
|
1085
|
-
longdf.
|
1086
|
-
|
1095
|
+
longdf.ffill()
|
1096
|
+
.pct_change()[
|
1097
|
+
shortdf.ffill().pct_change().to_numpy() < loss_limit
|
1087
1098
|
]
|
1088
1099
|
.add(1)
|
1089
1100
|
.to_numpy()
|
@@ -1092,8 +1103,9 @@ class OpenFrame(_CommonModel):
|
|
1092
1103
|
downarray.prod() ** (1 / (len(downarray) / time_factor)) - 1
|
1093
1104
|
)
|
1094
1105
|
downidxarray = (
|
1095
|
-
shortdf.
|
1096
|
-
|
1106
|
+
shortdf.ffill()
|
1107
|
+
.pct_change()[
|
1108
|
+
shortdf.ffill().pct_change().to_numpy() < loss_limit
|
1097
1109
|
]
|
1098
1110
|
.add(1)
|
1099
1111
|
.to_numpy()
|
@@ -1499,11 +1511,14 @@ class OpenFrame(_CommonModel):
|
|
1499
1511
|
)
|
1500
1512
|
|
1501
1513
|
retseries = (
|
1502
|
-
relative.
|
1514
|
+
relative.ffill()
|
1515
|
+
.pct_change()
|
1516
|
+
.rolling(observations, min_periods=observations)
|
1517
|
+
.sum()
|
1503
1518
|
)
|
1504
1519
|
retdf = retseries.dropna().to_frame()
|
1505
1520
|
|
1506
|
-
voldf = relative.pct_change().rolling(
|
1521
|
+
voldf = relative.ffill().pct_change().rolling(
|
1507
1522
|
observations,
|
1508
1523
|
min_periods=observations,
|
1509
1524
|
).std() * sqrt(time_factor)
|
@@ -1547,9 +1562,13 @@ class OpenFrame(_CommonModel):
|
|
1547
1562
|
asset_label = cast(tuple[str, str], self.tsdf.iloc[:, asset_column].name)[0]
|
1548
1563
|
beta_label = f"{asset_label} / {market_label}"
|
1549
1564
|
|
1550
|
-
rolling =
|
1551
|
-
|
1552
|
-
|
1565
|
+
rolling = (
|
1566
|
+
self.tsdf.ffill()
|
1567
|
+
.pct_change()
|
1568
|
+
.rolling(
|
1569
|
+
observations,
|
1570
|
+
min_periods=observations,
|
1571
|
+
)
|
1553
1572
|
)
|
1554
1573
|
|
1555
1574
|
rcov = rolling.cov(ddof=dlta_degr_freedms)
|
@@ -1604,10 +1623,11 @@ class OpenFrame(_CommonModel):
|
|
1604
1623
|
)
|
1605
1624
|
first_series = (
|
1606
1625
|
self.tsdf.iloc[:, first_column]
|
1626
|
+
.ffill()
|
1607
1627
|
.pct_change()[1:]
|
1608
1628
|
.rolling(observations, min_periods=observations)
|
1609
1629
|
)
|
1610
|
-
second_series = self.tsdf.iloc[:, second_column].pct_change()[1:]
|
1630
|
+
second_series = self.tsdf.iloc[:, second_column].ffill().pct_change()[1:]
|
1611
1631
|
corrdf = first_series.corr(other=second_series).dropna().to_frame()
|
1612
1632
|
corrdf.columns = MultiIndex.from_arrays(
|
1613
1633
|
[
|
@@ -308,7 +308,7 @@ def efficient_frontier( # noqa: C901
|
|
308
308
|
|
309
309
|
if tweak:
|
310
310
|
limit_tweak = 0.001
|
311
|
-
line_df["stdev_diff"] = line_df.stdev.pct_change()
|
311
|
+
line_df["stdev_diff"] = line_df.stdev.ffill().pct_change()
|
312
312
|
line_df = line_df.loc[line_df.stdev_diff.abs() > limit_tweak]
|
313
313
|
line_df = line_df.drop(columns="stdev_diff")
|
314
314
|
|
@@ -687,7 +687,7 @@ class OpenTimeSeries(_CommonModel):
|
|
687
687
|
returns_input = True
|
688
688
|
else:
|
689
689
|
values = [cast(float, self.tsdf.iloc[0, 0])]
|
690
|
-
ra_df = self.tsdf.pct_change()
|
690
|
+
ra_df = self.tsdf.ffill().pct_change()
|
691
691
|
returns_input = False
|
692
692
|
ra_df = ra_df.dropna()
|
693
693
|
|
@@ -122,7 +122,9 @@ class ReturnSimulation(BaseModel):
|
|
122
122
|
"""
|
123
123
|
return cast(
|
124
124
|
float,
|
125
|
-
(
|
125
|
+
(
|
126
|
+
self.results.ffill().pct_change().mean() * self.trading_days_in_year
|
127
|
+
).iloc[0],
|
126
128
|
)
|
127
129
|
|
128
130
|
@property
|
@@ -137,9 +139,10 @@ class ReturnSimulation(BaseModel):
|
|
137
139
|
"""
|
138
140
|
return cast(
|
139
141
|
float,
|
140
|
-
(
|
141
|
-
|
142
|
-
|
142
|
+
(
|
143
|
+
self.results.ffill().pct_change().std()
|
144
|
+
* sqrt(self.trading_days_in_year)
|
145
|
+
).iloc[0],
|
143
146
|
)
|
144
147
|
|
145
148
|
@classmethod
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[tool.poetry]
|
2
2
|
name = "openseries"
|
3
|
-
version = "1.7.
|
3
|
+
version = "1.7.6"
|
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"
|
@@ -34,32 +34,32 @@ keywords = [
|
|
34
34
|
[tool.poetry.dependencies]
|
35
35
|
python = ">=3.10,<3.13"
|
36
36
|
holidays = ">=0.30,<1.0"
|
37
|
-
numpy = ">=1.23.2
|
37
|
+
numpy = ">=1.23.2,<3.0.0"
|
38
38
|
openpyxl = ">=3.1.2,<4.0.0"
|
39
39
|
pandas = ">=2.1.2,<3.0.0"
|
40
40
|
plotly = ">=5.18.0,<6.0.0"
|
41
|
-
pyarrow = ">=14.0.2,<
|
41
|
+
pyarrow = ">=14.0.2,<19.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
45
|
scipy = ">=1.11.4,<2.0.0"
|
46
|
-
statsmodels = ">=0.14.0,<1.0.0"
|
46
|
+
statsmodels = ">=0.14.0,!=0.14.2,<1.0.0"
|
47
47
|
|
48
48
|
[tool.poetry.group.dev.dependencies]
|
49
49
|
black = ">=24.4.2,<25.0.0"
|
50
|
-
coverage = "
|
50
|
+
coverage = "^7.6.4"
|
51
51
|
genbadge = {version = ">=1.1.1,<2.0.0", extras = ["coverage"]}
|
52
|
-
mypy = "^1.
|
52
|
+
mypy = "^1.13.0"
|
53
53
|
pandas-stubs = ">=2.1.2,<3.0.0"
|
54
54
|
pre-commit = ">=3.7.1,<6.0.0"
|
55
55
|
pytest = ">=8.2.2,<9.0.0"
|
56
|
-
ruff = "^0.
|
56
|
+
ruff = "^0.7.1"
|
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"
|
60
60
|
|
61
61
|
[build-system]
|
62
|
-
requires = ["poetry-core>=1.8.
|
62
|
+
requires = ["poetry-core>=1.8.4"]
|
63
63
|
build-backend = "poetry.core.masonry.api"
|
64
64
|
|
65
65
|
[tool.coverage.run]
|
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
|