内部收益计算函数
曾经看过一个帖子:有一个理财产品,每年年初存入10000元,每年年底得到利息1000元。持续5年,5年后返还本金50000元:问:利率是多少?
下面有个回复:每年存10000,利息1000,所以利率是10%。
那么问题来了,真实利率到底是多少?
office的excel有个公式叫xirr,参考 https://support.office.com/zh-cn/article/XIRR-%E5%87%BD%E6%95%B0-de1242ec-6477-445b-b11b-a303ad9adc9d
irr,参考 https://support.office.com/zh-cn/article/IRR-%E5%87%BD%E6%95%B0-64925eaa-9988-495b-b290-3ad0c163c1bc
实现如下:
require 'date' def simply_parse str year, month, day = str.split('-') return Date.new(year.to_i, month.to_i, day.to_i) end def simply_sum arr arr.inject(0) { |sum, element| sum + element } end # guess : 从该值开始计算 # accuracy : 计算精度 # cal_times : 计算次数 def xirr(arr, guess = 0.05, accuracy = 0.00000001, cal_times = 100) day_rate = (guess+1)**(1.0/365) - 1 start_date = simply_parse(arr[0][1]) end_date = simply_parse(arr[-1][1]) #puts "day_rate=#{day_rate}" for t in (1..cal_times) do value = 0 value1 = 0 for i in 0...arr.size item = arr[i] _date = simply_parse(item[1]) nd = (_date - start_date) return 'date error' if _date < start_date || _date > end_date value = value + item[0].to_f / ((1+day_rate)**nd) value1 = value1 + nd * item[0].to_f / ((1+day_rate)**(nd + 1)) end new_xirr = day_rate + value/value1 if (new_xirr - day_rate).abs < accuracy puts "cal_times = #{t}" return (1+new_xirr)**(365) - 1; end day_rate = new_xirr end return "guess failed, try guess = #{(1+day_rate)**(365) - 1}" end #test arr = '10000 2010-01-01 -1000 2010-12-31 10000 2011-01-01 -1000 2011-12-31 10000 2012-01-01 -1000 2012-12-31 10000 2013-01-01 -1000 2013-12-31 10000 2014-01-01 -1000 2014-12-31 -50000 2014-12-31'.split("\n").map{|x| x.split} puts xirr(arr, 0.05, 0.000000001, 20) # => 0.03410896488851867 arr = '10000 2008-1-1 -2750 2008-3-1 -4250 2008-10-30 -3250 2009-2-15 -2750 2009-4-1'.split("\n").map{|x| x.split} puts xirr(arr, 0.37) # => 0.37336253351240334 arr = '-700000 2008-1-1 120000 2009-1-1 150000 2010-1-1 180000 2011-1-1 210000 2012-1-1'.split("\n").map{|x| x.split} puts xirr(arr, 0.0) # => -0.021223951914845718 arr = '-700000 2008-1-1 120000 2009-1-1 150000 2010-1-1 180000 2011-1-1 210000 2012-1-1 260000 2013-1-1'.split("\n").map{|x| x.split} puts xirr(arr, 0.087) # => 0.08653506650983078 arr = '-700000 2008-1-1 120000 2009-1-1 150000 2010-1-1'.split("\n").map{|x| x.split} puts xirr(arr, -0.44) # => -0.4429793703341375