26
26
'start' : 1 ,
27
27
'finish' : 0 }
28
28
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
+
29
47
30
48
def _convert_when (when ):
31
49
# 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):
598
616
# where
599
617
# g(r) is the formula
600
618
# 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 ):
602
620
"""
603
621
Compute the rate of interest per period.
604
622
@@ -621,7 +639,7 @@ def rate(nper, pmt, pv, fv, when='end', guess=None, tol=None, maxiter=100, raise
621
639
maxiter : int, optional
622
640
Maximum iterations in finding the solution
623
641
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
625
643
cannot be computed due to having reached the maximum number of
626
644
iterations (IterationsExceededException). Set to False as default,
627
645
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
669
687
iterator += 1
670
688
rn = rnp1
671
689
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
-
679
690
if not np .all (close ):
680
691
if np .isscalar (rn ):
681
692
if raise_exceptions :
682
- raise IterationsExceededException ('\n Maximum number of iterations exceeded.' )
693
+ raise IterationsExceededException ('Maximum number of iterations exceeded.' )
683
694
return default_type (np .nan )
684
695
else :
685
696
# Return nan's in array of the same shape as rn
686
697
# where the solution is not close to tol.
687
698
if raise_exceptions :
688
- raise IterationsExceededException (f'\n Maximum number of iterations exceeded in '
699
+ raise IterationsExceededException (f'Maximum number of iterations exceeded in '
689
700
f'{ len (close )- close .sum ()} rate(s).' )
690
701
rn [~ close ] = np .nan
691
702
return rn
692
703
693
704
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 ):
695
706
"""
696
707
Return the Internal Rate of Return (IRR).
697
708
@@ -772,23 +783,13 @@ def irr(values, guess=None, tol=1e-12, maxiter=100, raise_exceptions=False):
772
783
if values .ndim != 1 :
773
784
raise ValueError ("Cashflows must be a rank-1 array" )
774
785
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
-
785
786
# If all values are of the same sign no solution exists
786
787
# we don't perform any further calculations and exit early
787
788
same_sign = np .all (values > 0 ) if values [0 ] > 0 else np .all (values < 0 )
788
789
if same_sign :
789
790
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.' )
792
793
return np .nan
793
794
794
795
# If no value is passed for `guess`, then make a heuristic estimate
@@ -826,7 +827,7 @@ class IterationsExceededException(Exception):
826
827
g -= delta
827
828
828
829
if raise_exceptions :
829
- raise IterationsExceededException ('\n Maximum number of iterations exceeded.' )
830
+ raise IterationsExceededException ('Maximum number of iterations exceeded.' )
830
831
831
832
return np .nan
832
833
@@ -910,7 +911,7 @@ def npv(rate, values):
910
911
return npv
911
912
912
913
913
- def mirr (values , finance_rate , reinvest_rate ,raise_exceptions = False ):
914
+ def mirr (values , finance_rate , reinvest_rate , * , raise_exceptions = False ):
914
915
"""
915
916
Modified internal rate of return.
916
917
@@ -939,13 +940,6 @@ def mirr(values, finance_rate, reinvest_rate,raise_exceptions=False):
939
940
values = np .asarray (values )
940
941
n = values .size
941
942
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
-
949
943
# Without this explicit cast the 1/(n - 1) computation below
950
944
# becomes a float, which causes TypeError when using Decimal
951
945
# values.
@@ -956,8 +950,8 @@ class NoRealSolutionException(Exception):
956
950
neg = values < 0
957
951
if not (pos .any () and neg .any ()):
958
952
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.' )
961
955
return np .nan
962
956
numer = np .abs (npv (reinvest_rate , values * pos ))
963
957
denom = np .abs (npv (finance_rate , values * neg ))
0 commit comments