@@ -93,6 +93,7 @@ def __init__(
9393 self .n_points = n_points
9494 self .labels_are_tickers = ticker_names
9595 self ._ef_points = pd .DataFrame (dtype = float )
96+ self ._mdp_points = pd .DataFrame (dtype = float )
9697
9798 def __repr__ (self ):
9899 dic = {
@@ -707,6 +708,77 @@ def ef_points(self) -> pd.DataFrame:
707708 self ._ef_points = df
708709 return self ._ef_points
709710
711+ @property
712+ def mdp_points (self ) -> pd .DataFrame :
713+ """
714+ Generate Most diversified portfolios line.
715+
716+ Each point on the Most diversified portfolios line is a portfolio with optimized
717+ Diversification ratio for a given return.
718+
719+ The points are obtained through the constrained optimization process (optimization with bounds).
720+ Bounds are defined with 'bounds' property.
721+
722+ Returns
723+ -------
724+ DataFrame
725+ Table of weights and risk/return values for the Efficient Frontier.
726+ The columns:
727+
728+ - assets weights
729+ - CAGR (geometric mean)
730+ - Mean return (arithmetic mean)
731+ - Risk (standard deviation)
732+ - Diversification ratio
733+
734+ All the values are annualized.
735+
736+ Examples
737+ --------
738+ >>> ls4 = ['SP500TR.INDX', 'MCFTR.INDX', 'RGBITR.INDX', 'GC.COMM']
739+ >>> y = ok.EfficientFrontier(assets=ls4, ccy='RUB', last_date='2021-12', n_points=100)
740+ >>> y.mdp_points # print mdp weights, risk, mean return, CAGR and Diversification ratio
741+ Risk Mean return CAGR ... MCFTR.INDX RGBITR.INDX SP500TR.INDX
742+ 0 0.066040 0.094216 0.092220 ... 2.081668e-16 1.000000e+00 0.000000e+00
743+ 1 0.064299 0.095342 0.093451 ... 0.000000e+00 9.844942e-01 5.828671e-16
744+ 2 0.062761 0.096468 0.094670 ... 0.000000e+00 9.689885e-01 1.110223e-16
745+ 3 0.061445 0.097595 0.095874 ... 5.828671e-16 9.534827e-01 0.000000e+00
746+ 4 0.060364 0.098724 0.097065 ... 3.191891e-16 9.379769e-01 0.000000e+00
747+ .. ... ... ... ... ... ... ...
748+ 95 0.258857 0.205984 0.178346 ... 8.840844e-01 1.387779e-17 0.000000e+00
749+ 96 0.266583 0.207214 0.177941 ... 9.130633e-01 3.469447e-18 0.000000e+00
750+ 97 0.274594 0.208446 0.177432 ... 9.420422e-01 0.000000e+00 1.075529e-16
751+ 98 0.282873 0.209678 0.176820 ... 9.710211e-01 2.428613e-17 6.938894e-18
752+ 99 0.291402 0.210912 0.176103 ... 1.000000e+00 2.775558e-16 3.951094e-09
753+ [100 rows x 8 columns]
754+
755+ To plot the Most diversification portfolios line use the DataFrame with the points data.
756+ Additionaly 'Plot.plot_assets()' can be used to show the assets in the chart.
757+
758+ >>> import matplotlib.pyplot as plt
759+ >>> fig = plt.figure()
760+ >>> # Plot the assets points
761+ >>> y.plot_assets(kind='cagr') # kind should be set to "cagr" as we take "CAGR" column from the ef_points.
762+ >>> ax = plt.gca()
763+ >>> # Plot the Most diversified portfolios line
764+ >>> df = y.mdp_points
765+ >>> ax.plot(df['Risk'], df['CAGR']) # we chose to plot CAGR which is geometric mean of return series
766+ >>> # Set the axis labels and the title
767+ >>> ax.set_title('Most diversified portfolios line')
768+ >>> ax.set_xlabel('Risk (Standard Deviation)')
769+ >>> ax.set_ylabel('Return (CAGR)')
770+ >>> plt.show()
771+ """
772+ if self ._mdp_points .empty :
773+ target_rs = self .mean_return_range
774+ df = pd .DataFrame (dtype = "float" )
775+ for x in target_rs :
776+ row = self .get_most_diversified_portfolio (target_return = x , monthly_return = True )
777+ df = df .append (row , ignore_index = True )
778+ df = Frame .change_columns_order (df , ["Risk" , "Mean return" , "CAGR" ])
779+ self ._mdp_points = df
780+ return self ._mdp_points
781+
710782 def get_monte_carlo (self , n : int = 100 , kind : str = "mean" ) -> pd .DataFrame :
711783 """
712784 Generate N random portfolios with Monte Carlo simulation.
0 commit comments