Module: Finance::Cashflow

Included in:
Array
Defined in:
lib/finance/cashflows.rb

Overview

Provides methods for working with cash flows (collections of transactions)

Defined Under Namespace

Classes: Function

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &block) ⇒ Object


59
60
61
62
# File 'lib/finance/cashflows.rb', line 59

def method_missing(name, *args, &block)
  return self.inject(:+) if name.to_s == "sum"
  super
end

Instance Method Details

#irrDecNum

calculate the internal rate of return for a sequence of cash flows

Examples:

[-4000,1200,1410,1875,1050].irr #=> 0.143

Returns:

  • (DecNum)

    the internal rate of return

See Also:


46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/finance/cashflows.rb', line 46

def irr
  # Make sure we have a valid sequence of cash flows.
  positives, negatives = self.partition{ |i| i >= 0 }
  if positives.empty? || negatives.empty?
    raise ArgumentError, "Calculation does not converge."
  end

  func = Function.new(self, :npv)
  rate = [ func.one ]
  nlsolve( func, rate )
  rate[0]
end

#npv(rate) ⇒ DecNum

calculate the net present value of a sequence of cash flows

Examples:

[-100.0, 60, 60, 60].npv(0.1) #=> 49.211

Parameters:

  • rate (Numeric)

    the discount rate to be applied

Returns:

  • (DecNum)

    the net present value

See Also:


71
72
73
74
75
76
77
78
79
80
# File 'lib/finance/cashflows.rb', line 71

def npv(rate)
  self.collect! { |entry| Flt::DecNum.new(entry.to_s) }

  rate, total = Flt::DecNum.new(rate.to_s), Flt::DecNum.new(0.to_s)
  self.each_with_index do |cashflow, index|
    total += cashflow / (1 + rate) ** index
  end

  total
end

#xirr(iterations = 100) ⇒ Rate

calculate the internal rate of return for a sequence of cash flows with dates

Examples:

@transactions = []
@transactions << Transaction.new(-1000, :date => Time.new(1985,01,01))
@transactions << Transaction.new(  600, :date => Time.new(1990,01,01))
@transactions << Transaction.new(  600, :date => Time.new(1995,01,01))
@transactions.xirr(0.6) #=> Rate("0.024851", :apr, :compounds => :annually)

Returns:

  • (Rate)

    the internal rate of return


91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/finance/cashflows.rb', line 91

def xirr(iterations=100)
  # Make sure we have a valid sequence of cash flows.
  positives, negatives = self.partition{ |t| t.amount >= 0 }
  if positives.empty? || negatives.empty?
    raise ArgumentError, "Calculation does not converge."
  end

  func = Function.new(self, :xnpv)
  rate = [ func.one ]
  nlsolve( func, rate )
  Rate.new(rate[0], :apr, :compounds => :annually)
end

#xnpv(rate) ⇒ DecNum

calculate the net present value of a sequence of cash flows

Examples:

@transactions = []
@transactions << Transaction.new(-1000, :date => Time.new(1985,01,01))
@transactions << Transaction.new(  600, :date => Time.new(1990,01,01))
@transactions << Transaction.new(  600, :date => Time.new(1995,01,01))
@transactions.xnpv(0.6).round(2) #=> -937.41

Returns:

  • (DecNum)

113
114
115
116
117
118
119
120
121
# File 'lib/finance/cashflows.rb', line 113

def xnpv(rate)
  rate  = Flt::DecNum.new(rate.to_s)
  start = self[0].date

  self.inject(0) do |sum, t|
    n = t.amount / ( (1 + rate) ** ((t.date-start) / Flt::DecNum.new(31536000.to_s))) # 365 * 86400
    sum + n
  end
end