Class: Xirr::Cashflow

Inherits:
Array
  • Object
show all
Defined in:
lib/xirr/cashflow.rb

Overview

Note:

A Cashflow should consist of at least two transactions, one positive and one negative.

Expands [Array] to store a set of transactions which will be used to calculate the XIRR

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(flow: [], period: Xirr::PERIOD, **options) ⇒ Cashflow

Returns a new instance of Cashflow.

Examples:

Creating a Cashflow

cf = Cashflow.new
cf << Transaction.new( 1000, date: '2013-01-01'.to_date)
cf << Transaction.new(-1234, date: '2013-03-31'.to_date)
Or
cf = Cashflow.new Transaction.new( 1000, date: '2013-01-01'.to_date), Transaction.new(-1234, date: '2013-03-31'.to_date)

Parameters:



15
16
17
18
19
20
21
# File 'lib/xirr/cashflow.rb', line 15

def initialize(flow: [], period: Xirr::PERIOD, ** options)
  @period   = period
  @fallback = options[:fallback] || Xirr::FALLBACK
  @options  = options
  self << flow
  self.flatten!
end

Instance Attribute Details

#fallbackObject (readonly)

Returns the value of attribute fallback.



6
7
8
# File 'lib/xirr/cashflow.rb', line 6

def fallback
  @fallback
end

#iteration_limitObject (readonly)

Returns the value of attribute iteration_limit.



6
7
8
# File 'lib/xirr/cashflow.rb', line 6

def iteration_limit
  @iteration_limit
end

#optionsObject (readonly)

Returns the value of attribute options.



6
7
8
# File 'lib/xirr/cashflow.rb', line 6

def options
  @options
end

#raise_exceptionObject (readonly)

Returns the value of attribute raise_exception.



6
7
8
# File 'lib/xirr/cashflow.rb', line 6

def raise_exception
  @raise_exception
end

Instance Method Details

#<<(arg) ⇒ Object



119
120
121
122
123
# File 'lib/xirr/cashflow.rb', line 119

def << arg
  super arg
  self.sort! { |x, y| x.date <=> y.date }
  self
end

#compact_cfObject



95
96
97
98
99
100
# File 'lib/xirr/cashflow.rb', line 95

def compact_cf
  # self
  compact = Hash.new 0
  self.each { |flow| compact[flow.date] += flow.amount }
  Cashflow.new flow: compact.map { |key, value| Transaction.new(value, date: key) }, options: options, period: period
end

#invalid?Boolean

Check if Cashflow is invalid

Returns:

  • (Boolean)


25
26
27
# File 'lib/xirr/cashflow.rb', line 25

def invalid?
  inflow.empty? || outflows.empty?
end

#invalid_messageString

Error message depending on the missing transaction

Returns:

  • (String)


110
111
112
113
# File 'lib/xirr/cashflow.rb', line 110

def invalid_message
  return 'No positive transaction' if inflow.empty?
  return 'No negative transaction' if outflows.empty?
end

#irr_guessFloat

Calculates a simple IRR guess based on period of investment and multiples.

Returns:

  • (Float)


49
50
51
52
53
# File 'lib/xirr/cashflow.rb', line 49

def irr_guess
  return @irr_guess = 0.0 if periods_of_investment.zero?
  @irr_guess = valid? ? ((multiple ** (1 / periods_of_investment)) - 1).round(3) : false
  @irr_guess == 1.0/0 ? 0.0 : @irr_guess
end

#max_dateTime

Last investment date

Returns:

  • (Time)


43
44
45
# File 'lib/xirr/cashflow.rb', line 43

def max_date
  @max_date ||= self.map(&:date).max
end

#min_dateTime

First investment date

Returns:

  • (Time)


104
105
106
# File 'lib/xirr/cashflow.rb', line 104

def min_date
  @min_date ||= self.map(&:date).min
end

#other_calculation_method(method) ⇒ Object



91
92
93
# File 'lib/xirr/cashflow.rb', line 91

def other_calculation_method(method)
  method == :newton_method ? :bisection : :newton_method
end

#periodObject



115
116
117
# File 'lib/xirr/cashflow.rb', line 115

def period
  @temporary_period || @period
end

#process_options(method, options) ⇒ Object



70
71
72
73
74
75
# File 'lib/xirr/cashflow.rb', line 70

def process_options(method, options)
  @temporary_period         = options[:period]
  options[:raise_exception] ||= @options[:raise_exception] || Xirr::RAISE_EXCEPTION
  options[:iteration_limit] ||= @options[:iteration_limit] || Xirr::ITERATION_LIMIT
  return switch_fallback(method), options
end

#sumFloat

Sums all amounts in a cashflow

Returns:

  • (Float)


37
38
39
# File 'lib/xirr/cashflow.rb', line 37

def sum
  self.map(&:amount).sum
end

#switch_fallback(method) ⇒ Symbol

If method is defined it will turn off fallback it return either the provided method or the system default

Parameters:

  • method (Symbol)

Returns:

  • (Symbol)


81
82
83
84
85
86
87
88
89
# File 'lib/xirr/cashflow.rb', line 81

def switch_fallback method
  if method
    @fallback = false
    method
  else
    @fallback = Xirr::FALLBACK
    Xirr::DEFAULT_METHOD
  end
end

#valid?Boolean

Inverse of #invalid?

Returns:

  • (Boolean)


31
32
33
# File 'lib/xirr/cashflow.rb', line 31

def valid?
  !invalid?
end

#xirr(guess: nil, method: nil, **options) ⇒ Float

Parameters:

  • guess (Float) (defaults to: nil)
  • method (Symbol) (defaults to: nil)

Returns:

  • (Float)


58
59
60
61
62
63
64
65
66
67
68
# File 'lib/xirr/cashflow.rb', line 58

def xirr(guess: nil, method: nil, ** options)
  method, options = process_options(method, options)
  if invalid?
    raise ArgumentError, invalid_message if options[:raise_exception]
    BigDecimal(0, Xirr::PRECISION)
  else
    xirr = choose_(method).send :xirr, guess, options
    xirr = choose_(other_calculation_method(method)).send(:xirr, guess, options) if (xirr.nil? || xirr.nan?) && fallback
    xirr || Xirr::REPLACE_FOR_NIL
  end
end