wdss的blog

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

内部收益计算函数


曾经看过一个帖子:有一个理财产品,每年年初存入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

 

posted on 2017-07-10 16:43  wdss  阅读(972)  评论(0编辑  收藏  举报