xirr_newton_calculator 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: []