qis 3.1.5__tar.gz → 3.1.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.
Files changed (149) hide show
  1. {qis-3.1.5 → qis-3.1.6}/PKG-INFO +1 -1
  2. {qis-3.1.5 → qis-3.1.6}/pyproject.toml +1 -1
  3. {qis-3.1.5 → qis-3.1.6}/qis/models/linear/ewm.py +83 -1
  4. {qis-3.1.5 → qis-3.1.6}/qis/utils/__init__.py +1 -1
  5. {qis-3.1.5 → qis-3.1.6}/qis/utils/df_ops.py +34 -14
  6. {qis-3.1.5 → qis-3.1.6}/qis/utils/np_ops.py +1 -1
  7. {qis-3.1.5 → qis-3.1.6}/LICENSE.txt +0 -0
  8. {qis-3.1.5 → qis-3.1.6}/README.md +0 -0
  9. {qis-3.1.5 → qis-3.1.6}/qis/__init__.py +0 -0
  10. {qis-3.1.5 → qis-3.1.6}/qis/examples/best_returns.py +0 -0
  11. {qis-3.1.5 → qis-3.1.6}/qis/examples/bond_futures_portfolio.py +0 -0
  12. {qis-3.1.5 → qis-3.1.6}/qis/examples/bootstrap_analysis.py +0 -0
  13. {qis-3.1.5 → qis-3.1.6}/qis/examples/boxplot_conditional_returns.py +0 -0
  14. {qis-3.1.5 → qis-3.1.6}/qis/examples/btc_asset_corr.py +0 -0
  15. {qis-3.1.5 → qis-3.1.6}/qis/examples/constant_notional.py +0 -0
  16. {qis-3.1.5 → qis-3.1.6}/qis/examples/constant_weight_portfolios.py +0 -0
  17. {qis-3.1.5 → qis-3.1.6}/qis/examples/core/perf_bbg_prices.py +0 -0
  18. {qis-3.1.5 → qis-3.1.6}/qis/examples/core/price_plots.py +0 -0
  19. {qis-3.1.5 → qis-3.1.6}/qis/examples/core/us_election.py +0 -0
  20. {qis-3.1.5 → qis-3.1.6}/qis/examples/credit_spreads.py +0 -0
  21. {qis-3.1.5 → qis-3.1.6}/qis/examples/credit_trackers.py +0 -0
  22. {qis-3.1.5 → qis-3.1.6}/qis/examples/europe_futures.py +0 -0
  23. {qis-3.1.5 → qis-3.1.6}/qis/examples/factsheets/multi_assets.py +0 -0
  24. {qis-3.1.5 → qis-3.1.6}/qis/examples/factsheets/multi_strategy.py +0 -0
  25. {qis-3.1.5 → qis-3.1.6}/qis/examples/factsheets/pyblogs_reports.py +0 -0
  26. {qis-3.1.5 → qis-3.1.6}/qis/examples/factsheets/strategy.py +0 -0
  27. {qis-3.1.5 → qis-3.1.6}/qis/examples/factsheets/strategy_benchmark.py +0 -0
  28. {qis-3.1.5 → qis-3.1.6}/qis/examples/generate_option_rolls.py +0 -0
  29. {qis-3.1.5 → qis-3.1.6}/qis/examples/interpolation_infrequent_returns.py +0 -0
  30. {qis-3.1.5 → qis-3.1.6}/qis/examples/leveraged_strategies.py +0 -0
  31. {qis-3.1.5 → qis-3.1.6}/qis/examples/long_short.py +0 -0
  32. {qis-3.1.5 → qis-3.1.6}/qis/examples/momentum_indices.py +0 -0
  33. {qis-3.1.5 → qis-3.1.6}/qis/examples/ohlc_vol_analysis.py +0 -0
  34. {qis-3.1.5 → qis-3.1.6}/qis/examples/overnight_returns.py +0 -0
  35. {qis-3.1.5 → qis-3.1.6}/qis/examples/perf_external_assets.py +0 -0
  36. {qis-3.1.5 → qis-3.1.6}/qis/examples/perp_pricing.py +0 -0
  37. {qis-3.1.5 → qis-3.1.6}/qis/examples/readme_performances.py +0 -0
  38. {qis-3.1.5 → qis-3.1.6}/qis/examples/risk_return_frontier.py +0 -0
  39. {qis-3.1.5 → qis-3.1.6}/qis/examples/rolling_performance.py +0 -0
  40. {qis-3.1.5 → qis-3.1.6}/qis/examples/seasonality.py +0 -0
  41. {qis-3.1.5 → qis-3.1.6}/qis/examples/sharpe_vs_sortino.py +0 -0
  42. {qis-3.1.5 → qis-3.1.6}/qis/examples/simulate_quant_strats.py +0 -0
  43. {qis-3.1.5 → qis-3.1.6}/qis/examples/test_ewm.py +0 -0
  44. {qis-3.1.5 → qis-3.1.6}/qis/examples/test_scatter.py +0 -0
  45. {qis-3.1.5 → qis-3.1.6}/qis/examples/try_pybloqs.py +0 -0
  46. {qis-3.1.5 → qis-3.1.6}/qis/examples/universe_corrs.py +0 -0
  47. {qis-3.1.5 → qis-3.1.6}/qis/examples/vix_beta_to_equities_bonds.py +0 -0
  48. {qis-3.1.5 → qis-3.1.6}/qis/examples/vix_conditional_returns.py +0 -0
  49. {qis-3.1.5 → qis-3.1.6}/qis/examples/vix_spy_by_year.py +0 -0
  50. {qis-3.1.5 → qis-3.1.6}/qis/examples/vix_tenor_analysis.py +0 -0
  51. {qis-3.1.5 → qis-3.1.6}/qis/examples/vol_without_weekends.py +0 -0
  52. {qis-3.1.5 → qis-3.1.6}/qis/file_utils.py +0 -0
  53. {qis-3.1.5 → qis-3.1.6}/qis/local_path.py +0 -0
  54. {qis-3.1.5 → qis-3.1.6}/qis/models/README.md +0 -0
  55. {qis-3.1.5 → qis-3.1.6}/qis/models/__init__.py +0 -0
  56. {qis-3.1.5 → qis-3.1.6}/qis/models/linear/__init__.py +0 -0
  57. {qis-3.1.5 → qis-3.1.6}/qis/models/linear/auto_corr.py +0 -0
  58. {qis-3.1.5 → qis-3.1.6}/qis/models/linear/corr_cov_matrix.py +0 -0
  59. {qis-3.1.5 → qis-3.1.6}/qis/models/linear/ewm_convolution.py +0 -0
  60. {qis-3.1.5 → qis-3.1.6}/qis/models/linear/ewm_factors.py +0 -0
  61. {qis-3.1.5 → qis-3.1.6}/qis/models/linear/ewm_winsor_outliers.py +0 -0
  62. {qis-3.1.5 → qis-3.1.6}/qis/models/linear/pca.py +0 -0
  63. {qis-3.1.5 → qis-3.1.6}/qis/models/linear/plot_correlations.py +0 -0
  64. {qis-3.1.5 → qis-3.1.6}/qis/models/linear/ra_returns.py +0 -0
  65. {qis-3.1.5 → qis-3.1.6}/qis/models/stats/__init__.py +0 -0
  66. {qis-3.1.5 → qis-3.1.6}/qis/models/stats/bootstrap.py +0 -0
  67. {qis-3.1.5 → qis-3.1.6}/qis/models/stats/ohlc_vol.py +0 -0
  68. {qis-3.1.5 → qis-3.1.6}/qis/models/stats/rolling_stats.py +0 -0
  69. {qis-3.1.5 → qis-3.1.6}/qis/models/stats/test_bootstrap.py +0 -0
  70. {qis-3.1.5 → qis-3.1.6}/qis/perfstats/README.md +0 -0
  71. {qis-3.1.5 → qis-3.1.6}/qis/perfstats/__init__.py +0 -0
  72. {qis-3.1.5 → qis-3.1.6}/qis/perfstats/cond_regression.py +0 -0
  73. {qis-3.1.5 → qis-3.1.6}/qis/perfstats/config.py +0 -0
  74. {qis-3.1.5 → qis-3.1.6}/qis/perfstats/desc_table.py +0 -0
  75. {qis-3.1.5 → qis-3.1.6}/qis/perfstats/fx_ops.py +0 -0
  76. {qis-3.1.5 → qis-3.1.6}/qis/perfstats/perf_stats.py +0 -0
  77. {qis-3.1.5 → qis-3.1.6}/qis/perfstats/regime_classifier.py +0 -0
  78. {qis-3.1.5 → qis-3.1.6}/qis/perfstats/returns.py +0 -0
  79. {qis-3.1.5 → qis-3.1.6}/qis/perfstats/timeseries_bfill.py +0 -0
  80. {qis-3.1.5 → qis-3.1.6}/qis/plots/README.md +0 -0
  81. {qis-3.1.5 → qis-3.1.6}/qis/plots/__init__.py +0 -0
  82. {qis-3.1.5 → qis-3.1.6}/qis/plots/bars.py +0 -0
  83. {qis-3.1.5 → qis-3.1.6}/qis/plots/boxplot.py +0 -0
  84. {qis-3.1.5 → qis-3.1.6}/qis/plots/contour.py +0 -0
  85. {qis-3.1.5 → qis-3.1.6}/qis/plots/derived/__init__.py +0 -0
  86. {qis-3.1.5 → qis-3.1.6}/qis/plots/derived/data_timeseries.py +0 -0
  87. {qis-3.1.5 → qis-3.1.6}/qis/plots/derived/desc_table.py +0 -0
  88. {qis-3.1.5 → qis-3.1.6}/qis/plots/derived/drawdowns.py +0 -0
  89. {qis-3.1.5 → qis-3.1.6}/qis/plots/derived/perf_table.py +0 -0
  90. {qis-3.1.5 → qis-3.1.6}/qis/plots/derived/prices.py +0 -0
  91. {qis-3.1.5 → qis-3.1.6}/qis/plots/derived/regime_class_table.py +0 -0
  92. {qis-3.1.5 → qis-3.1.6}/qis/plots/derived/regime_data.py +0 -0
  93. {qis-3.1.5 → qis-3.1.6}/qis/plots/derived/regime_pdf.py +0 -0
  94. {qis-3.1.5 → qis-3.1.6}/qis/plots/derived/regime_scatter.py +0 -0
  95. {qis-3.1.5 → qis-3.1.6}/qis/plots/derived/returns_heatmap.py +0 -0
  96. {qis-3.1.5 → qis-3.1.6}/qis/plots/derived/returns_scatter.py +0 -0
  97. {qis-3.1.5 → qis-3.1.6}/qis/plots/errorbar.py +0 -0
  98. {qis-3.1.5 → qis-3.1.6}/qis/plots/heatmap.py +0 -0
  99. {qis-3.1.5 → qis-3.1.6}/qis/plots/histogram.py +0 -0
  100. {qis-3.1.5 → qis-3.1.6}/qis/plots/histplot2d.py +0 -0
  101. {qis-3.1.5 → qis-3.1.6}/qis/plots/lineplot.py +0 -0
  102. {qis-3.1.5 → qis-3.1.6}/qis/plots/pie.py +0 -0
  103. {qis-3.1.5 → qis-3.1.6}/qis/plots/qqplot.py +0 -0
  104. {qis-3.1.5 → qis-3.1.6}/qis/plots/reports/__init__.py +0 -0
  105. {qis-3.1.5 → qis-3.1.6}/qis/plots/reports/econ_data_single.py +0 -0
  106. {qis-3.1.5 → qis-3.1.6}/qis/plots/reports/gantt_data_history.py +0 -0
  107. {qis-3.1.5 → qis-3.1.6}/qis/plots/reports/price_history.py +0 -0
  108. {qis-3.1.5 → qis-3.1.6}/qis/plots/reports/utils.py +0 -0
  109. {qis-3.1.5 → qis-3.1.6}/qis/plots/scatter.py +0 -0
  110. {qis-3.1.5 → qis-3.1.6}/qis/plots/stackplot.py +0 -0
  111. {qis-3.1.5 → qis-3.1.6}/qis/plots/table.py +0 -0
  112. {qis-3.1.5 → qis-3.1.6}/qis/plots/time_series.py +0 -0
  113. {qis-3.1.5 → qis-3.1.6}/qis/plots/utils.py +0 -0
  114. {qis-3.1.5 → qis-3.1.6}/qis/portfolio/README.md +0 -0
  115. {qis-3.1.5 → qis-3.1.6}/qis/portfolio/__init__.py +0 -0
  116. {qis-3.1.5 → qis-3.1.6}/qis/portfolio/backtester.py +0 -0
  117. {qis-3.1.5 → qis-3.1.6}/qis/portfolio/ewm_portfolio_risk.py +0 -0
  118. {qis-3.1.5 → qis-3.1.6}/qis/portfolio/multi_portfolio_data.py +0 -0
  119. {qis-3.1.5 → qis-3.1.6}/qis/portfolio/portfolio_data.py +0 -0
  120. {qis-3.1.5 → qis-3.1.6}/qis/portfolio/reports/__init__.py +0 -0
  121. {qis-3.1.5 → qis-3.1.6}/qis/portfolio/reports/brinson_attribution.py +0 -0
  122. {qis-3.1.5 → qis-3.1.6}/qis/portfolio/reports/config.py +0 -0
  123. {qis-3.1.5 → qis-3.1.6}/qis/portfolio/reports/multi_assets_factsheet.py +0 -0
  124. {qis-3.1.5 → qis-3.1.6}/qis/portfolio/reports/multi_strategy_factseet_pybloqs.py +0 -0
  125. {qis-3.1.5 → qis-3.1.6}/qis/portfolio/reports/multi_strategy_factsheet.py +0 -0
  126. {qis-3.1.5 → qis-3.1.6}/qis/portfolio/reports/strategy_benchmark_factsheet.py +0 -0
  127. {qis-3.1.5 → qis-3.1.6}/qis/portfolio/reports/strategy_benchmark_factsheet_pybloqs.py +0 -0
  128. {qis-3.1.5 → qis-3.1.6}/qis/portfolio/reports/strategy_factsheet.py +0 -0
  129. {qis-3.1.5 → qis-3.1.6}/qis/portfolio/reports/strategy_signal_factsheet.py +0 -0
  130. {qis-3.1.5 → qis-3.1.6}/qis/portfolio/strats/__init__.py +0 -0
  131. {qis-3.1.5 → qis-3.1.6}/qis/portfolio/strats/quant_strats_delta1.py +0 -0
  132. {qis-3.1.5 → qis-3.1.6}/qis/portfolio/strats/seasonal_strats.py +0 -0
  133. {qis-3.1.5 → qis-3.1.6}/qis/settings.yaml +0 -0
  134. {qis-3.1.5 → qis-3.1.6}/qis/sql_engine.py +0 -0
  135. {qis-3.1.5 → qis-3.1.6}/qis/test_data.py +0 -0
  136. {qis-3.1.5 → qis-3.1.6}/qis/utils/README.md +0 -0
  137. {qis-3.1.5 → qis-3.1.6}/qis/utils/dates.py +0 -0
  138. {qis-3.1.5 → qis-3.1.6}/qis/utils/df_agg.py +0 -0
  139. {qis-3.1.5 → qis-3.1.6}/qis/utils/df_cut.py +0 -0
  140. {qis-3.1.5 → qis-3.1.6}/qis/utils/df_freq.py +0 -0
  141. {qis-3.1.5 → qis-3.1.6}/qis/utils/df_groups.py +0 -0
  142. {qis-3.1.5 → qis-3.1.6}/qis/utils/df_melt.py +0 -0
  143. {qis-3.1.5 → qis-3.1.6}/qis/utils/df_str.py +0 -0
  144. {qis-3.1.5 → qis-3.1.6}/qis/utils/df_to_scores.py +0 -0
  145. {qis-3.1.5 → qis-3.1.6}/qis/utils/df_to_weights.py +0 -0
  146. {qis-3.1.5 → qis-3.1.6}/qis/utils/generic.py +0 -0
  147. {qis-3.1.5 → qis-3.1.6}/qis/utils/ols.py +0 -0
  148. {qis-3.1.5 → qis-3.1.6}/qis/utils/sampling.py +0 -0
  149. {qis-3.1.5 → qis-3.1.6}/qis/utils/struct_ops.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: qis
3
- Version: 3.1.5
3
+ Version: 3.1.6
4
4
  Summary: Implementation of visualisation and reporting analytics for Quantitative Investment Strategies
5
5
  License: LICENSE.txt
6
6
  Keywords: quantitative,investing,portfolio optimization,systematic strategies,volatility
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "qis"
3
- version = "3.1.5"
3
+ version = "3.1.6"
4
4
  description = "Implementation of visualisation and reporting analytics for Quantitative Investment Strategies"
5
5
  license = "LICENSE.txt"
6
6
  authors = ["Artur Sepp <artursepp@gmail.com>"]
@@ -606,6 +606,7 @@ def compute_ewm_vol(data: Union[pd.DataFrame, pd.Series, np.ndarray],
606
606
  ) -> Union[pd.DataFrame, pd.Series, np.ndarray]:
607
607
  """
608
608
  implementation of ewm recursion for variance/volatility computation
609
+ vol_floor_quantile_roll_period will replace ewma estimate with quantile vol if vol < quantile vol
609
610
  """
610
611
  a = npo.to_finite_np(data=data, fill_value=np.nan)
611
612
 
@@ -634,7 +635,9 @@ def compute_ewm_vol(data: Union[pd.DataFrame, pd.Series, np.ndarray],
634
635
  # apply quantile
635
636
  if vol_floor_quantile is not None:
636
637
  ewm_pd = pd.DataFrame(ewm)
637
- ewm_quantiles = ewm_pd.rolling(vol_floor_quantile_roll_period, min_periods=100).quantile(vol_floor_quantile, interpolation="lower")
638
+ ewm_quantiles = ewm_pd.rolling(vol_floor_quantile_roll_period,
639
+ min_periods=int(0.2*vol_floor_quantile_roll_period)
640
+ ).quantile(vol_floor_quantile, interpolation="lower")
638
641
  vol_floor = ewm_quantiles.to_numpy()
639
642
  ewm = np.where(np.less(ewm, vol_floor), vol_floor, ewm)
640
643
 
@@ -657,7 +660,86 @@ def compute_ewm_vol(data: Union[pd.DataFrame, pd.Series, np.ndarray],
657
660
  ewm = pd.DataFrame(data=ewm, index=data.index, columns=data.columns)
658
661
  elif isinstance(data, pd.Series):
659
662
  ewm = pd.Series(data=ewm, index=data.index, name=data.name)
663
+ return ewm
664
+
665
+
666
+ def compute_ewm_newey_west_vol(data: Union[pd.DataFrame, pd.Series, np.ndarray],
667
+ num_lags: int = 3,
668
+ span: Optional[Union[float, np.ndarray]] = None,
669
+ ewm_lambda: Union[float, np.ndarray] = 0.94,
670
+ mean_adj_type: MeanAdjType = MeanAdjType.NONE,
671
+ init_type: InitType = InitType.X0,
672
+ init_value: Optional[Union[float, np.ndarray]] = None,
673
+ apply_sqrt: bool = True,
674
+ annualize: bool = False,
675
+ af: Optional[float] = None,
676
+ warmup_period: Optional[int] = None,
677
+ nan_backfill: NanBackfill = NanBackfill.FFILL
678
+ ) -> Union[pd.DataFrame, pd.Series, np.ndarray]:
679
+ """
680
+ implementation of newey west vol estimator
681
+ implementation of ewm recursion for variance/volatility computation
682
+ vol_floor_quantile_roll_period will replace ewma estimate with quantile vol if vol < quantile vol
683
+ """
684
+ a = npo.to_finite_np(data=data, fill_value=np.nan)
685
+
686
+ if span is not None:
687
+ ewm_lambda = 1.0 - 2.0 / (span + 1.0)
688
+
689
+ if mean_adj_type != MeanAdjType.NONE:
690
+ a = compute_rolling_mean_adj(data=a,
691
+ mean_adj_type=mean_adj_type,
692
+ ewm_lambda=ewm_lambda,
693
+ init_type=init_type,
694
+ nan_backfill=nan_backfill)
695
+
696
+ # initial conditions
697
+ a = a
698
+ if init_value is None:
699
+ init_value = set_init_dim1(data=a, init_type=init_type)
700
+
701
+ if isinstance(data, pd.Series) or (isinstance(data, np.ndarray) and data.ndim == 1):
702
+ ewm_lambda = float(ewm_lambda)
703
+ if isinstance(init_value, np.ndarray):
704
+ init_value = float(init_value)
705
+
706
+ ewm0 = ewm_recursion(a=a, ewm_lambda=ewm_lambda, init_value=init_value, nan_backfill=nan_backfill)
707
+
708
+
709
+ # compute m recursions:
710
+ ewms = {}
711
+ for m in np.arange(num_lags):
712
+ # lagged value
713
+ if m == 0:
714
+ a_m = a
715
+ else:
716
+ a_m = np.empty_like(a)
717
+ a_m[m:] = a[:-m]
718
+ a_m[:m] = np.nan
719
+ ewms[m] = ewm_recursion(a=a*a_m, ewm_lambda=ewm_lambda, init_value=init_value, nan_backfill=nan_backfill)
720
+
721
+ ewm_
722
+
723
+
724
+ if warmup_period is not None: # set to nan first nonnan in warmup_period
725
+ ewm = npo.set_nans_for_warmup_period(a=ewm, warmup_period=warmup_period)
726
+
727
+ if annualize or af is not None:
728
+ if af is None:
729
+ if isinstance(data, pd.DataFrame) or isinstance(data, pd.Series):
730
+ af = da.infer_an_from_data(data=data)
731
+ else:
732
+ warnings.warn(f"in compute_ewm annualization_factor for np array default is 1")
733
+ af = 1.0
734
+ ewm = af * ewm
660
735
 
736
+ if apply_sqrt:
737
+ ewm = np.sqrt(ewm)
738
+
739
+ if isinstance(data, pd.DataFrame):
740
+ ewm = pd.DataFrame(data=ewm, index=data.index, columns=data.columns)
741
+ elif isinstance(data, pd.Series):
742
+ ewm = pd.Series(data=ewm, index=data.index, name=data.name)
661
743
  return ewm
662
744
 
663
745
 
@@ -111,7 +111,7 @@ from qis.utils.df_ops import (
111
111
  get_first_nonnan_values,
112
112
  get_last_nonnan_values,
113
113
  get_last_nonnan,
114
- merge_on_column,
114
+ merge_dfs_on_column,
115
115
  compute_nans_zeros_ratio_after_first_non_nan,
116
116
  reindex_upto_last_nonnan,
117
117
  multiply_df_by_dt,
@@ -549,19 +549,21 @@ def df12_merge_with_tz(df1: pd.DataFrame,
549
549
  return dfs
550
550
 
551
551
 
552
- def merge_on_column(df1: pd.DataFrame,
553
- df2: pd.DataFrame,
554
- is_drop_y: bool = True
555
- ) -> pd.DataFrame:
556
- """
557
- merge on homogeneous column with preservation of indices and drop dublicated, _y columns
558
- """
559
- joint_data = pd.merge(left=df1, right=df2,
560
- left_index=True, right_index=True,
561
- suffixes=('', '_y'), how='inner')
562
- if is_drop_y:
563
- unique_columns = sop.merge_lists_unique(list1=df1.columns.to_list(), list2=df2.columns.to_list())
564
- joint_data = joint_data[unique_columns]
552
+ def merge_dfs_on_column(data_df: pd.DataFrame,
553
+ index_df: pd.DataFrame,
554
+ index_column_in_data_df: str = 'bbg_ticker'
555
+ ) -> pd.DataFrame:
556
+ """
557
+ merge data_df with index_df using index_column_in_data_df
558
+ index_df
559
+ """
560
+ data_df.index.name = 'index1' # rename index
561
+ index_df.index.name = 'index2' # rename index
562
+ # align dfs by index_column_in_data_df
563
+ index_df_joint_data = index_df.reindex(index=data_df[index_column_in_data_df].to_list())
564
+ # merge aligned dfs with reset index
565
+ joint_data = pd.concat([data_df.reset_index(drop=False), index_df_joint_data.reset_index(drop=False)], axis=1)
566
+ joint_data = joint_data.set_index(data_df.index.name)
565
567
  return joint_data
566
568
 
567
569
 
@@ -588,6 +590,7 @@ class UnitTests(Enum):
588
590
  SCORES = 2
589
591
  NONNANINDEX = 3
590
592
  REINDEX_UPTO_LAST_NONAN = 4
593
+ MERGE_DFS_ON_COLUMNS = 5
591
594
 
592
595
 
593
596
  def run_unit_test(unit_test: UnitTests):
@@ -643,10 +646,27 @@ def run_unit_test(unit_test: UnitTests):
643
646
  post_filled_up_nan = reindex_upto_last_nonnan(ds=ds, index=dates1, method='ffill')
644
647
  print(post_filled_up_nan)
645
648
 
649
+ elif unit_test == UnitTests.MERGE_DFS_ON_COLUMNS:
650
+ data_entries = {'Bond1': pd.Series(['AAA', 100.00, 'A3'], index=['bbg_ticker', 'face', 'raiting']),
651
+ 'Bond2': pd.Series(['AA', 100.00, 'A2'], index=['bbg_ticker', 'face', 'raiting']),
652
+ 'Bond3': pd.Series(['A', 100.00, 'A1'], index=['bbg_ticker', 'face', 'raiting']),
653
+ 'Bond4': pd.Series(['BBB', 100.00, 'B3'], index=['bbg_ticker', 'face', 'raiting'])}
654
+ data_df = pd.DataFrame.from_dict(data_entries, orient='index')
655
+
656
+ index_df = {'A': pd.Series([95.0], index=['price']),
657
+ 'AA': pd.Series([99.0], index=['price']),
658
+ 'AAA': pd.Series([101.0], index=['price']),
659
+ 'B': pd.Series([90.0], index=['price'])}
660
+ index_df = pd.DataFrame.from_dict(index_df, orient='index')
661
+ print(data_df)
662
+ print(index_df)
663
+ df = merge_dfs_on_column(data_df=data_df, index_df=index_df)
664
+ print(df)
665
+
646
666
 
647
667
  if __name__ == '__main__':
648
668
 
649
- unit_test = UnitTests.REINDEX_UPTO_LAST_NONAN
669
+ unit_test = UnitTests.MERGE_DFS_ON_COLUMNS
650
670
 
651
671
  is_run_all_tests = False
652
672
  if is_run_all_tests:
@@ -620,7 +620,7 @@ def run_unit_test(unit_test: UnitTests):
620
620
 
621
621
  if __name__ == '__main__':
622
622
 
623
- unit_test = UnitTests.CUM_POWER
623
+ unit_test = UnitTests.SHIFT_TEST
624
624
 
625
625
  is_run_all_tests = False
626
626
  if is_run_all_tests:
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
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
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
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
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
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
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
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
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