Small changes to source data causes crazy changes to IRR
weshatheleopard opened this issue · comments
2.1.1 :002 > arr = [ Finance::Transaction.new(70, :date => Time.new(2015,7,31)),
2.1.1 :003 > Finance::Transaction.new(-90, :date => Time.new(2021,1,12)),
2.1.1 :004 > Finance::Transaction.new(-20, :date => Time.new(2021,3,31)) ]
=> [Transaction(70), Transaction(-90), Transaction(-20)]
2.1.1 :005 > arr.xirr
=> Rate.new(0.085713, :apr)
This value matches what Excel 2013's XIRR function returns.
Now, if we change the date of $90 transaction just one day further...
2.1.1 :006 > arr = [ Finance::Transaction.new(70, :date => Time.new(2015,7,31)),
2.1.1 :007 > Finance::Transaction.new(-90, :date => Time.new(2021,1,13)),
2.1.1 :008 > Finance::Transaction.new(-20, :date => Time.new(2021,3,31)) ]
=> [Transaction(70), Transaction(-90), Transaction(-20)]
2.1.1 :009 > arr.xirr
=> Rate.new(-1.451804, :apr)
Excel 2013's XIRR function returns correct result in this case: 0.085676876
.
So I found the problem. It's right here: https://github.com/wkranec/finance/blob/master/lib/finance/cashflows.rb#L36
In some circumstances, you end up with value
being a Complex
number. When you do .to_s
on a Complex
number, string representation of that looks like 3.81633493748609+8695.884928556025i
— and when you make a BigDecimal
out of that, it ignores everything starting with the first non-digit character (in this case, +
), so the result is only the real part of complex number, which is completely incorrect:
2.1.1 :001 > n = Complex(12, 34).to_s
=> "12+34i"
2.1.1 :002 > BigDecimal.new(n.to_s)
=> #<BigDecimal:2e58b78,'0.12E2',9(18)>