2626 'start' : 1 ,
2727 'finish' : 0 }
2828
29+ # Define custom Exceptions
30+
31+ class NoRealSolutionException (Exception ):
32+ """ No real solution to the problem. """
33+ def __init__ (self , message ):
34+ self .message = message
35+
36+ def __str__ (self ):
37+ return self .message
38+
39+ class IterationsExceededException (Exception ):
40+ """ Maximum number of iterations reached. """
41+ def __init__ (self , message ):
42+ self .message = message
43+
44+ def __str__ (self ):
45+ return self .message
46+
2947
3048def _convert_when (when ):
3149 # Test to see if when has already been converted to ndarray
@@ -598,7 +616,7 @@ def _g_div_gp(r, n, p, x, y, w):
598616# where
599617# g(r) is the formula
600618# g'(r) is the derivative with respect to r.
601- def rate (nper , pmt , pv , fv , when = 'end' , guess = None , tol = None , maxiter = 100 , raise_exceptions = False ):
619+ def rate (nper , pmt , pv , fv , when = 'end' , guess = None , tol = None , maxiter = 100 , * , raise_exceptions = False ):
602620 """
603621 Compute the rate of interest per period.
604622
@@ -621,7 +639,7 @@ def rate(nper, pmt, pv, fv, when='end', guess=None, tol=None, maxiter=100, raise
621639 maxiter : int, optional
622640 Maximum iterations in finding the solution
623641 raise_exceptions: bool, optional
624- Flag to raise an exception when the at least one of the rates
642+ Flag to raise an exception when at least one of the rates
625643 cannot be computed due to having reached the maximum number of
626644 iterations (IterationsExceededException). Set to False as default,
627645 thus returning NaNs for those rates.
@@ -669,29 +687,22 @@ def rate(nper, pmt, pv, fv, when='end', guess=None, tol=None, maxiter=100, raise
669687 iterator += 1
670688 rn = rnp1
671689
672- # Define the custom Exceptions in case the flag raise_exceptions
673- # is set to True
674- if raise_exceptions :
675- class IterationsExceededException (Exception ):
676- "Raised when the maximum number of iterations is reached"
677- pass
678-
679690 if not np .all (close ):
680691 if np .isscalar (rn ):
681692 if raise_exceptions :
682- raise IterationsExceededException ('\n Maximum number of iterations exceeded.' )
693+ raise IterationsExceededException ('Maximum number of iterations exceeded.' )
683694 return default_type (np .nan )
684695 else :
685696 # Return nan's in array of the same shape as rn
686697 # where the solution is not close to tol.
687698 if raise_exceptions :
688- raise IterationsExceededException (f'\n Maximum number of iterations exceeded in '
699+ raise IterationsExceededException (f'Maximum number of iterations exceeded in '
689700 f'{ len (close )- close .sum ()} rate(s).' )
690701 rn [~ close ] = np .nan
691702 return rn
692703
693704
694- def irr (values , guess = None , tol = 1e-12 , maxiter = 100 , raise_exceptions = False ):
705+ def irr (values , guess = None , * , tol = 1e-12 , maxiter = 100 , raise_exceptions = False ):
695706 """
696707 Return the Internal Rate of Return (IRR).
697708
@@ -772,23 +783,13 @@ def irr(values, guess=None, tol=1e-12, maxiter=100, raise_exceptions=False):
772783 if values .ndim != 1 :
773784 raise ValueError ("Cashflows must be a rank-1 array" )
774785
775- # Define the custom Exceptions in case the flag raise_exceptions
776- # is set to True
777- if raise_exceptions :
778- class NoRealSolutionException (Exception ):
779- "Raised when all the input cashflows are of the same sign"
780- pass
781- class IterationsExceededException (Exception ):
782- "Raised when the maximum number of iterations is reached"
783- pass
784-
785786 # If all values are of the same sign no solution exists
786787 # we don't perform any further calculations and exit early
787788 same_sign = np .all (values > 0 ) if values [0 ] > 0 else np .all (values < 0 )
788789 if same_sign :
789790 if raise_exceptions :
790- raise NoRealSolutionException ('\n No real solution exists for IRR since all '
791- 'cashflows are of the same sign.\n ' )
791+ raise NoRealSolutionException ('No real solution exists for IRR since all '
792+ 'cashflows are of the same sign.' )
792793 return np .nan
793794
794795 # If no value is passed for `guess`, then make a heuristic estimate
@@ -826,7 +827,7 @@ class IterationsExceededException(Exception):
826827 g -= delta
827828
828829 if raise_exceptions :
829- raise IterationsExceededException ('\n Maximum number of iterations exceeded.' )
830+ raise IterationsExceededException ('Maximum number of iterations exceeded.' )
830831
831832 return np .nan
832833
@@ -910,7 +911,7 @@ def npv(rate, values):
910911 return npv
911912
912913
913- def mirr (values , finance_rate , reinvest_rate ,raise_exceptions = False ):
914+ def mirr (values , finance_rate , reinvest_rate , * , raise_exceptions = False ):
914915 """
915916 Modified internal rate of return.
916917
@@ -939,13 +940,6 @@ def mirr(values, finance_rate, reinvest_rate,raise_exceptions=False):
939940 values = np .asarray (values )
940941 n = values .size
941942
942- # Define the custom Exception in case the flag raise_exceptions
943- # is set to True
944- if raise_exceptions :
945- class NoRealSolutionException (Exception ):
946- "Raised when all the input cashflows are of the same sign"
947- pass
948-
949943 # Without this explicit cast the 1/(n - 1) computation below
950944 # becomes a float, which causes TypeError when using Decimal
951945 # values.
@@ -956,8 +950,8 @@ class NoRealSolutionException(Exception):
956950 neg = values < 0
957951 if not (pos .any () and neg .any ()):
958952 if raise_exceptions :
959- raise NoRealSolutionException ('\n No real solution exists for IRR since'
960- ' all cashflows are of the same sign.\n ' )
953+ raise NoRealSolutionException ('No real solution exists for MIRR since'
954+ ' all cashflows are of the same sign.' )
961955 return np .nan
962956 numer = np .abs (npv (reinvest_rate , values * pos ))
963957 denom = np .abs (npv (finance_rate , values * neg ))
0 commit comments