--- /dev/null
+blib*
+Makefile
+Makefile.old
+Build
+_build*
+pm_to_blib*
+*.tar.gz
+.lwpcookies
+Finance-Amortization-*
+cover_db
--- /dev/null
+0.5
+
+Changes to improve "kwalitee" rating on cpants.
+
+0.4
+
+Fixed doc bug in BUGS section. BUGS now notes that there is a test script,
+which should be better.
+
+Fixed documentation of new() constructor. It now matches the behavior.
+
+Added TODO about locale dependent rounding.
+
+0.3
+
+Added t directory and a test program.
+
+Added precision field to round results.
+
+Fixed some bugs.
+
+0.2
+
+Version number bump to get around PAUSE naming issue.
+
+0.1
+
+Initial release.
--- /dev/null
+.cvsignore
+Changes
+examples/htmlamtable
+lib/Finance/Amortization.pm
+Makefile.PL
+MANIFEST This list of files
+META.yml
+README
+t/00-load.t
+t/basic.t
+t/boilerplate.t
+t/pod-coverage.t
+t/pod.t
--- /dev/null
+--- #YAML:1.0
+name: Finance-Amortization
+version: 0.5
+abstract: Simple Amortization Schedules
+license: ~
+generated_by: ExtUtils::MakeMaker version 6.32
+distribution_type: module
+requires:
+ Test::More: 0
+meta-spec:
+ url: http://module-build.sourceforge.net/META-spec-v1.2.html
+ version: 1.2
+author:
+ - Nathan Wagner <wagner@cpan.org>
--- /dev/null
+use strict;
+use warnings;
+use ExtUtils::MakeMaker;
+
+WriteMakefile(
+ NAME => 'Finance::Amortization',
+ AUTHOR => 'Nathan Wagner <wagner@cpan.org>',
+ VERSION_FROM => 'lib/Finance/Amortization.pm',
+ ABSTRACT_FROM => 'lib/Finance/Amortization.pm',
+ PL_FILES => {},
+ PREREQ_PM => {
+ 'Test::More' => 0,
+ },
+ dist => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', },
+ clean => { FILES => 'Finance-Amortization-*' },
+);
--- /dev/null
+Finance::Amortization(3\bU)\bser Contributed Perl Documentati\bFo\bin\bnance::Amortization(3)
+
+
+
+N\bNA\bAM\bME\bE
+ Finance::Amortization - Simple Amortization Schedules
+
+S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS
+ use Finance::Amortization
+
+ # make a new schedule
+
+ $amortization = new Finance::Amortization(principal => 100000, rate =
+ 0.06/12, periods = 360);
+
+ # get the balance after a the twelveth period
+
+ $balance = $amortization->balance(12)
+
+ # get the interest paid during the twelfth period
+
+ $interest = $amortization->interest(12);
+
+D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
+ Finance::Amortization is a simple object oriented interface to an amor-
+ tization table. Pass in the principal to be amortized, the number of
+ payments to be made, and the interest rate per payment. It will calcu-
+ late the rest on demand, and provides a few methods to ask for the
+ state of the table after a given number of periods.
+
+ Finance::Amortization is written in pure perl and does not depend on
+ any other modules. It exports no functions; all access is via methods
+ called on an amortization object. (Except for _\bn_\be_\bw_\b(_\b), of course.)
+
+ _\bn_\be_\bw_\b(_\b)
+
+ $am = Finance::Amortization->new(principal => 0, rate => 0, periods =>
+ 0, compounding => 12, precision => 2);
+
+ Creates a new amortization object. Calling interface is hash style.
+ The fields principal, rate, and periods are available, all defaulting
+ to zero.
+
+ Compounding is a parameter which sets how many periods the rate is com-
+ pounded over. Thus, if each amortization period is one month, setting
+ compounding to 12 (the default), will make the rate an annual rate.
+ That is, the interest rate per period is the rate specified, divided by
+ the compounding.
+
+ So, to get an amortization for 30 years on 200000, with a 6% annual
+ rate, you would call new(principal => 200000, periods => 12*30, rate =>
+ 0.06), the compounding will default to 12, and so the rate will work
+ out right for monthly payments.
+
+ precision is used to specify the number of decimal places to round to
+ when returning answers. It defaults to 2, which is appropriate for US
+ currency and many others.
+
+ _\br_\ba_\bt_\be_\b(_\b)
+
+ $rate_per_period = $am->_\br_\ba_\bt_\be_\b(_\b)
+
+ returns the interest rate per period. Ignores any arguments.
+
+ _\bp_\br_\bi_\bn_\bc_\bi_\bp_\ba_\bl_\b(_\b)
+
+ $initial_value = $am->_\bp_\br_\bi_\bn_\bc_\bi_\bp_\ba_\bl_\b(_\b)
+
+ returns the initial principal being amortized. Ignores any arguments.
+
+ _\bp_\be_\br_\bi_\bo_\bd_\bs_\b(_\b)
+
+ $number_of_periods = $am->_\bp_\be_\br_\bi_\bo_\bd_\bs_\b(_\b)
+
+ returns the number of periods in which the principal is being amor-
+ tized. Ignores any arguments.
+
+ _\bp_\ba_\by_\bm_\be_\bn_\bt_\b(_\b)
+
+ $pmt = $am->_\bp_\ba_\by_\bm_\be_\bn_\bt_\b(_\b)
+
+ returns the payment per period. This method will cache the value the
+ first time it is called.
+
+ b\bba\bal\bla\ban\bnc\bce\be(\b(n\bn)\b)
+
+ $balance = $am->balance(12);
+
+ Returns the balance of the amortization after the period given in the
+ argument
+
+ i\bin\bnt\bte\ber\bre\bes\bst\bt(\b(n\bn)\b)
+
+ $interest = $am->interest(12);
+
+ Returns the interest paid in the period given in the argument
+
+B\bBU\bUG\bGS\bS
+ This module uses perl's floating point for financial calculations.
+ This may introduce inaccuracies and/or make this module unsuitable for
+ serious financial applications.
+
+T\bTO\bOD\bDO\bO
+ Use Math::BigRat for the calculations.
+
+ Provide amortizers for present value, future value, annuities, etc.
+
+ Allow for caching calculated values.
+
+ Provide output methods and converters to various table modules.
+ HTML::Table, Text::Table, and Data::Table come to mind.
+
+ Write better test scripts.
+
+ Better checking for errors and out of range input. Return undef in
+ these cases.
+
+ Use a locale dependent value to set an appropriate default for preci-
+ sion in the _\bn_\be_\bw_\b(_\b) method.
+
+L\bLI\bIC\bCE\bEN\bNS\bSE\bE
+ None. This entire module is in the public domain.
+
+A\bAU\bUT\bTH\bHO\bOR\bR
+ Nathan Wagner <nw@hydaspes.if.org>
+
+ This entire module is written by me and placed into the public domain.
+
+
+
+perl v5.8.6 2007-05-27 Finance::Amortization(3)
--- /dev/null
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use lib '../blib/lib';
+
+use Finance::Amortization;
+use HTML::Table;
+
+# this program generates a 30 year amortization table on a $200,000
+# loan at 7%
+
+my $am = Finance::Amortization->new(principal => 200000, rate => .07,
+ periods => 30*12, compounding => 12, precision => 2);
+
+
+#balance, interest, payment
+
+my @cols = qw(Period Payment Interest Principal Balance);
+
+my $table = HTML::Table->new(0, 5);
+
+$table->addRow(@cols);
+$table->setRowHead(1);
+
+my $pmt = $am->payment;
+
+for(1 .. 30*12) {
+ my ($int, $bal) = ($am->interest($_),$am->balance($_));
+ $table->addRow($_, $pmt, $int, $pmt-$int, $bal);
+}
+
+$table->print;
--- /dev/null
+package Finance::Amortization;
+
+use strict;
+use warnings;
+
+our $VERSION = '0.5';
+
+=head1 NAME
+
+Finance::Amortization - Simple Amortization Schedules
+
+=head1 SYNOPSIS
+
+use Finance::Amortization
+
+# make a new schedule
+
+$amortization = new Finance::Amortization(principal => 100000, rate = 0.06/12,
+ periods = 360);
+
+# get the balance after a the twelveth period
+
+$balance = $amortization->balance(12)
+
+# get the interest paid during the twelfth period
+
+$interest = $amortization->interest(12);
+
+=head1 DESCRIPTION
+
+Finance::Amortization is a simple object oriented interface to an
+amortization table. Pass in the principal to be amortized, the number
+of payments to be made, and the interest rate per payment. It will
+calculate the rest on demand, and provides a few methods to ask
+for the state of the table after a given number of periods.
+
+Finance::Amortization is written in pure perl and does not depend
+on any other modules. It exports no functions; all access is via
+methods called on an amortization object. (Except for new(), of course.)
+
+=cut
+
+=head2 new()
+
+$am = Finance::Amortization->new(principal => 0, rate => 0, periods => 0,
+ compounding => 12, precision => 2);
+
+Creates a new amortization object. Calling interface is hash style.
+The fields principal, rate, and periods are available, all defaulting
+to zero.
+
+Compounding is a parameter which sets how many periods the rate is compounded
+over. Thus, if each amortization period is one month, setting compounding
+to 12 (the default), will make the rate an annual rate. That is, the
+interest rate per period is the rate specified, divided by the compounding.
+
+So, to get an amortization for 30 years on 200000, with a 6% annual rate,
+you would call new(principal => 200000, periods => 12*30, rate => 0.06),
+the compounding will default to 12, and so the rate will work out right
+for monthly payments.
+
+precision is used to specify the number of decimal places to round to
+when returning answers. It defaults to 2, which is appropriate for
+US currency and many others.
+
+=cut
+
+sub new {
+ my $pkg = shift;
+ # bless package variables
+ my %conf = (
+ principal => 0.00,
+ rate => 0.00,
+ compounding => 12,
+ precision => 2, # how many decimals to round
+ @_
+ );
+ if (!defined $conf{'periods'}) {
+ $conf{'periods'} = $conf{'length'} * $conf{'compounding'};
+ }
+ if (defined($conf{'compounding'})) {
+ $conf{'rate'} /= $conf{'compounding'};
+ }
+
+ bless {
+ %conf
+ }, $pkg;
+}
+
+=head2 rate()
+
+$rate_per_period = $am->rate()
+
+returns the interest rate per period. Ignores any arguments.
+
+=cut
+
+sub rate {
+ my $am = shift;
+ return $am->{'rate'};
+}
+
+=head2 principal()
+
+$initial_value = $am->principal()
+
+returns the initial principal being amortized. Ignores any arguments.
+
+=cut
+
+sub principal {
+ my $am = shift;
+ return sprintf('%.*f', $am->{'precision'}, $am->{'principal'});
+}
+
+=head2 periods()
+
+$number_of_periods = $am->periods()
+
+returns the number of periods in which the principal is being amortized.
+Ignores any arguments.
+
+=cut
+
+sub periods {
+ my $am = shift;
+ return $am->{'periods'};
+}
+
+#P = r*L*(1+r)^n/{(1+r)^n - 1}
+
+=head2 payment()
+
+$pmt = $am->payment()
+
+returns the payment per period. This method will cache the value the
+first time it is called.
+
+=cut
+
+sub payment {
+ my $am = shift;
+
+ if ($am->{'payment'}) {
+ return $am->{'payment'}
+ }
+
+ my $r = $am->rate;
+ my $r1 = $r + 1;
+ my $n = $am->periods();
+ my $p = $am->principal;
+
+ if ($r == 0) {
+ return $am->{'payment'} = $p / $n;
+ }
+
+ $am->{'payment'} = sprintf('%.2f', $r * $p * $r1**$n / ($r1**$n-1));
+}
+
+=head2 balance(n)
+
+$balance = $am->balance(12);
+
+Returns the balance of the amortization after the period given in the
+argument
+
+=cut
+
+sub balance {
+ my $am = shift;
+ my $period = shift;
+ return $am->principal() if $period == 0;
+
+ return 0 if ($period < 1 or $period > $am->periods);
+
+ my $rate = $am->rate;
+ my $rate1 = $rate + 1;
+ my $periods = $am->periods();
+ my $principal = $am->principal;
+ my $pmt = $am->payment();
+
+ return sprintf('%.*f', $am->{'precision'},
+ $principal*$rate1**$period-$pmt*($rate1**$period - 1)/$rate);
+
+}
+
+=head2 interest(n)
+
+$interest = $am->interest(12);
+
+Returns the interest paid in the period given in the argument
+
+=cut
+
+sub interest {
+ my $am = shift;
+ my $period = shift;
+
+ return 0 if ($period < 1 or $period > $am->periods);
+
+ my $rate = $am->rate;
+
+ return sprintf('%.*f', $am->{'precision'},
+ $rate * $am->balance($period - 1));
+}
+
+=head1 BUGS
+
+This module uses perl's floating point for financial calculations. This
+may introduce inaccuracies and/or make this module unsuitable for serious
+financial applications.
+
+Please report any bugs or feature requests to
+C<bug-finance-amortization at rt.cpan.org>, or through the web interface at
+L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Finance-Amortization>.
+
+=head1 TODO
+
+Use Math::BigRat for the calculations.
+
+Provide amortizers for present value, future value, annuities, etc.
+
+Allow for caching calculated values.
+
+Provide output methods and converters to various table modules.
+HTML::Table, Text::Table, and Data::Table come to mind.
+
+Write better test scripts.
+
+Better checking for errors and out of range input. Return undef
+in these cases.
+
+Use a locale dependent value to set an appropriate default for precision
+in the new() method.
+
+=head1 LICENSE
+
+None. This entire module is in the public domain.
+
+=head1 AUTHOR
+
+Nathan Wagner <nw@hydaspes.if.org>
+
+This entire module is written by me and placed into the public domain.
+
+=cut
+
+1;
+
+__END__
--- /dev/null
+#!perl -T
+
+use Test::More tests => 1;
+
+BEGIN {
+ use_ok( 'Finance::Amortization' );
+}
+
+diag( "Testing Finance::Amortization $Finance::Amortization::VERSION, Perl $], $^X" );
--- /dev/null
+#!/usr/bin/perl
+
+use Test::More tests => 7;
+
+BEGIN { use_ok('Finance::Amortization') }
+
+my $am = Finance::Amortization->new(principal => 10000, rate => 0.12,
+ periods => 12 * 5);
+
+isa_ok($am, 'Finance::Amortization');
+
+is($am->periods(), 60, 'periods');
+is($am->principal, '10000.00', 'principal');
+is($am->rate, 0.01, 'rate');
+is($am->balance(1), 9877.56, 'balance 1');
+is($am->interest(1), '100.00', 'interest 1');
+
--- /dev/null
+#!perl -T
+
+use strict;
+use warnings;
+use Test::More tests => 3;
+
+sub not_in_file_ok {
+ my ($filename, %regex) = @_;
+ open my $fh, "<", $filename
+ or die "couldn't open $filename for reading: $!";
+
+ my %violated;
+
+ while (my $line = <$fh>) {
+ while (my ($desc, $regex) = each %regex) {
+ if ($line =~ $regex) {
+ push @{$violated{$desc}||=[]}, $.;
+ }
+ }
+ }
+
+ if (%violated) {
+ fail("$filename contains boilerplate text");
+ diag "$_ appears on lines @{$violated{$_}}" for keys %violated;
+ } else {
+ pass("$filename contains no boilerplate text");
+ }
+}
+
+not_in_file_ok(README =>
+ "The README is used..." => qr/The README is used/,
+ "'version information here'" => qr/to provide version information/,
+);
+
+not_in_file_ok(Changes =>
+ "placeholder date/time" => qr(Date/time)
+);
+
+sub module_boilerplate_ok {
+ my ($module) = @_;
+ not_in_file_ok($module =>
+ 'the great new $MODULENAME' => qr/ - The great new /,
+ 'boilerplate description' => qr/Quick summary of what the module/,
+ 'stub function definition' => qr/function[12]/,
+ );
+}
+
+module_boilerplate_ok('lib/Finance/Amortization.pm');
--- /dev/null
+#!perl -T
+
+use Test::More;
+eval "use Test::Pod::Coverage 1.04";
+plan skip_all => "Test::Pod::Coverage 1.04 required for testing POD coverage" if $@;
+all_pod_coverage_ok();
--- /dev/null
+#!perl -T
+
+use Test::More;
+eval "use Test::Pod 1.14";
+plan skip_all => "Test::Pod 1.14 required for testing POD" if $@;
+all_pod_files_ok();