]> pd.if.org Git - amortization/blob - lib/Finance/Amortization.pm
1 package Finance::Amortization;
3 use strict;
4 use warnings;
6 our \$VERSION = '0.5';
10 Finance::Amortization - Simple Amortization Schedules
14 use Finance::Amortization
16 # make a new schedule
18 \$amortization = new Finance::Amortization(principal => 100000, rate = 0.06/12,
19         periods = 360);
21 # get the balance after a the twelveth period
23 \$balance = \$amortization->balance(12)
25 # get the interest paid during the twelfth period
27 \$interest = \$amortization->interest(12);
31 Finance::Amortization is a simple object oriented interface to an
32 amortization table.  Pass in the principal to be amortized, the number
33 of payments to be made, and the interest rate per payment.  It will
34 calculate the rest on demand, and provides a few methods to ask
35 for the state of the table after a given number of periods.
37 Finance::Amortization is written in pure perl and does not depend
38 on any other modules.  It exports no functions; all access is via
39 methods called on an amortization object.  (Except for new(), of course.)
41 =cut
45 \$am = Finance::Amortization->new(principal => 0, rate => 0, periods => 0,
46         compounding => 12, precision => 2);
48 Creates a new amortization object.  Calling interface is hash style.
49 The fields principal, rate, and periods are available, all defaulting
50 to zero.
52 Compounding is a parameter which sets how many periods the rate is compounded
53 over.  Thus, if each amortization period is one month, setting compounding
54 to 12 (the default), will make the rate an annual rate.  That is, the
55 interest rate per period is the rate specified, divided by the compounding.
57 So, to get an amortization for 30 years on 200000, with a 6% annual rate,
58 you would call new(principal => 200000, periods => 12*30, rate => 0.06),
59 the compounding will default to 12, and so the rate will work out right
60 for monthly payments.
62 precision is used to specify the number of decimal places to round to
63 when returning answers.  It defaults to 2, which is appropriate for
64 US currency and many others.
66 =cut
68 sub new {
69         my \$pkg = shift;
70         # bless package variables
71         my %conf = (
72                 principal => 0.00,
73                 rate => 0.00,
74                 compounding => 12,
75                 precision => 2, # how many decimals to round
76                 @_
77         );
78         if (!defined \$conf{'periods'}) {
79                 \$conf{'periods'} = \$conf{'length'} * \$conf{'compounding'};
80         }
81         if (defined(\$conf{'compounding'})) {
82                 \$conf{'rate'} /= \$conf{'compounding'};
83         }
85         bless {
86                 %conf
87         }, \$pkg;
88 }
92 \$rate_per_period = \$am->rate()
94 returns the interest rate per period.  Ignores any arguments.
96 =cut
98 sub rate {
99         my \$am = shift;
100         return \$am->{'rate'};
101 }
105 \$initial_value = \$am->principal()
107 returns the initial principal being amortized.  Ignores any arguments.
109 =cut
111 sub principal {
112         my \$am = shift;
113         return sprintf('%.*f', \$am->{'precision'}, \$am->{'principal'});
114 }
118 \$number_of_periods = \$am->periods()
120 returns the number of periods in which the principal is being amortized.
121 Ignores any arguments.
123 =cut
125 sub periods {
126         my \$am = shift;
127         return \$am->{'periods'};
128 }
130 #P = r*L*(1+r)^n/{(1+r)^n - 1}
134 \$pmt = \$am->payment()
136 returns the payment per period.  This method will cache the value the
137 first time it is called.
139 =cut
141 sub payment {
142         my \$am = shift;
144         if (\$am->{'payment'}) {
145                 return \$am->{'payment'}
146         }
148         my \$r = \$am->rate;
149         my \$r1 = \$r + 1;
150         my \$n = \$am->periods();
151         my \$p = \$am->principal;
153         if (\$r == 0) {
154                 return \$am->{'payment'} = \$p / \$n;
155         }
157         \$am->{'payment'} = sprintf('%.2f', \$r * \$p * \$r1**\$n / (\$r1**\$n-1));
158 }
162 \$balance = \$am->balance(12);
164 Returns the balance of the amortization after the period given in the
165 argument
167 =cut
169 sub balance {
170         my \$am = shift;
171         my \$period = shift;
172         return \$am->principal() if \$period == 0;
174         return 0 if (\$period < 1 or \$period > \$am->periods);
176         my \$rate = \$am->rate;
177         my \$rate1 = \$rate + 1;
178         my \$periods = \$am->periods();
179         my \$principal = \$am->principal;
180         my \$pmt = \$am->payment();
182         return sprintf('%.*f', \$am->{'precision'},
183                  \$principal*\$rate1**\$period-\$pmt*(\$rate1**\$period - 1)/\$rate);
185 }
189 \$interest = \$am->interest(12);
191 Returns the interest paid in the period given in the argument
193 =cut
195 sub interest {
196         my \$am = shift;
197         my \$period = shift;
199         return 0 if (\$period < 1 or \$period > \$am->periods);
201         my \$rate = \$am->rate;
203         return sprintf('%.*f', \$am->{'precision'},
204                 \$rate * \$am->balance(\$period - 1));
205 }
209 This module uses perl's floating point for financial calculations.  This
210 may introduce inaccuracies and/or make this module unsuitable for serious
211 financial applications.
213 Please report any bugs or feature requests to
214 C<bug-finance-amortization at rt.cpan.org>, or through the web interface at
215 L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Finance-Amortization>.
219 Use Math::BigRat for the calculations.
221 Provide amortizers for present value, future value, annuities, etc.
223 Allow for caching calculated values.
225 Provide output methods and converters to various table modules.
226 HTML::Table, Text::Table, and Data::Table come to mind.
228 Write better test scripts.
230 Better checking for errors and out of range input.  Return undef
231 in these cases.
233 Use a locale dependent value to set an appropriate default for precision
234 in the new() method.