refinance 0.0.1 → 1.0.0
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/LICENSE.txt +1 -1
- data/README.md +8 -6
- data/lib/refinance/version.rb +1 -1
- data/refinance.gemspec +2 -2
- data/test/bigdecimal_annuities_test.rb +32 -79
- data/test/float_annuities_test.rb +20 -80
- data/test/refinance_test.rb +9 -3
- data/test/test_helper.rb +60 -0
- metadata +10 -8
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -5,15 +5,17 @@ Currently, it contains algorithms for calculating the properties of ordinary
|
|
5
5
|
annuities: principal, interest rate, number of payment periods, and payment
|
6
6
|
amount.
|
7
7
|
|
8
|
-
The algorithms are simple rather than fast
|
9
|
-
|
10
|
-
|
11
|
-
payment)
|
8
|
+
The algorithms are simple rather than fast and numerically robust. Thanks to
|
9
|
+
duck typing, they work with both BigDecimals and Floats. At present, they deal
|
10
|
+
only with _annuities immediate_ (in which the interest is accumulated _before_
|
11
|
+
the payment), not _annuities due_ (in which the interest is accumulated _after_
|
12
|
+
the payment). There are many opportunities for extension and improvement.
|
12
13
|
|
13
14
|
## Requirements
|
14
15
|
|
15
|
-
This library
|
16
|
-
1.9.2 if you only use Float, not
|
16
|
+
This library is tested with versions 1.9.3 and 2.0.0 of MRI (Matz's Ruby
|
17
|
+
Interpreter). It also works with version 1.9.2 if you only use Float, not
|
18
|
+
BigDecimal, for floating-point values.
|
17
19
|
|
18
20
|
## Installation
|
19
21
|
|
data/lib/refinance/version.rb
CHANGED
data/refinance.gemspec
CHANGED
@@ -19,6 +19,6 @@ Gem::Specification.new do |gem|
|
|
19
19
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
20
20
|
gem.require_paths = ["lib"]
|
21
21
|
|
22
|
-
gem.add_development_dependency 'rake', '0.
|
23
|
-
gem.add_development_dependency 'minitest', '
|
22
|
+
gem.add_development_dependency 'rake', '10.0.4'
|
23
|
+
gem.add_development_dependency 'minitest', '4.7.4'
|
24
24
|
end
|
@@ -1,109 +1,62 @@
|
|
1
|
-
require '
|
1
|
+
require 'test_helper'
|
2
2
|
require 'bigdecimal'
|
3
|
-
require 'refinance'
|
4
3
|
|
5
|
-
class BigDecimalAnnuitiesTest <
|
4
|
+
class BigDecimalAnnuitiesTest < AnnuitiesTest
|
6
5
|
|
7
6
|
def test_improve_interest_rate
|
8
7
|
# Based on Example 6 in http://oakroadsystems.com/math/loan.htm .
|
9
|
-
payment
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
expected = BigDecimal.new('0.0094295242')
|
15
|
-
actual = Refinance::Annuities.improve_interest_rate(payment, periods,
|
16
|
-
principal, guess)
|
17
|
-
|
18
|
-
assert_in_delta expected, actual, BigDecimal.new('0.00000001')
|
8
|
+
assert_improve_interest_rate payment: BigDecimal.new('291'),
|
9
|
+
periods: BigDecimal.new('48'), principal: BigDecimal.new('11200'),
|
10
|
+
guess: BigDecimal.new('0.01'), expected: BigDecimal.new('0.0094295242'),
|
11
|
+
delta: BigDecimal.new('0.00000001')
|
19
12
|
end
|
20
13
|
|
21
14
|
def test_interest_rate_stops_if_improvement_is_small
|
22
15
|
# Based on Example 6 in http://oakroadsystems.com/math/loan.htm .
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
expected = BigDecimal.new('0.0094295242')
|
30
|
-
actual = Refinance::Annuities.interest_rate(payment, periods, principal,
|
31
|
-
guess, imprecision)
|
32
|
-
|
33
|
-
assert_in_delta expected, actual, BigDecimal.new('0.00000001')
|
34
|
-
end
|
35
|
-
|
36
|
-
def test_interest_rate_stops_if_max_iterations_reached
|
37
|
-
extreme_precision = BigDecimal.new('0')
|
38
|
-
guess = BigDecimal.new('0.01')
|
39
|
-
|
40
|
-
expected = guess
|
41
|
-
actual = Refinance::Annuities.interest_rate(0, 0, 0, guess,
|
42
|
-
extreme_precision, 1, 0)
|
43
|
-
|
44
|
-
assert_equal expected, actual
|
16
|
+
assert_interest_rate_stops_if_improvement_is_small \
|
17
|
+
payment: BigDecimal.new('291'), periods: BigDecimal.new('48'),
|
18
|
+
principal: BigDecimal.new('11200'), guess: BigDecimal.new('0.01'),
|
19
|
+
precision: BigDecimal.new('0.5'),
|
20
|
+
expected: BigDecimal.new('0.0094295242'),
|
21
|
+
delta: BigDecimal.new('0.00000001')
|
45
22
|
end
|
46
23
|
|
47
24
|
def test_interest_rate_does_multiple_iterations
|
48
25
|
# Based on Example 6 in http://oakroadsystems.com/math/loan.htm .
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
expected = BigDecimal.new('0.0094007411')
|
57
|
-
actual = Refinance::Annuities.interest_rate(payment, periods, principal,
|
58
|
-
guess, extreme_precision, 10, 4)
|
59
|
-
|
60
|
-
assert_in_delta expected, actual, BigDecimal.new('0.0000000001')
|
26
|
+
assert_interest_rate_does_multiple_iterations \
|
27
|
+
payment: BigDecimal.new('291'), periods: BigDecimal.new('48'),
|
28
|
+
principal: BigDecimal.new('11200'), guess: BigDecimal.new('0.01'),
|
29
|
+
precision: BigDecimal.new('0'), max_decimals: 10, max_iterations: 4,
|
30
|
+
expected: BigDecimal.new('0.0094007411'),
|
31
|
+
delta: BigDecimal.new('0.0000000001')
|
61
32
|
end
|
62
33
|
|
63
34
|
def test_payment
|
64
35
|
# Based on Example 2 in http://oakroadsystems.com/math/loan.htm .
|
65
|
-
interest_rate
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
expected = BigDecimal.new('1619.708627')
|
70
|
-
actual = Refinance::Annuities.payment(interest_rate, periods, principal)
|
71
|
-
|
72
|
-
assert_in_delta expected, actual, BigDecimal.new('0.000001')
|
36
|
+
assert_payment interest_rate: BigDecimal.new('0.0065'),
|
37
|
+
periods: BigDecimal.new('360'), principal: BigDecimal.new('225000'),
|
38
|
+
expected: BigDecimal.new('1619.708627'),
|
39
|
+
delta: BigDecimal.new('0.000001')
|
73
40
|
end
|
74
41
|
|
75
42
|
def test_periods
|
76
43
|
# Based on Example 3 in http://oakroadsystems.com/math/loan.htm .
|
77
|
-
interest_rate
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
expected = BigDecimal.new('38.57')
|
82
|
-
actual = Refinance::Annuities.periods(interest_rate, payment, principal)
|
83
|
-
|
84
|
-
assert_in_delta expected, actual, BigDecimal.new('0.01')
|
44
|
+
assert_periods interest_rate: BigDecimal.new('0.005'),
|
45
|
+
payment: BigDecimal.new('100.0'), principal: BigDecimal.new('3500.0'),
|
46
|
+
expected: BigDecimal.new('38.57'), delta: BigDecimal.new('0.01')
|
85
47
|
end
|
86
48
|
|
87
49
|
def test_principal
|
88
50
|
# Based on Example 5 in http://oakroadsystems.com/math/loan.htm .
|
89
|
-
interest_rate
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
expected = BigDecimal.new('1685.26') # Example fudges to 1685.25.
|
94
|
-
actual = Refinance::Annuities.principal(interest_rate, payment, periods)
|
95
|
-
|
96
|
-
assert_in_delta expected, actual, BigDecimal.new('0.01')
|
51
|
+
assert_principal interest_rate: BigDecimal.new('0.014083'),
|
52
|
+
payment: BigDecimal.new('60'), periods: BigDecimal.new('36'),
|
53
|
+
expected: BigDecimal.new('1685.26'), delta: BigDecimal.new('0.01')
|
97
54
|
end
|
98
55
|
|
99
56
|
def test_effective_interest_rate
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
actual = Refinance::Annuities.effective_interest_rate(
|
105
|
-
nominal_annual_interest_rate, compounding_periods_per_year)
|
106
|
-
|
107
|
-
assert_in_delta expected, actual, BigDecimal.new('0.00001')
|
57
|
+
assert_effective_interest_rate \
|
58
|
+
nominal_annual_interest_rate: BigDecimal.new('0.1'),
|
59
|
+
compounding_periods_per_year: BigDecimal.new('12'),
|
60
|
+
expected: BigDecimal.new('0.10471'), delta: BigDecimal.new('0.00001')
|
108
61
|
end
|
109
62
|
end
|
@@ -1,108 +1,48 @@
|
|
1
|
-
require '
|
2
|
-
require 'refinance'
|
1
|
+
require 'test_helper'
|
3
2
|
|
4
|
-
class FloatAnnuitiesTest <
|
3
|
+
class FloatAnnuitiesTest < AnnuitiesTest
|
5
4
|
|
6
5
|
def test_improve_interest_rate
|
7
6
|
# Based on Example 6 in http://oakroadsystems.com/math/loan.htm .
|
8
|
-
payment
|
9
|
-
|
10
|
-
|
11
|
-
guess = 0.01
|
12
|
-
|
13
|
-
expected = 0.0094295242
|
14
|
-
actual = Refinance::Annuities.improve_interest_rate(payment, periods,
|
15
|
-
principal, guess)
|
16
|
-
|
17
|
-
assert_in_delta expected, actual, 0.00000001
|
7
|
+
assert_improve_interest_rate payment: 291.0, periods: 48.0,
|
8
|
+
principal: 11200.0, guess: 0.01, expected: 0.0094295242,
|
9
|
+
delta: 0.00000001
|
18
10
|
end
|
19
11
|
|
20
12
|
def test_interest_rate_stops_if_improvement_is_small
|
21
13
|
# Based on Example 6 in http://oakroadsystems.com/math/loan.htm .
|
22
|
-
payment
|
23
|
-
|
24
|
-
|
25
|
-
guess = 0.01
|
26
|
-
imprecision = 0.5
|
27
|
-
|
28
|
-
expected = 0.0094295242
|
29
|
-
actual = Refinance::Annuities.interest_rate(payment, periods, principal,
|
30
|
-
guess, imprecision)
|
31
|
-
|
32
|
-
assert_in_delta expected, actual, 0.00000001
|
33
|
-
end
|
34
|
-
|
35
|
-
def test_interest_rate_stops_if_max_iterations_reached
|
36
|
-
extreme_precision = 0.0
|
37
|
-
guess = 0.01
|
38
|
-
|
39
|
-
expected = guess
|
40
|
-
actual = Refinance::Annuities.interest_rate(0, 0, 0, guess,
|
41
|
-
extreme_precision, 1, 0)
|
42
|
-
|
43
|
-
assert_equal expected, actual
|
14
|
+
assert_interest_rate_stops_if_improvement_is_small payment: 291.0,
|
15
|
+
periods: 48.0, principal: 11200.0, guess: 0.01, precision: 0.5,
|
16
|
+
expected: 0.0094295242, delta: 0.00000001
|
44
17
|
end
|
45
18
|
|
46
19
|
def test_interest_rate_does_multiple_iterations
|
47
20
|
# Based on Example 6 in http://oakroadsystems.com/math/loan.htm .
|
48
|
-
payment
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
extreme_precision = 0.0
|
53
|
-
max_iterations = 4
|
54
|
-
|
55
|
-
expected = 0.0094007411
|
56
|
-
actual = Refinance::Annuities.interest_rate(payment, periods, principal,
|
57
|
-
guess, extreme_precision, 10, 4)
|
58
|
-
|
59
|
-
assert_in_delta expected, actual, 0.0000000001
|
21
|
+
assert_interest_rate_does_multiple_iterations payment: 291.0,
|
22
|
+
periods: 48.0, principal: 11200.0, guess: 0.01, precision: 0.0,
|
23
|
+
max_decimals: 10, max_iterations: 4, expected: 0.0094007411,
|
24
|
+
delta: 0.0000000001
|
60
25
|
end
|
61
26
|
|
62
27
|
def test_payment
|
63
|
-
|
64
|
-
|
65
|
-
periods = 360.0
|
66
|
-
principal = 225000.0
|
67
|
-
|
68
|
-
expected = 1619.708627
|
69
|
-
actual = Refinance::Annuities.payment(interest_rate, periods, principal)
|
70
|
-
|
71
|
-
assert_in_delta expected, actual, 0.000001
|
28
|
+
assert_payment interest_rate: 0.0065, periods: 360.0, principal: 225000.0,
|
29
|
+
expected: 1619.708627, delta: 0.000001
|
72
30
|
end
|
73
31
|
|
74
32
|
def test_periods
|
75
33
|
# Based on Example 3 in http://oakroadsystems.com/math/loan.htm .
|
76
|
-
interest_rate
|
77
|
-
|
78
|
-
principal = 3500.0
|
79
|
-
|
80
|
-
expected = 38.57
|
81
|
-
actual = Refinance::Annuities.periods(interest_rate, payment, principal)
|
82
|
-
|
83
|
-
assert_in_delta expected, actual, 0.01
|
34
|
+
assert_periods interest_rate: 0.005, payment: 100.0, principal: 3500.0,
|
35
|
+
expected: 38.57, delta: 0.01
|
84
36
|
end
|
85
37
|
|
86
38
|
def test_principal
|
87
39
|
# Based on Example 5 in http://oakroadsystems.com/math/loan.htm .
|
88
|
-
interest_rate
|
89
|
-
|
90
|
-
periods = 36.0
|
91
|
-
|
92
|
-
expected = 1685.26 # Example fudges to 1685.25.
|
93
|
-
actual = Refinance::Annuities.principal(interest_rate, payment, periods)
|
94
|
-
|
95
|
-
assert_in_delta expected, actual, 0.01
|
40
|
+
assert_principal interest_rate: 0.014083, payment: 60.0, periods: 36.0,
|
41
|
+
expected: 1685.26, delta: 0.01
|
96
42
|
end
|
97
43
|
|
98
44
|
def test_effective_interest_rate
|
99
|
-
nominal_annual_interest_rate
|
100
|
-
|
101
|
-
|
102
|
-
expected = 0.10471
|
103
|
-
actual = Refinance::Annuities.effective_interest_rate(
|
104
|
-
nominal_annual_interest_rate, compounding_periods_per_year)
|
105
|
-
|
106
|
-
assert_in_delta expected, actual, 0.00001
|
45
|
+
assert_effective_interest_rate nominal_annual_interest_rate: 0.1,
|
46
|
+
compounding_periods_per_year: 12.0, expected: 0.10471, delta: 0.00001
|
107
47
|
end
|
108
48
|
end
|
data/test/refinance_test.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
|
-
require '
|
2
|
-
require 'refinance'
|
1
|
+
require 'test_helper'
|
3
2
|
|
4
|
-
class RefinanceTest <
|
3
|
+
class RefinanceTest < Minitest::Unit::TestCase
|
5
4
|
def test_refinance_is_a_module
|
6
5
|
assert_kind_of Module, ::Refinance
|
7
6
|
end
|
@@ -9,4 +8,11 @@ class RefinanceTest < MiniTest::Unit::TestCase
|
|
9
8
|
def test_version_is_a_string
|
10
9
|
assert_kind_of String, ::Refinance::VERSION
|
11
10
|
end
|
11
|
+
|
12
|
+
def test_interest_rate_stops_if_max_iterations_reached
|
13
|
+
expected = 0.42
|
14
|
+
actual = Refinance::Annuities.interest_rate(0, 0, 0, expected, 0, 1, 0)
|
15
|
+
|
16
|
+
assert_equal expected, actual
|
17
|
+
end
|
12
18
|
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'refinance'
|
3
|
+
|
4
|
+
class AnnuitiesTest < Minitest::Unit::TestCase
|
5
|
+
def assert_improve_interest_rate options
|
6
|
+
actual = Refinance::Annuities.improve_interest_rate(
|
7
|
+
options.fetch(:payment),
|
8
|
+
options.fetch(:periods),
|
9
|
+
options.fetch(:principal),
|
10
|
+
options.fetch(:guess))
|
11
|
+
|
12
|
+
assert_in_delta options.fetch(:expected), actual, options.fetch(:delta)
|
13
|
+
end
|
14
|
+
|
15
|
+
def assert_interest_rate_stops_if_improvement_is_small options
|
16
|
+
actual = Refinance::Annuities.interest_rate(options.fetch(:payment),
|
17
|
+
options.fetch(:periods), options.fetch(:principal),
|
18
|
+
options.fetch(:guess), options.fetch(:precision))
|
19
|
+
|
20
|
+
assert_in_delta options.fetch(:expected), actual, options.fetch(:delta)
|
21
|
+
end
|
22
|
+
|
23
|
+
def assert_interest_rate_does_multiple_iterations options
|
24
|
+
actual = Refinance::Annuities.interest_rate(options.fetch(:payment),
|
25
|
+
options.fetch(:periods), options.fetch(:principal),
|
26
|
+
options.fetch(:guess), options.fetch(:precision),
|
27
|
+
options.fetch(:max_decimals), options.fetch(:max_iterations))
|
28
|
+
|
29
|
+
assert_in_delta options.fetch(:expected), actual, options.fetch(:delta)
|
30
|
+
end
|
31
|
+
|
32
|
+
def assert_payment options
|
33
|
+
actual = Refinance::Annuities.payment(options.fetch(:interest_rate),
|
34
|
+
options.fetch(:periods), options.fetch(:principal))
|
35
|
+
|
36
|
+
assert_in_delta options.fetch(:expected), actual, options.fetch(:delta)
|
37
|
+
end
|
38
|
+
|
39
|
+
def assert_periods options
|
40
|
+
actual = Refinance::Annuities.periods(options.fetch(:interest_rate),
|
41
|
+
options.fetch(:payment), options.fetch(:principal))
|
42
|
+
|
43
|
+
assert_in_delta options.fetch(:expected), actual, options.fetch(:delta)
|
44
|
+
end
|
45
|
+
|
46
|
+
def assert_principal options
|
47
|
+
actual = Refinance::Annuities.principal(options.fetch(:interest_rate),
|
48
|
+
options.fetch(:payment), options.fetch(:periods))
|
49
|
+
|
50
|
+
assert_in_delta options.fetch(:expected), actual, options.fetch(:delta)
|
51
|
+
end
|
52
|
+
|
53
|
+
def assert_effective_interest_rate options
|
54
|
+
actual = Refinance::Annuities.effective_interest_rate(
|
55
|
+
options.fetch(:nominal_annual_interest_rate),
|
56
|
+
options.fetch(:compounding_periods_per_year))
|
57
|
+
|
58
|
+
assert_in_delta options.fetch(:expected), actual, options.fetch(:delta)
|
59
|
+
end
|
60
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: refinance
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-05-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -18,7 +18,7 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - '='
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: 0.
|
21
|
+
version: 10.0.4
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -26,7 +26,7 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - '='
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: 0.
|
29
|
+
version: 10.0.4
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: minitest
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -34,7 +34,7 @@ dependencies:
|
|
34
34
|
requirements:
|
35
35
|
- - '='
|
36
36
|
- !ruby/object:Gem::Version
|
37
|
-
version:
|
37
|
+
version: 4.7.4
|
38
38
|
type: :development
|
39
39
|
prerelease: false
|
40
40
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -42,7 +42,7 @@ dependencies:
|
|
42
42
|
requirements:
|
43
43
|
- - '='
|
44
44
|
- !ruby/object:Gem::Version
|
45
|
-
version:
|
45
|
+
version: 4.7.4
|
46
46
|
description: A collection of finance algorithms related to annuities.
|
47
47
|
email:
|
48
48
|
- enquiries@reinteractive.net
|
@@ -62,6 +62,7 @@ files:
|
|
62
62
|
- test/bigdecimal_annuities_test.rb
|
63
63
|
- test/float_annuities_test.rb
|
64
64
|
- test/refinance_test.rb
|
65
|
+
- test/test_helper.rb
|
65
66
|
homepage: https://github.com/reinteractive-open/refinance
|
66
67
|
licenses:
|
67
68
|
- MIT
|
@@ -83,10 +84,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
83
84
|
version: '0'
|
84
85
|
segments:
|
85
86
|
- 0
|
86
|
-
hash:
|
87
|
+
hash: 1916847891747794597
|
87
88
|
requirements: []
|
88
89
|
rubyforge_project:
|
89
|
-
rubygems_version: 1.8.
|
90
|
+
rubygems_version: 1.8.25
|
90
91
|
signing_key:
|
91
92
|
specification_version: 3
|
92
93
|
summary: Simple annuity algorithms
|
@@ -94,3 +95,4 @@ test_files:
|
|
94
95
|
- test/bigdecimal_annuities_test.rb
|
95
96
|
- test/float_annuities_test.rb
|
96
97
|
- test/refinance_test.rb
|
98
|
+
- test/test_helper.rb
|