mortgage_calc 0.1.5

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/Manifest ADDED
@@ -0,0 +1,11 @@
1
+ README.rdoc
2
+ Rakefile
3
+ Version.yml
4
+ features/apr.feature
5
+ features/step_definitions/apr_steps.rb
6
+ features/support/env.rb
7
+ lib/mortgage_calc.rb
8
+ lib/mortgage_calc/mortgage_util.rb
9
+ spec/mortgage_calc/mortgage_util_spec.rb
10
+ spec/spec_helper.rb
11
+ Manifest
data/README.rdoc ADDED
@@ -0,0 +1,47 @@
1
+ = mortgage_calc
2
+
3
+ Calculates mortgage APR, monthly payments, and fees.
4
+
5
+ == INSTALL
6
+ $ sudo gem install gemcutter
7
+ $ gem tumble
8
+ $ sudo gem install mortgage_calc
9
+ or add the following to your <b>environment.rb</b>
10
+ config.gem 'mortgage_calc'
11
+
12
+ ==Example:
13
+ loan_amount = 350000
14
+ interest_rate = 4.75
15
+ period = 30 * 12
16
+ lender_fee = 800
17
+ points = 1.0
18
+
19
+ mort_calc = MortgageCalc::MortgageUtil.new(loan_amount, interest_rate, period, lender_fee, points)
20
+
21
+ mort_calc.apr
22
+ mort_calc.monthly_payment
23
+ mort_calc.monthly_payment_with_fees
24
+ mort_calc.total_fees
25
+
26
+ ==Formulas used
27
+ ===Monthly payment with fees
28
+ P = [(C + E) r (1 + r)^N]/[(1 + r)^N - 1]
29
+
30
+ P = monthly payment
31
+ C = Loan amount
32
+ r = Interest rate
33
+ N = Period in months
34
+ E = Lender fees
35
+
36
+ ===Monthly payment without fees is calculated like above with E = 0.
37
+
38
+ ===APR
39
+ [a (1 + a)^N] / [(1 + a)^N - 1] - P/C = 0
40
+ a = A/1200
41
+ N = Period in months
42
+ P = Monthly payment
43
+ C = Loan amount
44
+
45
+ ===Total fees
46
+ Total fees are calculated simply by adding Lender fees to the points paid by borrower.
47
+ T = E + P(C)
data/Rakefile ADDED
@@ -0,0 +1,37 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'echoe'
4
+ require 'spec'
5
+ require 'cucumber'
6
+ require 'lib/mortgage_calc'
7
+
8
+ require 'cucumber/rake/task'
9
+ require 'spec/rake/spectask'
10
+
11
+ Echoe.new("mortgage_calc", MortgageCalc::VERSION) do |p|
12
+ p.description = "Mortgage utilities"
13
+ p.url = "http://github.com/pathfinderdev/mortgage_calc"
14
+ p.author = "Perry Hertler"
15
+ p.email = "phertler@pathf.com"
16
+ p.ignore_pattern = ["tmp/*", "script/*, .idea/*"]
17
+ p.development_dependencies = []
18
+ end
19
+
20
+ Dir["#File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
21
+
22
+ spec_files = Rake::FileList["spec/**/*_spec.rb"]
23
+
24
+ desc "Run specs"
25
+ Spec::Rake::SpecTask.new do |t|
26
+ t.spec_files = spec_files
27
+ t.spec_opts = ["-c"]
28
+ end
29
+
30
+ Cucumber::Rake::Task.new(:features) do |t|
31
+ t.cucumber_opts = "features --format progress"
32
+ end
33
+
34
+ task :default => [:spec, :features]
35
+
36
+
37
+
data/Version.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 1
4
+ :patch: 5
@@ -0,0 +1,19 @@
1
+ Feature Calculate APR
2
+ In order to show sorted APR search results
3
+ As a person navigating OMT
4
+ I want to see correct APRs
5
+
6
+ Scenario Outline: Calculate APR
7
+ Given <loan_amount>, <fees>, <points>, <rate>, <period>
8
+ Then the resultant apr should be <apr>
9
+
10
+ Scenarios: with APR fields
11
+ | loan_amount | fees | points | rate | period | apr |
12
+ | 125000 | 5000 | 0 | 6.5 | 360 | 6.881 |
13
+ | 125000 | 5000 | -1.25 | 6.5 | 360 | 6.881 |
14
+ | 400000 | 1200 | 0 | 5.25 | 180 | 5.296 |
15
+ | 125000 | 811 | 0.375 | 6.125 | 360 | 6.221 |
16
+ | 125000 | 811 | -0.375 | 6.5 | 360 | 6.562 |
17
+ | 100000 | 1000 | 0 | 7.0 | 360 | 7.099 |
18
+ | 100000 | 0 | 0 | 7.0 | 360 | 7.0 |
19
+ | 250000 | 3135 | 2.125 | 6.5 | 360 | 6.822 |
@@ -0,0 +1,7 @@
1
+ Given /^(.*), (.*), (.*), (.*), (.*)$/ do |loan_amount, fees, points, rate, period|
2
+ @mortgage_util = MortgageCalc::MortgageUtil.new(Integer(loan_amount), Float(rate), Integer(period), Float(fees), Float(points))
3
+ end
4
+
5
+ Then /^the resultant apr should be (.*)$/ do |apr_expected|
6
+ @mortgage_util.apr.should be_close(Float(apr_expected), 0.001)
7
+ end
@@ -0,0 +1,5 @@
1
+ $LOAD_PATH << File.join(File.dirname(__FILE__),"..","..","lib")
2
+ require 'mortgage_calc'
3
+ require 'spec/expectations'
4
+ require 'spec/matchers'
5
+ require 'spec/stubs/cucumber'
@@ -0,0 +1,58 @@
1
+ module MortgageCalc
2
+ class MortgageUtil
3
+ attr_accessor :loan_amount, :interest_rate, :period, :lender_fee, :points
4
+
5
+ def initialize(loan_amount, interest_rate, period=360, lender_fee=0, points=0.0)
6
+ self.loan_amount = Float(loan_amount.to_s)
7
+ self.interest_rate = Float(interest_rate.to_s)
8
+ self.period = Integer(period.to_s)
9
+ self.lender_fee = lender_fee
10
+ self.points = Float(points.to_s)
11
+ end
12
+
13
+ def apr
14
+ calculate_apr_with_newton_raphson(self.period, monthly_payment_with_fees, self.loan_amount, monthly_interst_rate + 1)
15
+ end
16
+
17
+ def monthly_payment
18
+ calculate_monthly_payment(self.loan_amount, monthly_interst_rate, self.period)
19
+ end
20
+
21
+ def monthly_payment_with_fees
22
+ calculate_monthly_payment(self.loan_amount + total_fees, monthly_interst_rate, self.period)
23
+ end
24
+
25
+ def total_fees
26
+ buyer_points = self.points <= 0 ? 0 : self.points
27
+ self.lender_fee + (self.loan_amount * buyer_points.abs/100)
28
+ end
29
+
30
+ private
31
+ def monthly_interst_rate
32
+ self.interest_rate / 100 / 12
33
+ end
34
+
35
+ def calculate_monthly_payment(amount, monthly_rate, period)
36
+ amount * (monthly_rate/(1 - (1 + monthly_rate)**(-period)))
37
+ end
38
+
39
+ # solves APR
40
+ # where a = APR/1200, N = period, P = monthly payment, C = loan_amount
41
+ # calculate APR uses the Newton-Raphson to find the root (the value for 'a' that makes f(a) = 0)
42
+ # for best performance call this with 'start'= interest rate
43
+ def calculate_apr_with_newton_raphson(periods, monthly_payment, loan_amount, start=1.1)
44
+ payment_ratio = monthly_payment / loan_amount
45
+ f = lambda {|k| (k**(periods + 1) - (k**periods * (payment_ratio + 1)) + payment_ratio)}
46
+ f_slope = lambda { |k| ((periods + 1) * k**periods) - (periods * (payment_ratio + 1) * k**(periods - 1))}
47
+
48
+ k_plus_one = start
49
+ k = 0.0
50
+
51
+ while ((k - 1) * 100000).to_f.floor != ((k_plus_one - 1) * 100000).to_f.floor
52
+ k = k_plus_one
53
+ k_plus_one = k - f.call(k) / f_slope.call(k)
54
+ end
55
+ 100 * 12 * (k_plus_one - 1).to_f
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,9 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
2
+ require 'yaml'
3
+
4
+ module MortgageCalc
5
+ version = YAML.load_file(File.dirname(__FILE__) + "/../Version.yml")
6
+ VERSION = "#{version[:major]}.#{version[:minor]}.#{version[:patch]}"
7
+ end
8
+
9
+ require 'mortgage_calc/mortgage_util'
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{mortgage_calc}
5
+ s.version = "0.1.5"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Perry Hertler"]
9
+ s.date = %q{2010-02-13}
10
+ s.description = %q{Mortgage utilities}
11
+ s.email = %q{phertler@pathf.com}
12
+ s.extra_rdoc_files = ["README.rdoc", "lib/mortgage_calc.rb", "lib/mortgage_calc/mortgage_util.rb"]
13
+ s.files = ["README.rdoc", "Rakefile", "Version.yml", "features/apr.feature", "features/step_definitions/apr_steps.rb", "features/support/env.rb", "lib/mortgage_calc.rb", "lib/mortgage_calc/mortgage_util.rb", "spec/mortgage_calc/mortgage_util_spec.rb", "spec/spec_helper.rb", "Manifest", "mortgage_calc.gemspec"]
14
+ s.homepage = %q{http://github.com/pathfinderdev/mortgage_calc}
15
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Mortgage_calc", "--main", "README.rdoc"]
16
+ s.require_paths = ["lib"]
17
+ s.rubyforge_project = %q{mortgage_calc}
18
+ s.rubygems_version = %q{1.3.5}
19
+ s.summary = %q{Mortgage utilities}
20
+
21
+ if s.respond_to? :specification_version then
22
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
23
+ s.specification_version = 3
24
+
25
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
26
+ else
27
+ end
28
+ else
29
+ end
30
+ end
@@ -0,0 +1,61 @@
1
+ require File.join(File.dirname(__FILE__), "..", "spec_helper")
2
+
3
+ module MortgageCalc
4
+ describe MortgageUtil do
5
+ def assert_monthly_apr_payment_matches(loan_amount, rate, period, fee, points)
6
+ mortgage_util = MortgageUtil.new(loan_amount, rate, period, fee, points)
7
+ monthly_payment_with_fees = mortgage_util.monthly_payment_with_fees
8
+ monthly_payment_from_apr = MortgageUtil.new(loan_amount, mortgage_util.apr, period, 0, 0).monthly_payment
9
+ monthly_payment_with_fees.should be_close(monthly_payment_from_apr, 0.01)
10
+ end
11
+
12
+ context "with valid MortgageUtil" do
13
+ before(:all) do
14
+ @mortgage_util = MortgageUtil.new(100000, 6.0, 360, 1200, 1.25)
15
+ @mortgage_util_with_apr_as_rate = MortgageUtil.new(100000, @mortgage_util.apr, 360, 1200, 1.25)
16
+ end
17
+ it "should have proper monthly interest rate" do
18
+ @mortgage_util.send(:monthly_interst_rate).should == 0.005
19
+ end
20
+ it "should have proper monthly payment" do
21
+ @mortgage_util.monthly_payment.should be_close(599.55, 0.001)
22
+ end
23
+ it "should have proper total fees" do
24
+ @mortgage_util.total_fees.should be_close(2450, 0.001)
25
+ end
26
+ it "should have proper APR" do
27
+ @mortgage_util.apr.should be_close(6.22726, 0.00001)
28
+ end
29
+ end
30
+ it "should calculate original monthly payment from APR" do
31
+ assert_monthly_apr_payment_matches(300000, 6.5, 360, 1200, 1.25)
32
+ assert_monthly_apr_payment_matches(300000, 6.5, 360, 0, 0)
33
+ assert_monthly_apr_payment_matches(400000, 1.1, 180, 1200, 1.25)
34
+ assert_monthly_apr_payment_matches(300000, 6.5, 360, 0, 7.25)
35
+ assert_monthly_apr_payment_matches(300000, 6.5, 360, 10000, 7.25)
36
+ end
37
+ end
38
+ context "ignore lender points paid to broker" do
39
+ it "the fee should not include negative points" do
40
+ mortgage_util = MortgageUtil.new(100000, 6.0, 360, 1200, -1.25)
41
+ 1200.should == mortgage_util.total_fees
42
+ end
43
+ end
44
+ context "initialize convert to best types" do
45
+ before(:all) do
46
+ @mortgage_util = MortgageUtil.new('100000', '6.0', 360, 1200, '-1.25')
47
+ end
48
+ it "should convert rate to float if necessary" do
49
+ @mortgage_util.interest_rate.type.should == Float
50
+ end
51
+ it "should convert points to float if necessary" do
52
+ @mortgage_util.points.type.should == Float
53
+ end
54
+ it "should convert loan_amount to float if necessary" do
55
+ @mortgage_util.loan_amount.type.should == Float
56
+ end
57
+ it "should convert period to integer if necessary" do
58
+ @mortgage_util.period.type.should == Fixnum
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,3 @@
1
+ $LOAD_PATH << File.join(File.dirname(__FILE__),"..","lib")
2
+ require 'spec'
3
+ require 'mortgage_calc'
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mortgage_calc
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.5
5
+ platform: ruby
6
+ authors:
7
+ - Perry Hertler
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-02-13 00:00:00 -06:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Mortgage utilities
17
+ email: phertler@pathf.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.rdoc
24
+ - lib/mortgage_calc.rb
25
+ - lib/mortgage_calc/mortgage_util.rb
26
+ files:
27
+ - README.rdoc
28
+ - Rakefile
29
+ - Version.yml
30
+ - features/apr.feature
31
+ - features/step_definitions/apr_steps.rb
32
+ - features/support/env.rb
33
+ - lib/mortgage_calc.rb
34
+ - lib/mortgage_calc/mortgage_util.rb
35
+ - spec/mortgage_calc/mortgage_util_spec.rb
36
+ - spec/spec_helper.rb
37
+ - Manifest
38
+ - mortgage_calc.gemspec
39
+ has_rdoc: true
40
+ homepage: http://github.com/pathfinderdev/mortgage_calc
41
+ licenses: []
42
+
43
+ post_install_message:
44
+ rdoc_options:
45
+ - --line-numbers
46
+ - --inline-source
47
+ - --title
48
+ - Mortgage_calc
49
+ - --main
50
+ - README.rdoc
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ version:
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "1.2"
64
+ version:
65
+ requirements: []
66
+
67
+ rubyforge_project: mortgage_calc
68
+ rubygems_version: 1.3.5
69
+ signing_key:
70
+ specification_version: 3
71
+ summary: Mortgage utilities
72
+ test_files: []
73
+