xirr 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f37e42bdec94089e8afeeb382cdf5bc4fe4412a1
4
- data.tar.gz: d28de620d78c6017aa983de9f041cb269684b42b
3
+ metadata.gz: bfe1ad8aa4e571c85347827c80894312fcc0c2e1
4
+ data.tar.gz: dd2705ba456cccc2b6e01f1d10febdaf65cd7aef
5
5
  SHA512:
6
- metadata.gz: 427dbfd8aac84b0990549022018ca8c94833f24343a569ccfb21e2c66cdce2ac29b68fb779950fcdead40f1401ed5ea5b46a73a26fb9c497fd9ccb8f70f85e43
7
- data.tar.gz: 69b26e4cd30fc888662e3a36038c6a4a0059dc5ddbe9e2aa77425586b37a148fd6c86d055b50e908a0c555ddde9adb1dee3a7d8ca22a420855c209e2e2e6b49b
6
+ metadata.gz: 5e6b8f6b854db434c1e295f5421adaa5b4860c254e76bf7e38663a666c1cac34a925ccc11b44ebefd8f49ff72d2f2082275d7251432360341c0d7efbb2b8a60d
7
+ data.tar.gz: edd72d68efe8fc75192d01b1ad432b6f88b94c8d5c9767b7141a8ffa28bdb9148bcfa4b19d03501e3f7ecc8ea12e219c2ac6e785d0410c15c5d3884028d6388c
data/.travis.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  language: ruby
2
2
  rvm:
3
- - '2.1.2'
3
+ - '2.1.5'
4
4
  - '2.0.0'
5
5
  # - '1.9.3'
6
6
  script:
data/CHANGE_LOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## Version 0.3.1
2
+
3
+ * Added fallback to secondary calculation method.
4
+
1
5
  ## Version 0.3.0
2
6
 
3
7
  * Moved XNPV function to C.
data/lib/xirr/base.rb CHANGED
@@ -19,8 +19,9 @@ module Xirr
19
19
  (date - cf.min_date) / Xirr::DAYS_IN_YEAR
20
20
  end
21
21
 
22
- # Net Present Value funtion that will be used to reduce the cashflow
22
+ # Net Present Value function that will be used to reduce the cashflow
23
23
  # @param rate [BigDecimal]
24
+ # @return [BigDecimal]
24
25
  def xnpv(rate)
25
26
  cf.inject(0) do |sum, t|
26
27
  # sum += t.amount / (1 + rate) ** t_in_days(t.date)
@@ -28,13 +29,13 @@ module Xirr
28
29
  end
29
30
  end
30
31
 
31
- inline do |builder|
32
- builder.include "<math.h>"
33
- builder.c "
32
+ inline { |builder|
33
+ builder.include '<math.h>'
34
+ builder.c '
34
35
  double xnpv_c(double rate, double amount, double days) {
35
36
  return amount / pow(1 + rate, days);
36
- }"
37
- end
37
+ }'
38
+ }
38
39
 
39
40
  end
40
41
  end
@@ -32,7 +32,8 @@ module Xirr
32
32
 
33
33
  # If enabled, will retry XIRR with NewtonMethod
34
34
  if Xirr::FALLBACK && right_limit_reached?(midpoint)
35
- return NewtonMethod.new(cf).xirr
35
+ # return NewtonMethod.new(cf).xirr
36
+ return nil
36
37
  end
37
38
 
38
39
  return midpoint.round Xirr::PRECISION
data/lib/xirr/cashflow.rb CHANGED
@@ -49,10 +49,10 @@ module Xirr
49
49
  # @param guess [Float]
50
50
  # @param method [Symbol]
51
51
  # @return [Float]
52
- # Finds the XIRR according to the method provided. Default to Bisection
52
+ # Finds the XIRR according to the method provided.
53
53
  def xirr_with_exception(guess = nil, method = Xirr.config.default_method)
54
54
  if valid?
55
- choose_(method).send :xirr, guess
55
+ choose_(method).send(:xirr, guess) || choose_(method == :newton_method ? :bisection : :newton_method).send(:xirr, guess)
56
56
  else
57
57
  raise ArgumentError, invalid_message
58
58
  end
@@ -103,7 +103,7 @@ module Xirr
103
103
  # @api private
104
104
  # Sorts the {Cashflow} by date ascending
105
105
  # and finds the signal of the first transaction.
106
- # This implies the first transaction is a disembursement
106
+ # This implies the first transaction is a disbursement
107
107
  # @return [Integer]
108
108
  def first_transaction_direction
109
109
  self.sort! { |x, y| x.date <=> y.date }
@@ -130,29 +130,17 @@ module Xirr
130
130
  # @api private
131
131
  # @return [Array]
132
132
  # @see #negatives
133
- # @see #split_transactions
134
- # Finds all transactions income from Cashflow
133
+ # Selects all positives transactions from Cashflow
135
134
  def positives
136
- split_transactions
137
- @positives
135
+ @positives ||= self.select { |x| x.amount < 0 }
138
136
  end
139
137
 
140
138
  # @api private
141
139
  # @return [Array]
142
140
  # @see #positives
143
- # @see #split_transactions
144
- # Finds all transactions investments from Cashflow
141
+ # Selects all negatives transactions from Cashflow
145
142
  def negatives
146
- split_transactions
147
- @negatives
148
- end
149
-
150
- # @api private
151
- # @see #positives
152
- # @see #negatives
153
- # Uses partition to separate the investment transactions Negatives and the income transactions (Positives)
154
- def split_transactions
155
- @negatives, @positives = self.partition { |x| x.amount > 0 } # Inverted as negative amount is good
143
+ @negatives ||= self.select { |x| x.amount > 0 }
156
144
  end
157
145
 
158
146
  end
data/lib/xirr/config.rb CHANGED
@@ -7,13 +7,14 @@ module Xirr
7
7
  days_in_year: 365,
8
8
  iteration_limit: 50,
9
9
  precision: 6,
10
- default_method: :bisection,
10
+ # default_method: :bisection,
11
+ default_method: :newton_method,
11
12
  fallback: true
12
13
  }
13
14
 
14
- # Iterates trhough default values and sets in config
15
+ # Iterates though default values and sets in config
15
16
  default_values.each do |key, value|
16
17
  self.config.send("#{key.to_sym}=", value)
17
18
  const_set key.to_s.upcase.to_sym, value
18
19
  end
19
- end
20
+ end
@@ -11,10 +11,10 @@ module Xirr
11
11
  class Function
12
12
  values = {
13
13
  eps: Xirr::EPS,
14
- one: "1.0",
15
- two: "2.0",
16
- ten: "10.0",
17
- zero: "0.0"
14
+ one: '1.0',
15
+ two: '2.0',
16
+ ten: '10.0',
17
+ zero: '0.0'
18
18
  }
19
19
 
20
20
  # define default values
@@ -46,8 +46,12 @@ module Xirr
46
46
  def xirr(guess=nil)
47
47
  func = Function.new(self, :xnpv)
48
48
  rate = [guess || cf.irr_guess.to_f]
49
- nlsolve(func, rate)
50
- rate[0].round Xirr::PRECISION
49
+ begin
50
+ nlsolve(func, rate)
51
+ rate[0].round Xirr::PRECISION
52
+ rescue
53
+ nil
54
+ end
51
55
  end
52
56
  end
53
57
  end
data/lib/xirr/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Xirr
2
2
  # Version of the Gem
3
- VERSION = "0.3.0"
3
+ VERSION = '0.3.1'
4
4
  end
@@ -2,7 +2,7 @@ require_relative 'test_helper'
2
2
 
3
3
  describe 'Cashflows' do
4
4
 
5
- describe 'of a ok investment' do
5
+ describe 'of an ok investment' do
6
6
  before(:all) do
7
7
  @cf = Cashflow.new
8
8
  @cf << Transaction.new(1000, date: '1985-01-01'.to_date)
@@ -10,6 +10,10 @@ describe 'Cashflows' do
10
10
  @cf << Transaction.new(-6000, date: '1995-01-01'.to_date)
11
11
  end
12
12
 
13
+ it 'has a sum of its transactions' do
14
+ assert_equal '-5600'.to_f, @cf.sum
15
+ end
16
+
13
17
  it 'with a wrong method is invalid' do
14
18
  assert_raises(ArgumentError) { @cf.xirr(nil, :no_method) }
15
19
  end
@@ -18,12 +22,12 @@ describe 'Cashflows' do
18
22
  assert_equal '0.225683'.to_f, @cf.xirr
19
23
  end
20
24
 
21
- it 'has an Internal Rate of Return on default Method' do
25
+ it 'has an Internal Rate of Return on Bisection Method' do
22
26
  assert_equal '0.225683'.to_f, @cf.xirr(nil, :bisection)
23
27
  end
24
28
 
25
29
  it 'has an Internal Rate of Return on Bisection Method using a Guess' do
26
- assert_in_delta 0.225683, @cf.xirr(0.15).to_f, 0.000002
30
+ assert_in_delta '0.225683'.to_f, @cf.xirr(0.15).to_f, 0.000002
27
31
  end
28
32
 
29
33
  it 'has an Internal Rate of Return on Newton Method' do
@@ -49,11 +53,11 @@ describe 'Cashflows' do
49
53
  end
50
54
 
51
55
  it 'has an Internal Rate of Return on Bisection Method' do
52
- assert_equal '0.225683'.to_f, @cf.xirr
56
+ assert_equal '0.225683'.to_f, @cf.xirr(nil, :bisection)
53
57
  end
54
58
 
55
59
  it 'has an Internal Rate of Return on Bisection Method using a Guess' do
56
- assert_in_delta 0.225683, @cf.xirr(0.15).to_f, 0.000002
60
+ assert_in_delta '0.225683'.to_f, @cf.xirr(0.15).to_f, 0.000002
57
61
  end
58
62
 
59
63
  it 'has an Internal Rate of Return on Newton Method' do
@@ -74,7 +78,7 @@ describe 'Cashflows' do
74
78
  end
75
79
 
76
80
  it 'has an Internal Rate of Return on Bisection Method' do
77
- assert_equal '22.352206 '.to_f, @cf.xirr
81
+ assert_equal '22.352206 '.to_f, @cf.xirr(nil, :bisection)
78
82
  end
79
83
 
80
84
  it 'has a sum of its transactions' do
@@ -98,11 +102,11 @@ describe 'Cashflows' do
98
102
  end
99
103
 
100
104
  it 'has an Internal Rate of Return on Bisection Method' do
101
- assert_equal '1.0597572345993451e+284'.to_f, @cf.xirr
105
+ assert_equal '1.0597572345993451e+284'.to_f, @cf.xirr(nil, :bisection)
102
106
  end
103
107
 
104
108
  it 'has an Internal Rate of Return on Bisection Method using a bad Guess' do
105
- assert_raises(ArgumentError) { @cf.xirr(0.15) }
109
+ assert_raises(ArgumentError) { @cf.xirr(0.15, :bisection) }
106
110
  end
107
111
 
108
112
  it 'has an Internal Rate of Return on Newton Method' do
@@ -155,11 +159,11 @@ describe 'Cashflows' do
155
159
  assert true, !@cf.valid?
156
160
  end
157
161
 
158
- it 'raises error when xirr is called' do
162
+ it 'raises error when #xirr is called' do
159
163
  assert_raises(ArgumentError) { @cf.xirr_with_exception }
160
164
  end
161
165
 
162
- it 'raises error when xirr is called' do
166
+ it 'is invalid when #irr_guess is called' do
163
167
  assert true, !@cf.irr_guess
164
168
  end
165
169
  end
@@ -195,7 +199,7 @@ describe 'Cashflows' do
195
199
  end
196
200
 
197
201
  it 'has an Internal Rate of Return on Bisection Method' do
198
- assert_equal '0.112339'.to_f, @cf.xirr
202
+ assert_equal '0.112339'.to_f, @cf.xirr(nil, :bisection)
199
203
  end
200
204
 
201
205
  it 'has an Internal Rate of Return on Newton Method' do
@@ -208,4 +212,49 @@ describe 'Cashflows' do
208
212
 
209
213
  end
210
214
 
215
+ describe 'of a real case' do
216
+ before(:all) do
217
+ @cf = Cashflow.new
218
+ @cf << Transaction.new(105187.06, date: '2011-12-07'.to_date)
219
+ @cf << Transaction.new(816709.66, date: '2011-12-07'.to_date)
220
+ @cf << Transaction.new(479069.684, date: '2011-12-07'.to_date)
221
+ @cf << Transaction.new(937309.708, date: '2012-01-18'.to_date)
222
+ @cf << Transaction.new(88622.661, date: '2012-07-03'.to_date)
223
+ @cf << Transaction.new(100000.0, date: '2012-07-03'.to_date)
224
+ @cf << Transaction.new(80000.0, date: '2012-07-19'.to_date)
225
+ @cf << Transaction.new(403627.95, date: '2012-07-23'.to_date)
226
+ @cf << Transaction.new(508117.9, date: '2012-07-23'.to_date)
227
+ @cf << Transaction.new(789706.87, date: '2012-07-23'.to_date)
228
+ @cf << Transaction.new(-88622.661, date: '2012-09-11'.to_date)
229
+ @cf << Transaction.new(-789706.871, date: '2012-09-11'.to_date)
230
+ @cf << Transaction.new(-688117.9, date: '2012-09-11'.to_date)
231
+ @cf << Transaction.new(-403627.95, date: '2012-09-11'.to_date)
232
+ @cf << Transaction.new(403627.95, date: '2012-09-12'.to_date)
233
+ @cf << Transaction.new(789706.871, date: '2012-09-12'.to_date)
234
+ @cf << Transaction.new(88622.661, date: '2012-09-12'.to_date)
235
+ @cf << Transaction.new(688117.9, date: '2012-09-12'.to_date)
236
+ @cf << Transaction.new(45129.14, date: '2013-03-11'.to_date)
237
+ @cf << Transaction.new(26472.08, date: '2013-03-11'.to_date)
238
+ @cf << Transaction.new(51793.2, date: '2013-03-11'.to_date)
239
+ @cf << Transaction.new(126605.59, date: '2013-03-11'.to_date)
240
+ @cf << Transaction.new(278532.29, date: '2013-03-28'.to_date)
241
+ @cf << Transaction.new(99284.1, date: '2013-03-28'.to_date)
242
+ @cf << Transaction.new(58238.57, date: '2013-03-28'.to_date)
243
+ @cf << Transaction.new(113945.03, date: '2013-03-28'.to_date)
244
+ @cf << Transaction.new(405137.88, date: '2013-05-21'.to_date)
245
+ @cf << Transaction.new(-405137.88, date: '2013-05-21'.to_date)
246
+ @cf << Transaction.new(165738.23, date: '2013-05-21'.to_date)
247
+ @cf << Transaction.new(-165738.23, date: '2013-05-21'.to_date)
248
+ @cf << Transaction.new(144413.24, date: '2013-05-21'.to_date)
249
+ @cf << Transaction.new(84710.65, date: '2013-05-21'.to_date)
250
+ @cf << Transaction.new(-84710.65, date: '2013-05-21'.to_date)
251
+ @cf << Transaction.new(-144413.24, date: '2013-05-21'.to_date)
252
+ end
253
+
254
+ it 'has an Internal Rate of Return on Newton Method HERE' do
255
+ assert_equal '-0.99'.to_f, @cf.xirr(nil, :newton_method)
256
+ end
257
+
258
+ end
259
+
211
260
  end
data/xirr.gemspec CHANGED
@@ -4,26 +4,26 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'xirr/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
- spec.name = 'xirr'
8
- spec.version = Xirr::VERSION
9
- spec.authors = ['tubedude']
10
- spec.email = ['beto@trevisan.me']
11
- spec.summary = %q{Calculates XIRR (Bisection and Newton method) of a cashflow}
12
- spec.description = %q{Calculates IRR of a Cashflow, simillar to Excels, XIRR formula, but using the Bisection Method and Newton Method.}
13
- spec.homepage = 'https://github.com/tubedude/xirr'
14
- spec.license = 'MIT'
7
+ spec.name = 'xirr'
8
+ spec.version = Xirr::VERSION
9
+ spec.authors = ['tubedude']
10
+ spec.email = ['beto@trevisan.me']
11
+ spec.summary = %q{Calculates XIRR (Bisection and Newton method) of a cashflow}
12
+ spec.description = %q{Calculates IRR of a Cashflow, similar to Excel's, XIRR formula. It defaults to Newton Method, but will calculate Bisection as well.}
13
+ spec.homepage = 'https://github.com/tubedude/xirr'
14
+ spec.license = 'MIT'
15
15
 
16
- spec.files = `git ls-files -z`.split("\x0")
17
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ['lib']
20
20
 
21
21
  spec.add_development_dependency 'bundler', '~> 1.6'
22
22
  spec.add_development_dependency 'rake', '~> 10'
23
23
 
24
24
  spec.required_ruby_version = '>=2.0'
25
- spec.add_dependency 'activesupport', '~> 4.0'
26
- spec.add_dependency 'RubyInline', '> 3'
25
+ spec.add_dependency 'activesupport', '~> 4'
26
+ spec.add_dependency 'RubyInline', '~> 3'
27
27
  spec.add_development_dependency 'minitest', '~> 5.4'
28
28
  spec.add_development_dependency 'coveralls', '~> 0'
29
29
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xirr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - tubedude
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-10 00:00:00.000000000 Z
11
+ date: 2014-11-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -44,26 +44,26 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '4.0'
47
+ version: '4'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '4.0'
54
+ version: '4'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: RubyInline
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ">"
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
61
  version: '3'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ">"
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '3'
69
69
  - !ruby/object:Gem::Dependency
@@ -94,8 +94,8 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
- description: Calculates IRR of a Cashflow, simillar to Excels, XIRR formula, but using
98
- the Bisection Method and Newton Method.
97
+ description: Calculates IRR of a Cashflow, similar to Excel's, XIRR formula. It defaults
98
+ to Newton Method, but will calculate Bisection as well.
99
99
  email:
100
100
  - beto@trevisan.me
101
101
  executables: []