Skip to content

Instantly share code, notes, and snippets.

@chrisnicola
Forked from sapient/xirr.rb
Last active August 29, 2015 14:02
Show Gist options
  • Save chrisnicola/61e6b3b9676ebef9a83c to your computer and use it in GitHub Desktop.
Save chrisnicola/61e6b3b9676ebef9a83c to your computer and use it in GitHub Desktop.
Performs XIRR calculations using Ruby's Newton#nlsolve
require 'date'
require 'bigdecimal/newton'
require 'bigdecimal/math'
class XIRR
include Newton
def initialize(trans)
@trans = trans
@zero = 0.to_d
@one = 1.to_d
@two = 2.to_d
@ten = 10.to_d
@eps = 1.0e-16.to_d
end
def eps; @eps end
def one; @one end
def two; @two end
def ten; @ten end
def zero; @zero end
def values(x)
initial = @trans[0][:date]
value = @trans.reduce(0) do |s, t|
exponent = (t[:date].to_date - initial.to_date).to_i.to_d / 365.to_d
#nth = (@one + x[0]) ** exponent
nth = BigMath.exp(exponent * BigMath.log(@one + x[0], 15), 15)
s + t[:value].to_d / nth
end
[value]
end
def result
x = [zero]
nlsolve(self, x)
x[0]
end
end
trans = []
# LibreOffice Calc result 0.362709696
trans << { value: -1000, date: "2011-08-08"}
trans << { value: 400, date: "2011-09-13"}
trans << { value: 650, date: "2011-10-18"}
result = XIRR.new(trans).result
puts "Final: #{(result*100).round(2)}%"
@chrisnicola
Copy link
Author

Somewhat improved version of the original with some fixes. Also changed everything to use "to_d" and allowed it to support non-BigDecimal and non-Date types in the transactions. Performs to_d and to_date conversions on it's input.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment