xirr_newton_calculator 0.0.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.
data/README.md ADDED
@@ -0,0 +1,4 @@
1
+ xirr-newton-calculator
2
+ ======================
3
+
4
+ A library to calculate Xirr using Newton Raphson algorithm
@@ -0,0 +1,54 @@
1
+ class XirrNewtonCalculator
2
+ # Calculate Xirr using Newton Raphson
3
+
4
+ # Arguments
5
+ # flows: (Array)
6
+ # init_rate: (Fixnum, Bignum)
7
+ # max_iteration: (Fixnum)
8
+
9
+
10
+ EPS = 10 ** -7
11
+
12
+ attr_writer :f_xn
13
+
14
+ def initialize(flows, init_rate, max_iteration=1000)
15
+ @flows = flows
16
+ @x_n = init_rate < 1 ? 1 / (1 + init_rate) : 0.5
17
+ @max_iteration = max_iteration
18
+ end
19
+
20
+ def calculate
21
+ @f_xn = f(@x_n)
22
+ iteration = 0
23
+ while @f_xn.abs >= EPS && iteration <= @max_iteration
24
+ @f_xn = f(@x_n)
25
+ @x_n = next_value(@x_n)
26
+ iteration += 1
27
+ end
28
+ discount_factor_to_irr(@x_n)
29
+ end
30
+
31
+ private
32
+
33
+ def next_value(x)
34
+ x - @f_xn.to_f/dfdx(x)
35
+ end
36
+
37
+ def dfdx(x)
38
+ @flows.inject(0) do |result, flow|
39
+ diff_date = (flow.date - @flows[0].date)/365
40
+ result += flow.value * diff_date * x.to_f ** (diff_date -1)
41
+ end
42
+ end
43
+
44
+ def f(x)
45
+ @f_xn = @flows.inject(0) do |result, flow|
46
+ diff_date = (flow.date - @flows[0].date)/365
47
+ result += flow.value * x.to_f ** diff_date
48
+ end
49
+ end
50
+
51
+ def discount_factor_to_irr (disc_fac)
52
+ 1.0/disc_fac - 1
53
+ end
54
+ end
@@ -0,0 +1,89 @@
1
+ require_relative '../lib/xirr_newton_calculator'
2
+ Transaction = Struct.new(:value, :date)
3
+
4
+ describe "XirrNewtonCalculator" do
5
+ before :each do
6
+ @flows = [
7
+ Transaction.new(-40, Date.new(2013,10,17)),
8
+ Transaction.new(11, Date.new(2013,11, 1)),
9
+ Transaction.new(11, Date.new(2013,12, 1)),
10
+ Transaction.new(11, Date.new(2014,1, 1)),
11
+ Transaction.new(11, Date.new(2014,2, 1))
12
+ ]
13
+ @init_rate = 0.15
14
+ end
15
+
16
+ let(:xirr_calculator) { XirrNewtonCalculator.new(@flows, @init_rate) }
17
+
18
+ describe "#calculate" do
19
+ it "returns 0.789" do
20
+ expect(xirr_calculator.calculate.round(3)).to eq 0.789
21
+ end
22
+
23
+ it "returns correct value" do
24
+ flows = []
25
+ flows << Transaction.new(-213_024_000, Date.new(2013, 10, 17))
26
+ flows << Transaction.new(10_011_582, Date.new(2013, 11, 7))
27
+ flows << Transaction.new(10_021_461, Date.new(2013, 12, 9))
28
+ flows << Transaction.new(10_030_258, Date.new(2014, 1, 7))
29
+ flows << Transaction.new(10_039_489, Date.new(2014, 2, 7))
30
+ flows << Transaction.new(10_048_642, Date.new(2014, 3, 7))
31
+ flows << Transaction.new(10_058_204, Date.new(2014, 4, 7))
32
+ flows << Transaction.new(10_067_615, Date.new(2014, 5, 7))
33
+ flows << Transaction.new(10_077_241, Date.new(2014, 6, 9))
34
+ flows << Transaction.new(10_086_750, Date.new(2014, 7, 7))
35
+ flows << Transaction.new(10_096_787, Date.new(2014, 8, 7))
36
+ flows << Transaction.new(10_106_729, Date.new(2014, 9, 8))
37
+ flows << Transaction.new(10_116_739, Date.new(2014, 10, 7))
38
+ flows << Transaction.new(10_127_085, Date.new(2014, 11, 7))
39
+ flows << Transaction.new(10_137_444, Date.new(2014, 12, 9))
40
+ flows << Transaction.new(10_147_891, Date.new(2015, 1, 7))
41
+ flows << Transaction.new(10_158_638, Date.new(2015, 2, 9))
42
+ flows << Transaction.new(10_169_341, Date.new(2015, 3, 9))
43
+ flows << Transaction.new(10_180_406, Date.new(2015, 4, 7))
44
+ flows << Transaction.new(10_191_572, Date.new(2015, 5, 7))
45
+ flows << Transaction.new(10_202_851, Date.new(2015, 6, 8))
46
+ flows << Transaction.new(10_214_228, Date.new(2015, 7, 7))
47
+ flows << Transaction.new(10_225_830, Date.new(2015, 8, 7))
48
+ flows << Transaction.new(10_237_550, Date.new(2015, 9, 7))
49
+ flows << Transaction.new(10_249_432, Date.new(2015, 10, 7))
50
+ xirr_calculator = XirrNewtonCalculator.new(flows, 0.15)
51
+ expect(xirr_calculator.calculate.round(6)).to eq 0.141087
52
+ end
53
+ end
54
+
55
+ describe "#next_value" do
56
+ it "calls dfdx" do
57
+ xirr_calculator.instance_variable_set(:@f_xn, 1)
58
+ xirr_calculator.should_receive(:dfdx).with(10).and_return(1)
59
+ xirr_calculator.send(:next_value,10)
60
+ end
61
+
62
+ it "returns proper value for x=1" do
63
+ xirr_calculator.stub(dfdx: 2)
64
+ xirr_calculator.f_xn = 1
65
+ expect(xirr_calculator.send(:next_value,1)).to eq 0.5
66
+ end
67
+ end
68
+
69
+ describe "#f" do
70
+ it "returns 4 for x = 1" do
71
+ expect(xirr_calculator.send(:f, 1)).to eq 4
72
+ end
73
+
74
+ it "returns -9.3 for x = 0.1" do
75
+ expect(xirr_calculator.send(:f, 0.1).round(1)).to eq -9.3
76
+ end
77
+ end
78
+
79
+ describe '#dfdx' do
80
+ it "returns 44.9 for x = 0.1" do
81
+ expect(xirr_calculator.send(:dfdx, 0.1).round(1)).to eq 44.9
82
+ end
83
+
84
+ it "returns 7.3 for x = 1" do
85
+ expect(xirr_calculator.send(:dfdx, 1).round(1)).to eq 7.3
86
+ end
87
+ end
88
+
89
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: xirr_newton_calculator
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - JP Colomer
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-10-17 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 2.14.1
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 2.14.1
30
+ description:
31
+ email: jpcolomer@gmail.com
32
+ executables: []
33
+ extensions: []
34
+ extra_rdoc_files: []
35
+ files:
36
+ - lib/xirr_newton_calculator.rb
37
+ - spec/xirr_newton_calculator_spec.rb
38
+ - README.md
39
+ homepage:
40
+ licenses:
41
+ - MIT
42
+ post_install_message:
43
+ rdoc_options: []
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ none: false
48
+ requirements:
49
+ - - ! '>='
50
+ - !ruby/object:Gem::Version
51
+ version: '1.9'
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ! '>='
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ requirements: []
59
+ rubyforge_project:
60
+ rubygems_version: 1.8.25
61
+ signing_key:
62
+ specification_version: 3
63
+ summary: a library to calculate xirr on Ruby.
64
+ test_files: []