openseries 1.6.0__py3-none-any.whl → 1.7.1__py3-none-any.whl

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/frame.py CHANGED
@@ -1,13 +1,15 @@
1
1
  """Defining the OpenFrame class."""
2
2
 
3
- # mypy: disable-error-code="index,assignment"
3
+ # mypy: disable-error-code="index,assignment,arg-type"
4
4
  from __future__ import annotations
5
5
 
6
- import datetime as dt
7
6
  from copy import deepcopy
8
7
  from functools import reduce
9
8
  from logging import warning
10
- from typing import Optional, Union, cast
9
+ from typing import TYPE_CHECKING, cast
10
+
11
+ if TYPE_CHECKING:
12
+ import datetime as dt # pragma: no cover
11
13
 
12
14
  import statsmodels.api as sm # type: ignore[import-untyped,unused-ignore]
13
15
  from numpy import (
@@ -40,10 +42,10 @@ from statsmodels.regression.linear_model import ( # type: ignore[import-untyped
40
42
  )
41
43
  from typing_extensions import Self
42
44
 
43
- from openseries._common_model import _CommonModel
44
- from openseries.datefixer import do_resample_to_business_period_ends
45
- from openseries.series import OpenTimeSeries
46
- from openseries.types import (
45
+ from ._common_model import _CommonModel
46
+ from .datefixer import _do_resample_to_business_period_ends
47
+ from .series import OpenTimeSeries
48
+ from .types import (
47
49
  CountriesType,
48
50
  DaysInYearType,
49
51
  LiteralBizDayFreq,
@@ -62,11 +64,9 @@ from openseries.types import (
62
64
  __all__ = ["OpenFrame"]
63
65
 
64
66
 
65
- # noinspection PyUnresolvedReferences
67
+ # noinspection PyUnresolvedReferences,PyTypeChecker
66
68
  class OpenFrame(_CommonModel):
67
-
68
- """
69
- OpenFrame objects hold OpenTimeSeries in the list constituents.
69
+ """OpenFrame objects hold OpenTimeSeries in the list constituents.
70
70
 
71
71
  The intended use is to allow comparisons across these timeseries.
72
72
 
@@ -86,7 +86,7 @@ class OpenFrame(_CommonModel):
86
86
 
87
87
  constituents: list[OpenTimeSeries]
88
88
  tsdf: DataFrame = DataFrame(dtype="float64")
89
- weights: Optional[list[float]] = None
89
+ weights: list[float] | None = None
90
90
 
91
91
  # noinspection PyMethodParameters
92
92
  @field_validator("constituents") # type: ignore[misc]
@@ -104,10 +104,9 @@ class OpenFrame(_CommonModel):
104
104
  def __init__(
105
105
  self: Self,
106
106
  constituents: list[OpenTimeSeries],
107
- weights: Optional[list[float]] = None,
107
+ weights: list[float] | None = None,
108
108
  ) -> None:
109
- """
110
- OpenFrame objects hold OpenTimeSeries in the list constituents.
109
+ """OpenFrame objects hold OpenTimeSeries in the list constituents.
111
110
 
112
111
  The intended use is to allow comparisons across these timeseries.
113
112
 
@@ -144,8 +143,7 @@ class OpenFrame(_CommonModel):
144
143
  warning("OpenFrame() was passed an empty list.")
145
144
 
146
145
  def from_deepcopy(self: Self) -> Self:
147
- """
148
- Create copy of the OpenFrame object.
146
+ """Create copy of the OpenFrame object.
149
147
 
150
148
  Returns
151
149
  -------
@@ -159,8 +157,7 @@ class OpenFrame(_CommonModel):
159
157
  self: Self,
160
158
  how: LiteralHowMerge = "outer",
161
159
  ) -> Self:
162
- """
163
- Merge index of Pandas Dataframes of the constituent OpenTimeSeries.
160
+ """Merge index of Pandas Dataframes of the constituent OpenTimeSeries.
164
161
 
165
162
  Parameters
166
163
  ----------
@@ -202,10 +199,9 @@ class OpenFrame(_CommonModel):
202
199
 
203
200
  def all_properties(
204
201
  self: Self,
205
- properties: Optional[list[LiteralFrameProps]] = None,
202
+ properties: list[LiteralFrameProps] | None = None,
206
203
  ) -> DataFrame:
207
- """
208
- Calculate chosen timeseries properties.
204
+ """Calculate chosen timeseries properties.
209
205
 
210
206
  Parameters
211
207
  ----------
@@ -229,8 +225,7 @@ class OpenFrame(_CommonModel):
229
225
 
230
226
  @property
231
227
  def lengths_of_items(self: Self) -> Series[int]:
232
- """
233
- Number of observations of all constituents.
228
+ """Number of observations of all constituents.
234
229
 
235
230
  Returns
236
231
  -------
@@ -247,8 +242,7 @@ class OpenFrame(_CommonModel):
247
242
 
248
243
  @property
249
244
  def item_count(self: Self) -> int:
250
- """
251
- Number of constituents.
245
+ """Number of constituents.
252
246
 
253
247
  Returns
254
248
  -------
@@ -260,8 +254,7 @@ class OpenFrame(_CommonModel):
260
254
 
261
255
  @property
262
256
  def columns_lvl_zero(self: Self) -> list[str]:
263
- """
264
- Level 0 values of the MultiIndex columns in the .tsdf DataFrame.
257
+ """Level 0 values of the MultiIndex columns in the .tsdf DataFrame.
265
258
 
266
259
  Returns
267
260
  -------
@@ -273,8 +266,7 @@ class OpenFrame(_CommonModel):
273
266
 
274
267
  @property
275
268
  def columns_lvl_one(self: Self) -> list[ValueType]:
276
- """
277
- Level 1 values of the MultiIndex columns in the .tsdf DataFrame.
269
+ """Level 1 values of the MultiIndex columns in the .tsdf DataFrame.
278
270
 
279
271
  Returns
280
272
  -------
@@ -286,8 +278,7 @@ class OpenFrame(_CommonModel):
286
278
 
287
279
  @property
288
280
  def first_indices(self: Self) -> Series[dt.date]:
289
- """
290
- The first dates in the timeseries of all constituents.
281
+ """The first dates in the timeseries of all constituents.
291
282
 
292
283
  Returns
293
284
  -------
@@ -304,8 +295,7 @@ class OpenFrame(_CommonModel):
304
295
 
305
296
  @property
306
297
  def last_indices(self: Self) -> Series[dt.date]:
307
- """
308
- The last dates in the timeseries of all constituents.
298
+ """The last dates in the timeseries of all constituents.
309
299
 
310
300
  Returns
311
301
  -------
@@ -322,8 +312,7 @@ class OpenFrame(_CommonModel):
322
312
 
323
313
  @property
324
314
  def span_of_days_all(self: Self) -> Series[int]:
325
- """
326
- Number of days from the first date to the last for all items in the frame.
315
+ """Number of days from the first date to the last for all items in the frame.
327
316
 
328
317
  Returns
329
318
  -------
@@ -340,8 +329,7 @@ class OpenFrame(_CommonModel):
340
329
  )
341
330
 
342
331
  def value_to_ret(self: Self) -> Self:
343
- """
344
- Convert series of values into series of returns.
332
+ """Convert series of values into series of returns.
345
333
 
346
334
  Returns
347
335
  -------
@@ -349,7 +337,7 @@ class OpenFrame(_CommonModel):
349
337
  The returns of the values in the series
350
338
 
351
339
  """
352
- self.tsdf = self.tsdf.pct_change(fill_method=cast(str, None))
340
+ self.tsdf = self.tsdf.pct_change(fill_method=None)
353
341
  self.tsdf.iloc[0] = 0
354
342
  new_labels = [ValueType.RTRN] * self.item_count
355
343
  arrays = [self.tsdf.columns.get_level_values(0), new_labels]
@@ -357,8 +345,7 @@ class OpenFrame(_CommonModel):
357
345
  return self
358
346
 
359
347
  def value_to_diff(self: Self, periods: int = 1) -> Self:
360
- """
361
- Convert series of values to series of their period differences.
348
+ """Convert series of values to series of their period differences.
362
349
 
363
350
  Parameters
364
351
  ----------
@@ -380,8 +367,7 @@ class OpenFrame(_CommonModel):
380
367
  return self
381
368
 
382
369
  def to_cumret(self: Self) -> Self:
383
- """
384
- Convert series of returns into cumulative series of values.
370
+ """Convert series of returns into cumulative series of values.
385
371
 
386
372
  Returns
387
373
  -------
@@ -404,14 +390,13 @@ class OpenFrame(_CommonModel):
404
390
 
405
391
  def resample(
406
392
  self: Self,
407
- freq: Union[LiteralBizDayFreq, str] = "BME",
393
+ freq: LiteralBizDayFreq | str = "BME",
408
394
  ) -> Self:
409
- """
410
- Resample the timeseries frequency.
395
+ """Resample the timeseries frequency.
411
396
 
412
397
  Parameters
413
398
  ----------
414
- freq: Union[LiteralBizDayFreq, str], default "BME"
399
+ freq: LiteralBizDayFreq | str, default "BME"
415
400
  The date offset string that sets the resampled frequency
416
401
 
417
402
  Returns
@@ -438,8 +423,7 @@ class OpenFrame(_CommonModel):
438
423
  countries: CountriesType = "SE",
439
424
  method: LiteralPandasReindexMethod = "nearest",
440
425
  ) -> Self:
441
- """
442
- Resamples timeseries frequency to the business calendar month end dates.
426
+ """Resamples timeseries frequency to the business calendar month end dates.
443
427
 
444
428
  Stubs left in place. Stubs will be aligned to the shortest stub.
445
429
 
@@ -459,21 +443,18 @@ class OpenFrame(_CommonModel):
459
443
  An OpenFrame object
460
444
 
461
445
  """
462
- head: Series[float] = self.tsdf.loc[self.first_indices.max()].copy()
463
- tail: Series[float] = self.tsdf.loc[self.last_indices.min()].copy()
464
- dates = do_resample_to_business_period_ends(
465
- data=self.tsdf,
466
- head=head,
467
- tail=tail,
468
- freq=freq,
469
- countries=countries,
470
- )
471
- self.tsdf = self.tsdf.reindex([deyt.date() for deyt in dates], method=method)
472
446
  for xerie in self.constituents:
447
+ dates = _do_resample_to_business_period_ends(
448
+ data=xerie.tsdf,
449
+ freq=freq,
450
+ countries=countries,
451
+ )
473
452
  xerie.tsdf = xerie.tsdf.reindex(
474
- [deyt.date() for deyt in dates],
475
- method=method,
453
+ [deyt.date() for deyt in dates], method=method,
476
454
  )
455
+
456
+ self._set_tsdf()
457
+
477
458
  return self
478
459
 
479
460
  def ewma_risk(
@@ -483,13 +464,12 @@ class OpenFrame(_CommonModel):
483
464
  dlta_degr_freedms: int = 0,
484
465
  first_column: int = 0,
485
466
  second_column: int = 1,
486
- months_from_last: Optional[int] = None,
487
- from_date: Optional[dt.date] = None,
488
- to_date: Optional[dt.date] = None,
489
- periods_in_a_year_fixed: Optional[DaysInYearType] = None,
467
+ months_from_last: int | None = None,
468
+ from_date: dt.date | None = None,
469
+ to_date: dt.date | None = None,
470
+ periods_in_a_year_fixed: DaysInYearType | None = None,
490
471
  ) -> DataFrame:
491
- """
492
- Exponentially Weighted Moving Average Volatilities and Correlation.
472
+ """Exponentially Weighted Moving Average Volatilities and Correlation.
493
473
 
494
474
  Exponentially Weighted Moving Average (EWMA) for Volatilities and
495
475
  Correlation. https://www.investopedia.com/articles/07/ewma.asp.
@@ -601,8 +581,7 @@ class OpenFrame(_CommonModel):
601
581
 
602
582
  @property
603
583
  def correl_matrix(self: Self) -> DataFrame:
604
- """
605
- Correlation matrix.
584
+ """Correlation matrix.
606
585
 
607
586
  Returns
608
587
  -------
@@ -610,7 +589,7 @@ class OpenFrame(_CommonModel):
610
589
  Correlation matrix
611
590
 
612
591
  """
613
- corr_matrix = self.tsdf.pct_change(fill_method=cast(str, None)).corr(
592
+ corr_matrix = self.tsdf.pct_change(fill_method=None).corr(
614
593
  method="pearson",
615
594
  min_periods=1,
616
595
  )
@@ -623,8 +602,7 @@ class OpenFrame(_CommonModel):
623
602
  self: Self,
624
603
  new_series: OpenTimeSeries,
625
604
  ) -> Self:
626
- """
627
- To add an OpenTimeSeries object.
605
+ """To add an OpenTimeSeries object.
628
606
 
629
607
  Parameters
630
608
  ----------
@@ -643,8 +621,7 @@ class OpenFrame(_CommonModel):
643
621
  return self
644
622
 
645
623
  def delete_timeseries(self: Self, lvl_zero_item: str) -> Self:
646
- """
647
- To delete an OpenTimeSeries object.
624
+ """To delete an OpenTimeSeries object.
648
625
 
649
626
  Parameters
650
627
  ----------
@@ -674,12 +651,11 @@ class OpenFrame(_CommonModel):
674
651
 
675
652
  def trunc_frame(
676
653
  self: Self,
677
- start_cut: Optional[dt.date] = None,
678
- end_cut: Optional[dt.date] = None,
654
+ start_cut: dt.date | None = None,
655
+ end_cut: dt.date | None = None,
679
656
  where: LiteralTrunc = "both",
680
657
  ) -> Self:
681
- """
682
- Truncate DataFrame such that all timeseries have the same time span.
658
+ """Truncate DataFrame such that all timeseries have the same time span.
683
659
 
684
660
  Parameters
685
661
  ----------
@@ -733,8 +709,7 @@ class OpenFrame(_CommonModel):
733
709
  *,
734
710
  base_zero: bool = True,
735
711
  ) -> None:
736
- """
737
- Calculate cumulative relative return between two series.
712
+ """Calculate cumulative relative return between two series.
738
713
 
739
714
  Parameters
740
715
  ----------
@@ -766,14 +741,13 @@ class OpenFrame(_CommonModel):
766
741
 
767
742
  def tracking_error_func(
768
743
  self: Self,
769
- base_column: Union[tuple[str, ValueType], int] = -1,
770
- months_from_last: Optional[int] = None,
771
- from_date: Optional[dt.date] = None,
772
- to_date: Optional[dt.date] = None,
773
- periods_in_a_year_fixed: Optional[DaysInYearType] = None,
744
+ base_column: tuple[str, ValueType] | int = -1,
745
+ months_from_last: int | None = None,
746
+ from_date: dt.date | None = None,
747
+ to_date: dt.date | None = None,
748
+ periods_in_a_year_fixed: DaysInYearType | None = None,
774
749
  ) -> Series[float]:
775
- """
776
- Tracking Error.
750
+ """Tracking Error.
777
751
 
778
752
  Calculates Tracking Error which is the standard deviation of the
779
753
  difference between the fund and its index returns.
@@ -781,7 +755,7 @@ class OpenFrame(_CommonModel):
781
755
 
782
756
  Parameters
783
757
  ----------
784
- base_column: Union[tuple[str, ValueType], int], default: -1
758
+ base_column: tuple[str, ValueType] | int, default: -1
785
759
  Column of timeseries that is the denominator in the ratio.
786
760
  months_from_last : int, optional
787
761
  number of months offset as positive integer. Overrides use of from_date
@@ -846,8 +820,7 @@ class OpenFrame(_CommonModel):
846
820
  # noinspection PyTypeChecker
847
821
  relative = 1.0 + longdf - shortdf
848
822
  vol = float(
849
- relative.pct_change(fill_method=cast(str, None)).std()
850
- * sqrt(time_factor),
823
+ relative.pct_change(fill_method=None).std() * sqrt(time_factor),
851
824
  )
852
825
  terrors.append(vol)
853
826
 
@@ -860,14 +833,13 @@ class OpenFrame(_CommonModel):
860
833
 
861
834
  def info_ratio_func(
862
835
  self: Self,
863
- base_column: Union[tuple[str, ValueType], int] = -1,
864
- months_from_last: Optional[int] = None,
865
- from_date: Optional[dt.date] = None,
866
- to_date: Optional[dt.date] = None,
867
- periods_in_a_year_fixed: Optional[DaysInYearType] = None,
836
+ base_column: tuple[str, ValueType] | int = -1,
837
+ months_from_last: int | None = None,
838
+ from_date: dt.date | None = None,
839
+ to_date: dt.date | None = None,
840
+ periods_in_a_year_fixed: DaysInYearType | None = None,
868
841
  ) -> Series[float]:
869
- """
870
- Information Ratio.
842
+ """Information Ratio.
871
843
 
872
844
  The Information Ratio equals ( fund return less index return ) divided
873
845
  by the Tracking Error. And the Tracking Error is the standard deviation of
@@ -876,7 +848,7 @@ class OpenFrame(_CommonModel):
876
848
 
877
849
  Parameters
878
850
  ----------
879
- base_column: Union[tuple[str, ValueType], int], default: -1
851
+ base_column: tuple[str, ValueType] | int, default: -1
880
852
  Column of timeseries that is the denominator in the ratio.
881
853
  months_from_last : int, optional
882
854
  number of months offset as positive integer. Overrides use of from_date
@@ -941,12 +913,10 @@ class OpenFrame(_CommonModel):
941
913
  # noinspection PyTypeChecker
942
914
  relative = 1.0 + longdf - shortdf
943
915
  ret = float(
944
- relative.pct_change(fill_method=cast(str, None)).mean()
945
- * time_factor,
916
+ relative.pct_change(fill_method=None).mean() * time_factor,
946
917
  )
947
918
  vol = float(
948
- relative.pct_change(fill_method=cast(str, None)).std()
949
- * sqrt(time_factor),
919
+ relative.pct_change(fill_method=None).std() * sqrt(time_factor),
950
920
  )
951
921
  ratios.append(ret / vol)
952
922
 
@@ -960,14 +930,13 @@ class OpenFrame(_CommonModel):
960
930
  def capture_ratio_func( # noqa: C901
961
931
  self: Self,
962
932
  ratio: LiteralCaptureRatio,
963
- base_column: Union[tuple[str, ValueType], int] = -1,
964
- months_from_last: Optional[int] = None,
965
- from_date: Optional[dt.date] = None,
966
- to_date: Optional[dt.date] = None,
967
- periods_in_a_year_fixed: Optional[DaysInYearType] = None,
933
+ base_column: tuple[str, ValueType] | int = -1,
934
+ months_from_last: int | None = None,
935
+ from_date: dt.date | None = None,
936
+ to_date: dt.date | None = None,
937
+ periods_in_a_year_fixed: DaysInYearType | None = None,
968
938
  ) -> Series[float]:
969
- """
970
- Capture Ratio.
939
+ """Capture Ratio.
971
940
 
972
941
  The Up (Down) Capture Ratio is calculated by dividing the CAGR
973
942
  of the asset during periods that the benchmark returns are positive (negative)
@@ -982,7 +951,7 @@ class OpenFrame(_CommonModel):
982
951
  ----------
983
952
  ratio: LiteralCaptureRatio
984
953
  The ratio to calculate
985
- base_column: Union[tuple[str, ValueType], int], default: -1
954
+ base_column: tuple[str, ValueType] | int, default: -1
986
955
  Column of timeseries that is the denominator in the ratio.
987
956
  months_from_last : int, optional
988
957
  number of months offset as positive integer. Overrides use of from_date
@@ -1047,8 +1016,8 @@ class OpenFrame(_CommonModel):
1047
1016
  ]
1048
1017
  if ratio == "up":
1049
1018
  uparray = (
1050
- longdf.pct_change(fill_method=cast(str, None))[
1051
- shortdf.pct_change(fill_method=cast(str, None)).to_numpy()
1019
+ longdf.pct_change(fill_method=None)[
1020
+ shortdf.pct_change(fill_method=None).to_numpy()
1052
1021
  > loss_limit
1053
1022
  ]
1054
1023
  .add(1)
@@ -1056,8 +1025,8 @@ class OpenFrame(_CommonModel):
1056
1025
  )
1057
1026
  up_rtrn = uparray.prod() ** (1 / (len(uparray) / time_factor)) - 1
1058
1027
  upidxarray = (
1059
- shortdf.pct_change(fill_method=cast(str, None))[
1060
- shortdf.pct_change(fill_method=cast(str, None)).to_numpy()
1028
+ shortdf.pct_change(fill_method=None)[
1029
+ shortdf.pct_change(fill_method=None).to_numpy()
1061
1030
  > loss_limit
1062
1031
  ]
1063
1032
  .add(1)
@@ -1069,8 +1038,8 @@ class OpenFrame(_CommonModel):
1069
1038
  ratios.append(up_rtrn / up_idx_return)
1070
1039
  elif ratio == "down":
1071
1040
  downarray = (
1072
- longdf.pct_change(fill_method=cast(str, None))[
1073
- shortdf.pct_change(fill_method=cast(str, None)).to_numpy()
1041
+ longdf.pct_change(fill_method=None)[
1042
+ shortdf.pct_change(fill_method=None).to_numpy()
1074
1043
  < loss_limit
1075
1044
  ]
1076
1045
  .add(1)
@@ -1080,8 +1049,8 @@ class OpenFrame(_CommonModel):
1080
1049
  downarray.prod() ** (1 / (len(downarray) / time_factor)) - 1
1081
1050
  )
1082
1051
  downidxarray = (
1083
- shortdf.pct_change(fill_method=cast(str, None))[
1084
- shortdf.pct_change(fill_method=cast(str, None)).to_numpy()
1052
+ shortdf.pct_change(fill_method=None)[
1053
+ shortdf.pct_change(fill_method=None).to_numpy()
1085
1054
  < loss_limit
1086
1055
  ]
1087
1056
  .add(1)
@@ -1094,8 +1063,8 @@ class OpenFrame(_CommonModel):
1094
1063
  ratios.append(down_return / down_idx_return)
1095
1064
  elif ratio == "both":
1096
1065
  uparray = (
1097
- longdf.pct_change(fill_method=cast(str, None))[
1098
- shortdf.pct_change(fill_method=cast(str, None)).to_numpy()
1066
+ longdf.pct_change(fill_method=None)[
1067
+ shortdf.pct_change(fill_method=None).to_numpy()
1099
1068
  > loss_limit
1100
1069
  ]
1101
1070
  .add(1)
@@ -1103,8 +1072,8 @@ class OpenFrame(_CommonModel):
1103
1072
  )
1104
1073
  up_rtrn = uparray.prod() ** (1 / (len(uparray) / time_factor)) - 1
1105
1074
  upidxarray = (
1106
- shortdf.pct_change(fill_method=cast(str, None))[
1107
- shortdf.pct_change(fill_method=cast(str, None)).to_numpy()
1075
+ shortdf.pct_change(fill_method=None)[
1076
+ shortdf.pct_change(fill_method=None).to_numpy()
1108
1077
  > loss_limit
1109
1078
  ]
1110
1079
  .add(1)
@@ -1114,8 +1083,8 @@ class OpenFrame(_CommonModel):
1114
1083
  upidxarray.prod() ** (1 / (len(upidxarray) / time_factor)) - 1
1115
1084
  )
1116
1085
  downarray = (
1117
- longdf.pct_change(fill_method=cast(str, None))[
1118
- shortdf.pct_change(fill_method=cast(str, None)).to_numpy()
1086
+ longdf.pct_change(fill_method=None)[
1087
+ shortdf.pct_change(fill_method=None).to_numpy()
1119
1088
  < loss_limit
1120
1089
  ]
1121
1090
  .add(1)
@@ -1125,8 +1094,8 @@ class OpenFrame(_CommonModel):
1125
1094
  downarray.prod() ** (1 / (len(downarray) / time_factor)) - 1
1126
1095
  )
1127
1096
  downidxarray = (
1128
- shortdf.pct_change(fill_method=cast(str, None))[
1129
- shortdf.pct_change(fill_method=cast(str, None)).to_numpy()
1097
+ shortdf.pct_change(fill_method=None)[
1098
+ shortdf.pct_change(fill_method=None).to_numpy()
1130
1099
  < loss_limit
1131
1100
  ]
1132
1101
  .add(1)
@@ -1139,6 +1108,9 @@ class OpenFrame(_CommonModel):
1139
1108
  ratios.append(
1140
1109
  (up_rtrn / up_idx_return) / (down_return / down_idx_return),
1141
1110
  )
1111
+ else:
1112
+ msg = "ratio must be one of 'up', 'down' or 'both'."
1113
+ raise ValueError(msg)
1142
1114
 
1143
1115
  if ratio == "up":
1144
1116
  resultname = f"Up Capture Ratios vs {short_label}"
@@ -1156,21 +1128,20 @@ class OpenFrame(_CommonModel):
1156
1128
 
1157
1129
  def beta(
1158
1130
  self: Self,
1159
- asset: Union[tuple[str, ValueType], int],
1160
- market: Union[tuple[str, ValueType], int],
1131
+ asset: tuple[str, ValueType] | int,
1132
+ market: tuple[str, ValueType] | int,
1161
1133
  dlta_degr_freedms: int = 1,
1162
1134
  ) -> float:
1163
- """
1164
- Market Beta.
1135
+ """Market Beta.
1165
1136
 
1166
1137
  Calculates Beta as Co-variance of asset & market divided by Variance
1167
1138
  of the market. https://www.investopedia.com/terms/b/beta.asp.
1168
1139
 
1169
1140
  Parameters
1170
1141
  ----------
1171
- asset: Union[tuple[str, ValueType], int]
1142
+ asset: tuple[str, ValueType] | int
1172
1143
  The column of the asset
1173
- market: Union[tuple[str, ValueType], int]
1144
+ market: tuple[str, ValueType] | int
1174
1145
  The column of the market against which Beta is measured
1175
1146
  dlta_degr_freedms: int, default: 1
1176
1147
  Variance bias factor taking the value 0 or 1.
@@ -1238,15 +1209,14 @@ class OpenFrame(_CommonModel):
1238
1209
 
1239
1210
  def ord_least_squares_fit(
1240
1211
  self: Self,
1241
- y_column: Union[tuple[str, ValueType], int],
1242
- x_column: Union[tuple[str, ValueType], int],
1212
+ y_column: tuple[str, ValueType] | int,
1213
+ x_column: tuple[str, ValueType] | int,
1243
1214
  method: LiteralOlsFitMethod = "pinv",
1244
1215
  cov_type: LiteralOlsFitCovType = "nonrobust",
1245
1216
  *,
1246
1217
  fitted_series: bool = True,
1247
1218
  ) -> OLSResults:
1248
- """
1249
- Ordinary Least Squares fit.
1219
+ """Ordinary Least Squares fit.
1250
1220
 
1251
1221
  Performs a linear regression and adds a new column with a fitted line
1252
1222
  using Ordinary Least Squares fit
@@ -1254,9 +1224,9 @@ class OpenFrame(_CommonModel):
1254
1224
 
1255
1225
  Parameters
1256
1226
  ----------
1257
- y_column: Union[tuple[str, ValueType], int]
1227
+ y_column: tuple[str, ValueType] | int
1258
1228
  The column level values of the dependent variable y
1259
- x_column: Union[tuple[str, ValueType], int]
1229
+ x_column: tuple[str, ValueType] | int
1260
1230
  The column level values of the exogenous variable x
1261
1231
  method: LiteralOlsFitMethod, default: pinv
1262
1232
  Method to solve least squares problem
@@ -1309,13 +1279,12 @@ class OpenFrame(_CommonModel):
1309
1279
 
1310
1280
  def jensen_alpha( # noqa: C901
1311
1281
  self: Self,
1312
- asset: Union[tuple[str, ValueType], int],
1313
- market: Union[tuple[str, ValueType], int],
1282
+ asset: tuple[str, ValueType] | int,
1283
+ market: tuple[str, ValueType] | int,
1314
1284
  riskfree_rate: float = 0.0,
1315
1285
  dlta_degr_freedms: int = 1,
1316
1286
  ) -> float:
1317
- """
1318
- Jensen's alpha.
1287
+ """Jensen's alpha.
1319
1288
 
1320
1289
  The Jensen's measure, or Jensen's alpha, is a risk-adjusted performance
1321
1290
  measure that represents the average return on a portfolio or investment,
@@ -1326,9 +1295,9 @@ class OpenFrame(_CommonModel):
1326
1295
 
1327
1296
  Parameters
1328
1297
  ----------
1329
- asset: Union[tuple[str, ValueType], int]
1298
+ asset: tuple[str, ValueType] | int
1330
1299
  The column of the asset
1331
- market: Union[tuple[str, ValueType], int]
1300
+ market: tuple[str, ValueType] | int
1332
1301
  The column of the market against which Jensen's alpha is measured
1333
1302
  riskfree_rate : float, default: 0.0
1334
1303
  The return of the zero volatility riskfree asset
@@ -1448,10 +1417,9 @@ class OpenFrame(_CommonModel):
1448
1417
  def make_portfolio(
1449
1418
  self: Self,
1450
1419
  name: str,
1451
- weight_strat: Optional[LiteralPortfolioWeightings] = None,
1420
+ weight_strat: LiteralPortfolioWeightings | None = None,
1452
1421
  ) -> DataFrame:
1453
- """
1454
- Calculate a basket timeseries based on the supplied weights.
1422
+ """Calculate a basket timeseries based on the supplied weights.
1455
1423
 
1456
1424
  Parameters
1457
1425
  ----------
@@ -1479,7 +1447,7 @@ class OpenFrame(_CommonModel):
1479
1447
  x == ValueType.RTRN
1480
1448
  for x in self.tsdf.columns.get_level_values(1).to_numpy()
1481
1449
  ):
1482
- dframe = dframe.pct_change(fill_method=cast(str, None))
1450
+ dframe = dframe.pct_change(fill_method=None)
1483
1451
  dframe.iloc[0] = 0
1484
1452
  if weight_strat:
1485
1453
  if weight_strat == "eq_weights":
@@ -1503,10 +1471,9 @@ class OpenFrame(_CommonModel):
1503
1471
  long_column: int = 0,
1504
1472
  short_column: int = 1,
1505
1473
  observations: int = 21,
1506
- periods_in_a_year_fixed: Optional[DaysInYearType] = None,
1474
+ periods_in_a_year_fixed: DaysInYearType | None = None,
1507
1475
  ) -> DataFrame:
1508
- """
1509
- Calculate rolling Information Ratio.
1476
+ """Calculate rolling Information Ratio.
1510
1477
 
1511
1478
  The Information Ratio equals ( fund return less index return ) divided by
1512
1479
  the Tracking Error. And the Tracking Error is the standard deviation of the
@@ -1548,13 +1515,13 @@ class OpenFrame(_CommonModel):
1548
1515
  )
1549
1516
 
1550
1517
  retseries = (
1551
- relative.pct_change(fill_method=cast(str, None))
1518
+ relative.pct_change(fill_method=None)
1552
1519
  .rolling(observations, min_periods=observations)
1553
1520
  .sum()
1554
1521
  )
1555
1522
  retdf = retseries.dropna().to_frame()
1556
1523
 
1557
- voldf = relative.pct_change(fill_method=cast(str, None)).rolling(
1524
+ voldf = relative.pct_change(fill_method=None).rolling(
1558
1525
  observations,
1559
1526
  min_periods=observations,
1560
1527
  ).std() * sqrt(time_factor)
@@ -1572,8 +1539,7 @@ class OpenFrame(_CommonModel):
1572
1539
  observations: int = 21,
1573
1540
  dlta_degr_freedms: int = 1,
1574
1541
  ) -> DataFrame:
1575
- """
1576
- Calculate rolling Market Beta.
1542
+ """Calculate rolling Market Beta.
1577
1543
 
1578
1544
  Calculates Beta as Co-variance of asset & market divided by Variance
1579
1545
  of the market. https://www.investopedia.com/terms/b/beta.asp.
@@ -1599,8 +1565,7 @@ class OpenFrame(_CommonModel):
1599
1565
  asset_label = cast(tuple[str, str], self.tsdf.iloc[:, asset_column].name)[0]
1600
1566
  beta_label = f"{asset_label} / {market_label}"
1601
1567
 
1602
- rolling: DataFrame = self.tsdf.copy()
1603
- rolling = rolling.pct_change(fill_method=cast(str, None)).rolling(
1568
+ rolling = self.tsdf.pct_change(fill_method=None).rolling(
1604
1569
  observations,
1605
1570
  min_periods=observations,
1606
1571
  )
@@ -1630,8 +1595,7 @@ class OpenFrame(_CommonModel):
1630
1595
  second_column: int = 1,
1631
1596
  observations: int = 21,
1632
1597
  ) -> DataFrame:
1633
- """
1634
- Calculate rolling Correlation.
1598
+ """Calculate rolling Correlation.
1635
1599
 
1636
1600
  Calculates correlation between two series. The period with
1637
1601
  at least the given number of observations is the first period calculated.
@@ -1658,11 +1622,11 @@ class OpenFrame(_CommonModel):
1658
1622
  )
1659
1623
  first_series = (
1660
1624
  self.tsdf.iloc[:, first_column]
1661
- .pct_change(fill_method=cast(str, None))[1:]
1625
+ .pct_change(fill_method=None)[1:]
1662
1626
  .rolling(observations, min_periods=observations)
1663
1627
  )
1664
1628
  second_series = self.tsdf.iloc[:, second_column].pct_change(
1665
- fill_method=cast(str, None),
1629
+ fill_method=None,
1666
1630
  )[1:]
1667
1631
  corrdf = first_series.corr(other=second_series).dropna().to_frame()
1668
1632
  corrdf.columns = MultiIndex.from_arrays(