openseries 1.4.11__tar.gz → 1.4.12__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.1
2
2
  Name: openseries
3
- Version: 1.4.11
3
+ Version: 1.4.12
4
4
  Summary: Package for analyzing financial timeseries.
5
5
  Home-page: https://github.com/CaptorAB/OpenSeries
6
6
  License: BSD-3-Clause
@@ -1,4 +1,5 @@
1
1
  """Defining the _CommonModel class."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  import datetime as dt
@@ -484,7 +485,7 @@ class _CommonModel(BaseModel):
484
485
  if any([months_offset, from_dt, to_dt]):
485
486
  if months_offset is not None:
486
487
  earlier = date_offset_foll(
487
- raw_date=self.tsdf.index[-1],
488
+ raw_date=DatetimeIndex(self.tsdf.index)[-1],
488
489
  months_offset=-months_offset,
489
490
  adjust=False,
490
491
  following=True,
@@ -537,8 +538,8 @@ class _CommonModel(BaseModel):
537
538
  An OpenFrame object
538
539
 
539
540
  """
540
- startyear = self.tsdf.index[0].year
541
- endyear = self.tsdf.index[-1].year
541
+ startyear = DatetimeIndex(self.tsdf.index)[0].year
542
+ endyear = DatetimeIndex(self.tsdf.index)[-1].year
542
543
  calendar = holiday_calendar(
543
544
  startyear=startyear,
544
545
  endyear=endyear,
@@ -1514,24 +1515,20 @@ class _CommonModel(BaseModel):
1514
1515
  )
1515
1516
  fraction = (later - earlier).days / 365.25
1516
1517
 
1517
- if (
1518
- zero in self.tsdf.loc[earlier].tolist()
1519
- or self.tsdf.loc[[earlier, later]].lt(0.0).any().any()
1520
- ):
1518
+ any_below_zero = any(self.tsdf.loc[[earlier, later]].lt(0.0).any().to_numpy())
1519
+ if zero in self.tsdf.loc[earlier].to_numpy() or any_below_zero:
1521
1520
  msg = (
1522
1521
  "Geometric return cannot be calculated due to "
1523
1522
  "an initial value being zero or a negative value."
1524
1523
  )
1525
- raise ValueError(
1526
- msg,
1527
- )
1524
+ raise ValueError(msg)
1528
1525
 
1529
1526
  result = (self.tsdf.loc[later] / self.tsdf.loc[earlier]) ** (1 / fraction) - 1
1530
1527
 
1531
1528
  if self.tsdf.shape[1] == 1:
1532
1529
  return float(result.iloc[0])
1533
1530
  return Series(
1534
- data=result,
1531
+ data=result.to_numpy(),
1535
1532
  index=self.tsdf.columns,
1536
1533
  name="Geometric return",
1537
1534
  dtype="float64",
@@ -1917,7 +1914,7 @@ class _CommonModel(BaseModel):
1917
1914
  if self.tsdf.shape[1] == 1:
1918
1915
  return float(result.iloc[0])
1919
1916
  return Series(
1920
- data=result,
1917
+ data=result.to_numpy(),
1921
1918
  index=self.tsdf.columns,
1922
1919
  name="Simple return",
1923
1920
  dtype="float64",
@@ -168,6 +168,7 @@ class OpenFrame(_CommonModel):
168
168
  An OpenFrame object
169
169
 
170
170
  """
171
+ lvl_zero = list(self.columns_lvl_zero)
171
172
  self.tsdf = reduce(
172
173
  lambda left, right: merge(
173
174
  left=left,
@@ -178,14 +179,17 @@ class OpenFrame(_CommonModel):
178
179
  ),
179
180
  [x.tsdf for x in self.constituents],
180
181
  )
182
+
183
+ mapper = dict(zip(self.columns_lvl_zero, lvl_zero))
184
+ self.tsdf = self.tsdf.rename(columns=mapper, level=0)
185
+
181
186
  if self.tsdf.empty:
182
187
  msg = (
183
188
  "Merging OpenTimeSeries DataFrames with "
184
189
  f"argument how={how} produced an empty DataFrame."
185
190
  )
186
- raise ValueError(
187
- msg,
188
- )
191
+ raise ValueError(msg)
192
+
189
193
  if how == "inner":
190
194
  for xerie in self.constituents:
191
195
  xerie.tsdf = xerie.tsdf.loc[self.tsdf.index]
@@ -454,8 +458,8 @@ class OpenFrame(_CommonModel):
454
458
  tail = self.tsdf.loc[self.last_indices.min()].copy()
455
459
  dates = do_resample_to_business_period_ends(
456
460
  data=self.tsdf,
457
- head=head,
458
- tail=tail,
461
+ head=head, # type: ignore[arg-type]
462
+ tail=tail, # type: ignore[arg-type]
459
463
  freq=freq,
460
464
  countries=countries,
461
465
  )
@@ -1046,9 +1050,7 @@ class OpenFrame(_CommonModel):
1046
1050
  .add(1)
1047
1051
  .to_numpy()
1048
1052
  )
1049
- up_return = (
1050
- uparray.prod() ** (1 / (len(uparray) / time_factor)) - 1
1051
- )
1053
+ up_rtrn = uparray.prod() ** (1 / (len(uparray) / time_factor)) - 1
1052
1054
  upidxarray = (
1053
1055
  shortdf.pct_change(fill_method=cast(str, None))[
1054
1056
  shortdf.pct_change(fill_method=cast(str, None)).to_numpy()
@@ -1060,7 +1062,7 @@ class OpenFrame(_CommonModel):
1060
1062
  up_idx_return = (
1061
1063
  upidxarray.prod() ** (1 / (len(upidxarray) / time_factor)) - 1
1062
1064
  )
1063
- ratios.append(up_return / up_idx_return)
1065
+ ratios.append(up_rtrn / up_idx_return)
1064
1066
  elif ratio == "down":
1065
1067
  downarray = (
1066
1068
  longdf.pct_change(fill_method=cast(str, None))[
@@ -1095,9 +1097,7 @@ class OpenFrame(_CommonModel):
1095
1097
  .add(1)
1096
1098
  .to_numpy()
1097
1099
  )
1098
- up_return = (
1099
- uparray.prod() ** (1 / (len(uparray) / time_factor)) - 1
1100
- )
1100
+ up_rtrn = uparray.prod() ** (1 / (len(uparray) / time_factor)) - 1
1101
1101
  upidxarray = (
1102
1102
  shortdf.pct_change(fill_method=cast(str, None))[
1103
1103
  shortdf.pct_change(fill_method=cast(str, None)).to_numpy()
@@ -1133,7 +1133,7 @@ class OpenFrame(_CommonModel):
1133
1133
  - 1
1134
1134
  )
1135
1135
  ratios.append(
1136
- (up_return / up_idx_return) / (down_return / down_idx_return),
1136
+ (up_rtrn / up_idx_return) / (down_return / down_idx_return),
1137
1137
  )
1138
1138
 
1139
1139
  if ratio == "up":
@@ -1154,6 +1154,7 @@ class OpenFrame(_CommonModel):
1154
1154
  self: Self,
1155
1155
  asset: Union[tuple[str, ValueType], int],
1156
1156
  market: Union[tuple[str, ValueType], int],
1157
+ dlta_degr_freedms: int = 1,
1157
1158
  ) -> float:
1158
1159
  """
1159
1160
  Market Beta.
@@ -1167,6 +1168,8 @@ class OpenFrame(_CommonModel):
1167
1168
  The column of the asset
1168
1169
  market: Union[tuple[str, ValueType], int]
1169
1170
  The column of the market against which Beta is measured
1171
+ dlta_degr_freedms: int, default: 1
1172
+ Variance bias factor taking the value 0 or 1.
1170
1173
 
1171
1174
  Returns
1172
1175
  -------
@@ -1224,7 +1227,7 @@ class OpenFrame(_CommonModel):
1224
1227
  msg,
1225
1228
  )
1226
1229
 
1227
- covariance = cov(y_value, x_value, ddof=1)
1230
+ covariance = cov(y_value, x_value, ddof=dlta_degr_freedms)
1228
1231
  beta = covariance[0, 1] / covariance[1, 1]
1229
1232
 
1230
1233
  return float(beta)
@@ -1305,6 +1308,7 @@ class OpenFrame(_CommonModel):
1305
1308
  asset: Union[tuple[str, ValueType], int],
1306
1309
  market: Union[tuple[str, ValueType], int],
1307
1310
  riskfree_rate: float = 0.0,
1311
+ dlta_degr_freedms: int = 1,
1308
1312
  ) -> float:
1309
1313
  """
1310
1314
  Jensen's alpha.
@@ -1324,6 +1328,8 @@ class OpenFrame(_CommonModel):
1324
1328
  The column of the market against which Jensen's alpha is measured
1325
1329
  riskfree_rate : float, default: 0.0
1326
1330
  The return of the zero volatility riskfree asset
1331
+ dlta_degr_freedms: int, default: 1
1332
+ Variance bias factor taking the value 0 or 1.
1327
1333
 
1328
1334
  Returns
1329
1335
  -------
@@ -1430,7 +1436,7 @@ class OpenFrame(_CommonModel):
1430
1436
  msg,
1431
1437
  )
1432
1438
 
1433
- covariance = cov(asset_log, market_log, ddof=1)
1439
+ covariance = cov(asset_log, market_log, ddof=dlta_degr_freedms)
1434
1440
  beta = covariance[0, 1] / covariance[1, 1]
1435
1441
 
1436
1442
  return float(asset_cagr - riskfree_rate - beta * (market_cagr - riskfree_rate))
@@ -1609,6 +1615,7 @@ class OpenFrame(_CommonModel):
1609
1615
  asset_column: int = 0,
1610
1616
  market_column: int = 1,
1611
1617
  observations: int = 21,
1618
+ dlta_degr_freedms: int = 1,
1612
1619
  ) -> DataFrame:
1613
1620
  """
1614
1621
  Calculate rolling Market Beta.
@@ -1624,6 +1631,8 @@ class OpenFrame(_CommonModel):
1624
1631
  Column of timeseries that is the market.
1625
1632
  observations: int, default: 21
1626
1633
  The length of the rolling window to use is set as number of observations.
1634
+ dlta_degr_freedms: int, default: 1
1635
+ Variance bias factor taking the value 0 or 1.
1627
1636
 
1628
1637
  Returns
1629
1638
  -------
@@ -1635,13 +1644,13 @@ class OpenFrame(_CommonModel):
1635
1644
  asset_label = cast(tuple[str, str], self.tsdf.iloc[:, asset_column].name)[0]
1636
1645
  beta_label = f"{asset_label} / {market_label}"
1637
1646
 
1638
- rolling = self.tsdf.copy()
1647
+ rolling: DataFrame = self.tsdf.copy()
1639
1648
  rolling = rolling.pct_change(fill_method=cast(str, None)).rolling(
1640
1649
  observations,
1641
1650
  min_periods=observations,
1642
1651
  )
1643
1652
 
1644
- rcov = rolling.cov()
1653
+ rcov = rolling.cov(ddof=dlta_degr_freedms)
1645
1654
  rcov = rcov.dropna()
1646
1655
 
1647
1656
  rollbetaseries = rcov.iloc[:, asset_column].xs(
@@ -1692,17 +1701,15 @@ class OpenFrame(_CommonModel):
1692
1701
  + "_VS_"
1693
1702
  + cast(tuple[str, str], self.tsdf.iloc[:, second_column].name)[0]
1694
1703
  )
1695
- corrseries = (
1704
+ first_series = (
1696
1705
  self.tsdf.iloc[:, first_column]
1697
1706
  .pct_change(fill_method=cast(str, None))[1:]
1698
1707
  .rolling(observations, min_periods=observations)
1699
- .corr(
1700
- self.tsdf.iloc[:, second_column].pct_change(
1701
- fill_method=cast(str, None),
1702
- )[1:],
1703
- )
1704
1708
  )
1705
- corrdf = corrseries.dropna().to_frame()
1709
+ second_series = self.tsdf.iloc[:, second_column].pct_change(
1710
+ fill_method=cast(str, None),
1711
+ )[1:]
1712
+ corrdf = first_series.corr(other=second_series).dropna().to_frame()
1706
1713
  corrdf.columns = MultiIndex.from_arrays(
1707
1714
  [
1708
1715
  [corr_label],
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "openseries"
3
- version = "1.4.11"
3
+ version = "1.4.12"
4
4
  description = "Package for analyzing financial timeseries."
5
5
  authors = ["Martin Karrin <martin.karrin@captor.se>"]
6
6
  repository = "https://github.com/CaptorAB/OpenSeries"
@@ -51,13 +51,13 @@ coverage = "^7.4.1"
51
51
  coverage-badge = "^1.1.0"
52
52
  mypy = "^1.8.0"
53
53
  pre-commit = "^3.6.1"
54
- pytest = "^8.0.0"
55
- ruff = "^0.2.1"
54
+ pytest = "^8.0.1"
55
+ ruff = "^0.2.2"
56
56
  toml = "^0.10.2"
57
57
  types-openpyxl = "^3.1.0.20240205"
58
58
  pandas-stubs = "^2.1.4.231227"
59
59
  types-python-dateutil = "^2.8.19.20240106"
60
- types-requests = "^2.31.0.20240125"
60
+ types-requests = "^2.31.0.20240218"
61
61
  types-toml = "^0.10.8.7"
62
62
 
63
63
  [build-system]
File without changes
File without changes