-
-
Save chrisnicola/61e6b3b9676ebef9a83c to your computer and use it in GitHub Desktop.
Performs XIRR calculations using Ruby's Newton#nlsolve
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)}%" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.