marksweston / finance

A library for financial calculations in Ruby

Home Page:https://rubygems.org/gems/finance

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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)>