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 +4 -0
- data/lib/xirr_newton_calculator.rb +54 -0
- data/spec/xirr_newton_calculator_spec.rb +89 -0
- metadata +64 -0
data/README.md
ADDED
@@ -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: []
|