Skip to content

Commit ca2658a

Browse files
committed
Implement Finance::Loan#ppmt & fix Finance::Loan#pmt
1 parent cedef13 commit ca2658a

File tree

3 files changed

+77
-9
lines changed

3 files changed

+77
-9
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ which are as follows:
1414
| fv || Computes the future value|
1515
| ipmt || Computes interest payment for a loan|
1616
| pmt || Computes the fixed periodic payment(principal + interest) made against a loan amount|
17-
| ppmt | | Computes principal payment for a loan|
17+
| ppmt | | Computes principal payment for a loan|
1818
| nper | | Computes the number of periodic payments|
1919
| pv | | Computes the present value of a payment|
2020
| rate | | Computes the rate of interest per period|

lib/finance/loan.rb

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def pmt
8080
(factor - 1) * (1 + monthly_rate * ptype) / monthly_rate
8181
end
8282

83-
(-future_value + amount * factor) / second_factor
83+
-((future_value + amount * factor) / second_factor)
8484
end
8585

8686
# IPmt computes interest payment for a loan under a given period.
@@ -111,6 +111,27 @@ def ipmt
111111
end
112112
end
113113

114+
# PPmt computes principal payment for a loan under a given period.
115+
#
116+
# Required Loan arguments: period, nominal_rate, duration, amount, future_value*
117+
#
118+
# @return [Float] Principal payment for a loan under a given period.
119+
#
120+
# @example
121+
# require 'finance_rb'
122+
# Finance::Loan.new(nominal_rate: 0.0824, duration: 12, amount: 2500, period: 1).ppmt
123+
# #=> -200.58192368678277
124+
#
125+
# @see http://www.oasis-open.org/committees/documents.php?wg_abbrev=office-formulaOpenDocument-formula-20090508.odt
126+
# @see [WRW] Wheeler, D. A., E. Rathke, and R. Weir (Eds.) (2009, May).
127+
# Open Document Format for Office Applications (OpenDocument)v1.2,
128+
# Part 2: Recalculated Formula (OpenFormula) Format - Annotated Version,
129+
# Pre-Draft 12. Organization for the Advancement of Structured Information
130+
# Standards (OASIS). Billerica, MA, USA. [ODT Document].
131+
def ppmt
132+
pmt - ipmt
133+
end
134+
114135
# Fv computes future value at the end of some periods (duration).
115136
# Required Loan arguments: nominal_rate, duration, payment, amount*
116137
#
@@ -156,7 +177,7 @@ def remaining_balance
156177
self.class.new(
157178
nominal_rate: nominal_rate.to_f, duration: period - 1.0,
158179
amount: amount.to_f, ptype: PAYMENT_TYPE_MAPPING.key(ptype)
159-
).fv(payment: -pmt)
180+
).fv(payment: pmt)
160181
end
161182
end
162183
end

spec/finance/loan_spec.rb

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,37 +5,37 @@
55
context 'w/o a full set of params' do
66
it 'calculates correct pmt value w/o :ptype' do
77
loan = Finance::Loan.new(nominal_rate: 0.1, duration: 12, amount: 1000)
8-
expect(loan.pmt).to eq(87.9158872300099)
8+
expect(loan.pmt).to eq(-87.9158872300099)
99
end
1010

1111
it 'calculates correct pmt value w/o :nominal_rate' do
1212
loan = Finance::Loan.new(duration: 12, amount: 1200, ptype: :end)
13-
expect(loan.pmt).to eq(100)
13+
expect(loan.pmt).to eq(-100)
1414
end
1515
end
1616

1717
context 'with zero rates' do
1818
it 'calculates correct pmt value for 3 years' do
1919
loan = Finance::Loan.new(nominal_rate: 0, duration: 36, amount: 10_000, ptype: :end)
20-
expect(loan.pmt).to eq(277.77777777777777)
20+
expect(loan.pmt).to eq(-277.77777777777777)
2121
end
2222

2323
it 'calculates correct pmt value for 6 months' do
2424
loan = Finance::Loan.new(nominal_rate: 0, duration: 6, amount: 10_000, ptype: :end)
25-
expect(loan.pmt).to eq(1666.6666666666667)
25+
expect(loan.pmt).to eq(-1666.6666666666667)
2626
end
2727
end
2828

2929
context 'with :beginning ptype' do
3030
it 'calculates correct pmt value' do
3131
loan = Finance::Loan.new(nominal_rate: 0.12, duration: 6, amount: 1000, ptype: :beginning)
32-
expect(loan.pmt).to eq(170.8399670404763)
32+
expect(loan.pmt).to eq(-170.8399670404763)
3333
end
3434
end
3535

3636
it 'calculates correct pmt value' do
3737
loan = Finance::Loan.new(nominal_rate: 0.13, duration: 90, amount: 1_000_000, ptype: :end)
38-
expect(loan.pmt).to eq(17_449.90775727763)
38+
expect(loan.pmt).to eq(-17_449.90775727763)
3939
end
4040
end
4141

@@ -99,4 +99,51 @@
9999
end
100100
end
101101
end
102+
103+
describe '#ppmt' do
104+
context 'when 1 period' do
105+
it 'calculates correct ppmt value' do
106+
loan = Finance::Loan.new(
107+
nominal_rate: 0.0824, duration: 12, amount: 2500, period: 1
108+
)
109+
expect(loan.ppmt).to eq(-200.58192368678277)
110+
end
111+
end
112+
113+
context 'when 2 periods' do
114+
it 'calculates correct ppmt value' do
115+
loan = Finance::Loan.new(
116+
nominal_rate: 0.0824, duration: 12, amount: 2500, period: 2
117+
)
118+
expect(loan.ppmt).to eq(-201.95925289609866)
119+
end
120+
end
121+
122+
context 'when 3 periods' do
123+
it 'calculates correct ppmt value' do
124+
loan = Finance::Loan.new(
125+
nominal_rate: 0.0824, duration: 12, amount: 2500, period: 3
126+
)
127+
expect(loan.ppmt).to eq(-203.34603976598518)
128+
end
129+
end
130+
131+
context 'when 4 periods' do
132+
it 'calculates correct ppmt value' do
133+
loan = Finance::Loan.new(
134+
nominal_rate: 0.0824, duration: 12, amount: 2500, period: 4
135+
)
136+
expect(loan.ppmt).to eq(-204.7423492390449)
137+
end
138+
end
139+
140+
context 'when 5 periods' do
141+
it 'calculates correct ppmt value' do
142+
loan = Finance::Loan.new(
143+
nominal_rate: 0.0824, duration: 12, amount: 2500, period: 5
144+
)
145+
expect(loan.ppmt).to eq(-206.1482467038197)
146+
end
147+
end
148+
end
102149
end

0 commit comments

Comments
 (0)