@@ -963,12 +963,12 @@ def mirr(values, finance_rate, reinvest_rate, *, raise_exceptions=False):
963963
964964 Parameters
965965 ----------
966- values : array_like
966+ values : array_like, 1D or 2D
967967 Cash flows, where the first value is considered a sunk cost at time zero.
968968 It must contain at least one positive and one negative value.
969- finance_rate : scalar
969+ finance_rate : scalar or 1D array
970970 Interest rate paid on the cash flows.
971- reinvest_rate : scalar
971+ reinvest_rate : scalar or D array
972972 Interest rate received on the cash flows upon reinvestment.
973973 raise_exceptions: bool, optional
974974 Flag to raise an exception when the MIRR cannot be computed due to
@@ -977,7 +977,7 @@ def mirr(values, finance_rate, reinvest_rate, *, raise_exceptions=False):
977977
978978 Returns
979979 -------
980- out : float
980+ out : float or 2D array
981981 Modified internal rate of return
982982
983983 Notes
@@ -1007,6 +1007,22 @@ def mirr(values, finance_rate, reinvest_rate, *, raise_exceptions=False):
10071007 >>> npf.mirr([-100, 50, -60, 70], 0.10, 0.12)
10081008 np.float64(-0.03909366594356467)
10091009
1010+ It is also possible to supply multiple cashflows or pairs of
1011+ finance and reinvstment rates, note that in this case the number of elements
1012+ in each of the rates arrays must match.
1013+
1014+ >>> values = [
1015+ ... [-4500, -800, 800, 800, 600],
1016+ ... [-120000, 39000, 30000, 21000, 37000],
1017+ ... [100, 200, -50, 300, -200],
1018+ ... ]
1019+ >>> finance_rate = [0.05, 0.08, 0.10]
1020+ >>> reinvestment_rate = [0.08, 0.10, 0.12]
1021+ >>> npf.mirr(values, finance_rate, reinvestment_rate)
1022+ array([[-0.1784449 , -0.17328716, -0.1684366 ],
1023+ [ 0.04627293, 0.05437856, 0.06252201],
1024+ [ 0.35712458, 0.40628857, 0.44435295]])
1025+
10101026 Now, let's consider the scenario where all cash flows are negative.
10111027
10121028 >>> npf.mirr([-100, -50, -60, -70], 0.10, 0.12)
@@ -1025,22 +1041,31 @@ def mirr(values, finance_rate, reinvest_rate, *, raise_exceptions=False):
10251041 numpy_financial._financial.NoRealSolutionError:
10261042 No real solution exists for MIRR since all cashflows are of the same sign.
10271043 """
1028- values = np .asarray (values )
1029- n = values .size
1030-
1031- # Without this explicit cast the 1/(n - 1) computation below
1032- # becomes a float, which causes TypeError when using Decimal
1033- # values.
1034- if isinstance (finance_rate , Decimal ):
1035- n = Decimal (n )
1036-
1037- pos = values > 0
1038- neg = values < 0
1039- if not (pos .any () and neg .any ()):
1044+ values_inner = np .atleast_2d (values ).astype (np .float64 )
1045+ finance_rate_inner = np .atleast_1d (finance_rate ).astype (np .float64 )
1046+ reinvest_rate_inner = np .atleast_1d (reinvest_rate ).astype (np .float64 )
1047+ n = values_inner .shape [1 ]
1048+
1049+ if finance_rate_inner .size != reinvest_rate_inner .size :
10401050 if raise_exceptions :
1041- raise NoRealSolutionError ('No real solution exists for MIRR since'
1042- ' all cashflows are of the same sign.' )
1051+ raise ValueError ("finance_rate and reinvest_rate must have the same size" )
10431052 return np .nan
1044- numer = np .abs (npv (reinvest_rate , values * pos ))
1045- denom = np .abs (npv (finance_rate , values * neg ))
1046- return (numer / denom ) ** (1 / (n - 1 )) * (1 + reinvest_rate ) - 1
1053+
1054+ out_shape = _get_output_array_shape (values_inner , finance_rate_inner )
1055+ out = np .empty (out_shape )
1056+
1057+ for i , v in enumerate (values_inner ):
1058+ for j , (rr , fr ) in enumerate (zip (reinvest_rate_inner , finance_rate_inner )):
1059+ pos = v > 0
1060+ neg = v < 0
1061+
1062+ if not (pos .any () and neg .any ()):
1063+ if raise_exceptions :
1064+ raise NoRealSolutionError ("No real solution exists for MIRR since"
1065+ " all cashflows are of the same sign." )
1066+ out [i , j ] = np .nan
1067+ else :
1068+ numer = np .abs (npv (rr , v * pos ))
1069+ denom = np .abs (npv (fr , v * neg ))
1070+ out [i , j ] = (numer / denom ) ** (1 / (n - 1 )) * (1 + rr ) - 1
1071+ return _ufunc_like (out )
0 commit comments