1
+ # // Copyright (c) 2012 Sutoiku, Inc. (MIT License)
2
+
3
+ # // Some algorithms have been ported from Apache OpenOffice:
4
+
5
+ # /**************************************************************
6
+ # *
7
+ # * Licensed to the Apache Software Foundation (ASF) under one
8
+ # * or more contributor license agreements. See the NOTICE file
9
+ # * distributed with this work for additional information
10
+ # * regarding copyright ownership. The ASF licenses this file
11
+ # * to you under the Apache License, Version 2.0 (the
12
+ # * "License"); you may not use this file except in compliance
13
+ # * with the License. You may obtain a copy of the License at
14
+ # *
15
+ # * http://www.apache.org/licenses/LICENSE-2.0
16
+ # *
17
+ # * Unless required by applicable law or agreed to in writing,
18
+ # * software distributed under the License is distributed on an
19
+ # * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20
+ # * KIND, either express or implied. See the License for the
21
+ # * specific language governing permissions and limitations
22
+ # * under the License.
23
+ # *
24
+ # *************************************************************/
25
+
26
+
27
+ def years_between_dates (date1 , date2 ):
28
+ delta = date2 - date1
29
+ return (delta .days / 365 )
30
+
31
+
32
+ # // Credits: algorithm inspired by Apache OpenOffice
33
+ # // Calculates the resulting amount
34
+ def irrResult (values , dates , rate ):
35
+ r = rate + 1
36
+ result = values [0 ]
37
+ for i in range (1 , len (values )):
38
+ result = result + values [i ] / pow (r , years_between_dates (dates [0 ], dates [i ]))
39
+ i = i + 1
40
+ return result
41
+
42
+
43
+ # // Calculates the first derivation
44
+ def irrResultDeriv (values , dates , rate ):
45
+ r = rate + 1
46
+ result = 0
47
+ for i in range (1 , len (values )):
48
+ frac = years_between_dates (dates [0 ], dates [i ])
49
+ result = result - frac * values [i ] / pow (r , frac + 1 )
50
+ i = i + 1
51
+ return result
52
+
53
+
54
+ def xirr (values , dates ):
55
+ # // Check that values contains at least one positive value and one negative value
56
+ positive = False
57
+ negative = False
58
+ for v in values :
59
+ if v > 0 :
60
+ positive = True
61
+ if v < 0 :
62
+ negative = True
63
+
64
+ # // Return error if values does not contain at least one positive value and one negative value
65
+ if not (positive and negative ):
66
+ return 'Error'
67
+ # // Initialize guess and resultRate
68
+ guess = 0.1
69
+ resultRate = guess
70
+
71
+ # // Set maximum epsilon for end of iteration
72
+ epsMax = 1e-10
73
+
74
+ # // Set maximum number of iterations
75
+ iterMax = 20
76
+
77
+ # // Implement Newton's method
78
+ iteration = 0
79
+ contLoop = True
80
+ while contLoop and (iteration < iterMax ):
81
+ resultValue = irrResult (values , dates , resultRate )
82
+ newRate = resultRate - (resultValue / irrResultDeriv (values , dates , resultRate ))
83
+ epsRate = abs (newRate - resultRate )
84
+ resultRate = newRate
85
+ if resultRate < - 1 :
86
+ resultRate = - 0.999999999
87
+ contLoop = (epsRate > epsMax ) and (abs (resultValue ) > epsMax )
88
+ iteration = iteration + 1
89
+ if contLoop :
90
+ return epsRate > epsMax , epsRate , 'iterMax'
91
+ return resultRate
0 commit comments