Open
Description
XIRR function will produce unstable results when the input cashflow is reasonably large (e.g. 1 * 10^12)
The simple fix to this is to normalize the input cashflow sequence, which will greatly improve the numerical stability of the output.
pyxirr could check for the order of magnitude of the input cashflow, and apply proactive normalization to the inputs to ensure numerical stability, at a low marginal cost of precision.
See the example fix below:
import datetime
import pyxirr
dates = [
datetime.date(2000, 1, 1),
datetime.date(1994, 6, 15),
datetime.date(1994, 7, 12),
datetime.date(2017, 10, 30),
datetime.date(2008, 1, 22),
datetime.date(1977, 7, 1),
datetime.date(2005, 12, 30),
datetime.date(2005, 12, 30),
datetime.date(2005, 12, 30),
datetime.date(1976, 12, 19),
datetime.date(1976, 12, 19),
datetime.date(1976, 12, 19),
datetime.date(2107, 3, 23),
]
cf1 = [
-253524383149.60605,
-0.0,
-0.0,
-0.0,
-0.0,
-1.1201669784316488,
-0.01,
-0.0,
-0.0,
-0.0,
-0.0,
-0.0,
32017.129321072072,
]
cf2 = [
-253524383149.60605,
-0.0,
-0.0,
-0.0,
-0.0,
-1.1201669784316488,
-0.01,
-0.0,
-0.0,
-0.0,
-0.0,
-0.0,
36590.74097669936,
]
# Exhibit 1
# Falsifying example, if large floats are not not normalized
xirr1 = pyxirr.xirr(dates, cf1)
xirr2 = pyxirr.xirr(dates, cf2)
print(xirr1)
print(xirr2)
# Results:
# -0.13761159201780845
# 1.800265354828463e+17
# Exhibit 2
# Normalize cash flows
max_cf1 = max(abs(x) for x in cf1)
max_cf2 = max(abs(x) for x in cf2)
normalized_cf1 = [x / max_cf1 for x in cf1]
normalized_cf2 = [x / max_cf2 for x in cf2]
# Calculate XIRR on normalized cash flows
xirr1 = pyxirr.xirr(dates, normalized_cf1)
xirr2 = pyxirr.xirr(dates, normalized_cf2)
print(xirr1)
print(xirr2)
# Normalized results:
# -0.13761159201780845
# -0.13653769882244854
Metadata
Metadata
Assignees
Labels
No labels