openseries 1.6.0__py3-none-any.whl → 1.7.0__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
 
@@ -483,13 +467,12 @@ class OpenFrame(_CommonModel):
483
467
  dlta_degr_freedms: int = 0,
484
468
  first_column: int = 0,
485
469
  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,
470
+ months_from_last: int | None = None,
471
+ from_date: dt.date | None = None,
472
+ to_date: dt.date | None = None,
473
+ periods_in_a_year_fixed: DaysInYearType | None = None,
490
474
  ) -> DataFrame:
491
- """
492
- Exponentially Weighted Moving Average Volatilities and Correlation.
475
+ """Exponentially Weighted Moving Average Volatilities and Correlation.
493
476
 
494
477
  Exponentially Weighted Moving Average (EWMA) for Volatilities and
495
478
  Correlation. https://www.investopedia.com/articles/07/ewma.asp.
@@ -601,8 +584,7 @@ class OpenFrame(_CommonModel):
601
584
 
602
585
  @property
603
586
  def correl_matrix(self: Self) -> DataFrame:
604
- """
605
- Correlation matrix.
587
+ """Correlation matrix.
606
588
 
607
589
  Returns
608
590
  -------
@@ -610,7 +592,7 @@ class OpenFrame(_CommonModel):
610
592
  Correlation matrix
611
593
 
612
594
  """
613
- corr_matrix = self.tsdf.pct_change(fill_method=cast(str, None)).corr(
595
+ corr_matrix = self.tsdf.pct_change(fill_method=None).corr(
614
596
  method="pearson",
615
597
  min_periods=1,
616
598
  )
@@ -623,8 +605,7 @@ class OpenFrame(_CommonModel):
623
605
  self: Self,
624
606
  new_series: OpenTimeSeries,
625
607
  ) -> Self:
626
- """
627
- To add an OpenTimeSeries object.
608
+ """To add an OpenTimeSeries object.
628
609
 
629
610
  Parameters
630
611
  ----------
@@ -643,8 +624,7 @@ class OpenFrame(_CommonModel):
643
624
  return self
644
625
 
645
626
  def delete_timeseries(self: Self, lvl_zero_item: str) -> Self:
646
- """
647
- To delete an OpenTimeSeries object.
627
+ """To delete an OpenTimeSeries object.
648
628
 
649
629
  Parameters
650
630
  ----------
@@ -674,12 +654,11 @@ class OpenFrame(_CommonModel):
674
654
 
675
655
  def trunc_frame(
676
656
  self: Self,
677
- start_cut: Optional[dt.date] = None,
678
- end_cut: Optional[dt.date] = None,
657
+ start_cut: dt.date | None = None,
658
+ end_cut: dt.date | None = None,
679
659
  where: LiteralTrunc = "both",
680
660
  ) -> Self:
681
- """
682
- Truncate DataFrame such that all timeseries have the same time span.
661
+ """Truncate DataFrame such that all timeseries have the same time span.
683
662
 
684
663
  Parameters
685
664
  ----------
@@ -733,8 +712,7 @@ class OpenFrame(_CommonModel):
733
712
  *,
734
713
  base_zero: bool = True,
735
714
  ) -> None:
736
- """
737
- Calculate cumulative relative return between two series.
715
+ """Calculate cumulative relative return between two series.
738
716
 
739
717
  Parameters
740
718
  ----------
@@ -766,14 +744,13 @@ class OpenFrame(_CommonModel):
766
744
 
767
745
  def tracking_error_func(
768
746
  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,
747
+ base_column: tuple[str, ValueType] | int = -1,
748
+ months_from_last: int | None = None,
749
+ from_date: dt.date | None = None,
750
+ to_date: dt.date | None = None,
751
+ periods_in_a_year_fixed: DaysInYearType | None = None,
774
752
  ) -> Series[float]:
775
- """
776
- Tracking Error.
753
+ """Tracking Error.
777
754
 
778
755
  Calculates Tracking Error which is the standard deviation of the
779
756
  difference between the fund and its index returns.
@@ -781,7 +758,7 @@ class OpenFrame(_CommonModel):
781
758
 
782
759
  Parameters
783
760
  ----------
784
- base_column: Union[tuple[str, ValueType], int], default: -1
761
+ base_column: tuple[str, ValueType] | int, default: -1
785
762
  Column of timeseries that is the denominator in the ratio.
786
763
  months_from_last : int, optional
787
764
  number of months offset as positive integer. Overrides use of from_date
@@ -846,8 +823,7 @@ class OpenFrame(_CommonModel):
846
823
  # noinspection PyTypeChecker
847
824
  relative = 1.0 + longdf - shortdf
848
825
  vol = float(
849
- relative.pct_change(fill_method=cast(str, None)).std()
850
- * sqrt(time_factor),
826
+ relative.pct_change(fill_method=None).std() * sqrt(time_factor),
851
827
  )
852
828
  terrors.append(vol)
853
829
 
@@ -860,14 +836,13 @@ class OpenFrame(_CommonModel):
860
836
 
861
837
  def info_ratio_func(
862
838
  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,
839
+ base_column: tuple[str, ValueType] | int = -1,
840
+ months_from_last: int | None = None,
841
+ from_date: dt.date | None = None,
842
+ to_date: dt.date | None = None,
843
+ periods_in_a_year_fixed: DaysInYearType | None = None,
868
844
  ) -> Series[float]:
869
- """
870
- Information Ratio.
845
+ """Information Ratio.
871
846
 
872
847
  The Information Ratio equals ( fund return less index return ) divided
873
848
  by the Tracking Error. And the Tracking Error is the standard deviation of
@@ -876,7 +851,7 @@ class OpenFrame(_CommonModel):
876
851
 
877
852
  Parameters
878
853
  ----------
879
- base_column: Union[tuple[str, ValueType], int], default: -1
854
+ base_column: tuple[str, ValueType] | int, default: -1
880
855
  Column of timeseries that is the denominator in the ratio.
881
856
  months_from_last : int, optional
882
857
  number of months offset as positive integer. Overrides use of from_date
@@ -941,12 +916,10 @@ class OpenFrame(_CommonModel):
941
916
  # noinspection PyTypeChecker
942
917
  relative = 1.0 + longdf - shortdf
943
918
  ret = float(
944
- relative.pct_change(fill_method=cast(str, None)).mean()
945
- * time_factor,
919
+ relative.pct_change(fill_method=None).mean() * time_factor,
946
920
  )
947
921
  vol = float(
948
- relative.pct_change(fill_method=cast(str, None)).std()
949
- * sqrt(time_factor),
922
+ relative.pct_change(fill_method=None).std() * sqrt(time_factor),
950
923
  )
951
924
  ratios.append(ret / vol)
952
925
 
@@ -960,14 +933,13 @@ class OpenFrame(_CommonModel):
960
933
  def capture_ratio_func( # noqa: C901
961
934
  self: Self,
962
935
  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,
936
+ base_column: tuple[str, ValueType] | int = -1,
937
+ months_from_last: int | None = None,
938
+ from_date: dt.date | None = None,
939
+ to_date: dt.date | None = None,
940
+ periods_in_a_year_fixed: DaysInYearType | None = None,
968
941
  ) -> Series[float]:
969
- """
970
- Capture Ratio.
942
+ """Capture Ratio.
971
943
 
972
944
  The Up (Down) Capture Ratio is calculated by dividing the CAGR
973
945
  of the asset during periods that the benchmark returns are positive (negative)
@@ -982,7 +954,7 @@ class OpenFrame(_CommonModel):
982
954
  ----------
983
955
  ratio: LiteralCaptureRatio
984
956
  The ratio to calculate
985
- base_column: Union[tuple[str, ValueType], int], default: -1
957
+ base_column: tuple[str, ValueType] | int, default: -1
986
958
  Column of timeseries that is the denominator in the ratio.
987
959
  months_from_last : int, optional
988
960
  number of months offset as positive integer. Overrides use of from_date
@@ -1047,8 +1019,8 @@ class OpenFrame(_CommonModel):
1047
1019
  ]
1048
1020
  if ratio == "up":
1049
1021
  uparray = (
1050
- longdf.pct_change(fill_method=cast(str, None))[
1051
- shortdf.pct_change(fill_method=cast(str, None)).to_numpy()
1022
+ longdf.pct_change(fill_method=None)[
1023
+ shortdf.pct_change(fill_method=None).to_numpy()
1052
1024
  > loss_limit
1053
1025
  ]
1054
1026
  .add(1)
@@ -1056,8 +1028,8 @@ class OpenFrame(_CommonModel):
1056
1028
  )
1057
1029
  up_rtrn = uparray.prod() ** (1 / (len(uparray) / time_factor)) - 1
1058
1030
  upidxarray = (
1059
- shortdf.pct_change(fill_method=cast(str, None))[
1060
- shortdf.pct_change(fill_method=cast(str, None)).to_numpy()
1031
+ shortdf.pct_change(fill_method=None)[
1032
+ shortdf.pct_change(fill_method=None).to_numpy()
1061
1033
  > loss_limit
1062
1034
  ]
1063
1035
  .add(1)
@@ -1069,8 +1041,8 @@ class OpenFrame(_CommonModel):
1069
1041
  ratios.append(up_rtrn / up_idx_return)
1070
1042
  elif ratio == "down":
1071
1043
  downarray = (
1072
- longdf.pct_change(fill_method=cast(str, None))[
1073
- shortdf.pct_change(fill_method=cast(str, None)).to_numpy()
1044
+ longdf.pct_change(fill_method=None)[
1045
+ shortdf.pct_change(fill_method=None).to_numpy()
1074
1046
  < loss_limit
1075
1047
  ]
1076
1048
  .add(1)
@@ -1080,8 +1052,8 @@ class OpenFrame(_CommonModel):
1080
1052
  downarray.prod() ** (1 / (len(downarray) / time_factor)) - 1
1081
1053
  )
1082
1054
  downidxarray = (
1083
- shortdf.pct_change(fill_method=cast(str, None))[
1084
- shortdf.pct_change(fill_method=cast(str, None)).to_numpy()
1055
+ shortdf.pct_change(fill_method=None)[
1056
+ shortdf.pct_change(fill_method=None).to_numpy()
1085
1057
  < loss_limit
1086
1058
  ]
1087
1059
  .add(1)
@@ -1094,8 +1066,8 @@ class OpenFrame(_CommonModel):
1094
1066
  ratios.append(down_return / down_idx_return)
1095
1067
  elif ratio == "both":
1096
1068
  uparray = (
1097
- longdf.pct_change(fill_method=cast(str, None))[
1098
- shortdf.pct_change(fill_method=cast(str, None)).to_numpy()
1069
+ longdf.pct_change(fill_method=None)[
1070
+ shortdf.pct_change(fill_method=None).to_numpy()
1099
1071
  > loss_limit
1100
1072
  ]
1101
1073
  .add(1)
@@ -1103,8 +1075,8 @@ class OpenFrame(_CommonModel):
1103
1075
  )
1104
1076
  up_rtrn = uparray.prod() ** (1 / (len(uparray) / time_factor)) - 1
1105
1077
  upidxarray = (
1106
- shortdf.pct_change(fill_method=cast(str, None))[
1107
- shortdf.pct_change(fill_method=cast(str, None)).to_numpy()
1078
+ shortdf.pct_change(fill_method=None)[
1079
+ shortdf.pct_change(fill_method=None).to_numpy()
1108
1080
  > loss_limit
1109
1081
  ]
1110
1082
  .add(1)
@@ -1114,8 +1086,8 @@ class OpenFrame(_CommonModel):
1114
1086
  upidxarray.prod() ** (1 / (len(upidxarray) / time_factor)) - 1
1115
1087
  )
1116
1088
  downarray = (
1117
- longdf.pct_change(fill_method=cast(str, None))[
1118
- shortdf.pct_change(fill_method=cast(str, None)).to_numpy()
1089
+ longdf.pct_change(fill_method=None)[
1090
+ shortdf.pct_change(fill_method=None).to_numpy()
1119
1091
  < loss_limit
1120
1092
  ]
1121
1093
  .add(1)
@@ -1125,8 +1097,8 @@ class OpenFrame(_CommonModel):
1125
1097
  downarray.prod() ** (1 / (len(downarray) / time_factor)) - 1
1126
1098
  )
1127
1099
  downidxarray = (
1128
- shortdf.pct_change(fill_method=cast(str, None))[
1129
- shortdf.pct_change(fill_method=cast(str, None)).to_numpy()
1100
+ shortdf.pct_change(fill_method=None)[
1101
+ shortdf.pct_change(fill_method=None).to_numpy()
1130
1102
  < loss_limit
1131
1103
  ]
1132
1104
  .add(1)
@@ -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(