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.config.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:



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

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

Instance Attribute Details

#fallbackObject (readonly)

Returns the value of attribute fallback.



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

def fallback
  @fallback
end

#iteration_limitObject (readonly)

Returns the value of attribute iteration_limit.



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

def iteration_limit
  @iteration_limit
end

#optionsObject (readonly)

Returns the value of attribute options.



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

def options
  @options
end

#raise_exceptionObject (readonly)

Returns the value of attribute raise_exception.



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

def raise_exception
  @raise_exception
end

Instance Method Details

#<<(arg) ⇒ Object



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

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

#compact_cfObject



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

def compact_cf
  # self
  compact = Hash.new 0
  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)


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

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

#invalid_messageString

Error message depending on the missing transaction

Returns:

  • (String)


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

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)


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

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

#max_dateTime

Last investment date

Returns:

  • (Time)


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

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

#min_dateTime

First investment date

Returns:

  • (Time)


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

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

#other_calculation_method(method) ⇒ Object



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

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

#periodObject



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

def period
  @temporary_period || @period
end

#process_options(method, options) ⇒ Object



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

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

#sumFloat

Sums all amounts in a cashflow

Returns:

  • (Float)


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

def sum
  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)


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

def switch_fallback(method)
  if method
    @fallback = false
    method
  else
    @fallback = Xirr.config.fallback
    Xirr.config.default_method
  end
end

#valid?Boolean

Inverse of #invalid?

Returns:

  • (Boolean)


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

def valid?
  !invalid?
end

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

Parameters:

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

Returns:

  • (Float)


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

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.config.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.config.replace_for_nil
  end
end