Amortizy
A comprehensive Ruby library for generating professional loan amortization schedules with advanced features including grace periods, interest-only payments, federal bank holidays, and multiple interest calculation methods.
Perfect for financial applications, lending platforms, and loan calculators.
Features
- Multiple payment frequencies: Daily or weekly payments
- Flexible loan terms: 6, 9, 12, 15, or 18 month terms
- Interest calculation methods: Simple (accrued daily) or precomputed (fixed per payment)
- Grace periods: Automatic interest capitalization during grace periods
- Interest-only periods: Configure initial interest-only payment phases
- Fee handling: Origination fees and additional fees with three treatment options
- Bank day calculations: Automatically skip weekends and US Federal Reserve holidays
- Multiple output formats: Console display or CSV export
- Comprehensive testing: 29 RSpec tests with 100% pass rate
Installation
Add this line to your application's Gemfile:
gem 'amortizy'And then execute:
bundle installOr install it yourself as:
gem install amortizyQuick Start
Basic Example
require 'amortizy'
schedule = Amortizy::AmortizationSchedule.new(
start_date: "2025-11-15",
principal: 100000.00,
term_months: 12,
annual_rate: 17.75,
frequency: :daily
)
# Display in console
schedule.generate
# Generate CSV file
schedule.generate(output: :csv, csv_path: "schedule.csv")Advanced Example with All Features
require 'amortizy'
schedule = Amortizy::AmortizationSchedule.new(
start_date: "2025-11-15",
principal: 100000.00,
term_months: 12,
annual_rate: 17.75,
frequency: :daily,
origination_fee: 10000.00, # Added to principal
additional_fee: 2500.00, # Additional fee
additional_fee_label: "Processing Fee" # Additional fee label Example: Processing fee
additional_fee_treatment: :distributed, # Options: :distributed, :add_to_principal, :separate_payment
bank_days_only: true, # Skip weekends & holidays
interest_only_periods: 10, # First 10 payments are interest-only
grace_period_days: 3, # 3-day grace period
interest_method: :simple # Options: :simple, :precomputed
)
schedule.generateCommand Line Interface
Amortizy includes an interactive CLI tool:
amortizyThe CLI provides:
- Run default examples (demonstrates simple vs precomputed interest)
- Enter parameters manually with interactive prompts
- Automatic CSV generation option
API Reference
Initialization Parameters
| Parameter | Type | Required | Default | Options | Description |
|---|---|---|---|---|---|
start_date |
String/Date | Yes | - | YYYY-MM-DD | Loan start date |
principal |
Float | Yes | - | - | Loan principal amount |
term_months |
Integer | Yes | - | 6, 9, 12, 15, 18 | Loan term in months |
annual_rate |
Float | Yes | - | - | Annual interest rate (%) |
frequency |
Symbol | Yes | - |
:daily, :weekly
|
Payment frequency |
origination_fee |
Float | No | 0 | - | Fee added to principal |
additional_fee |
Float | No | 0 | - | Additional processing fee |
additional_fee_label |
String | No | "Additional Fee" | - | Label for additional fee |
additional_fee_treatment |
Symbol | No | :distributed |
:distributed, :add_to_principal, :separate_payment
|
How to handle additional fee |
bank_days_only |
Boolean | No | false | - | Skip weekends and holidays |
interest_only_periods |
Integer | No | 0 | - | Number of interest-only payments |
grace_period_days |
Integer | No | 0 | - | Days before first payment |
interest_method |
Symbol | No | :simple |
:simple, :precomputed
|
Interest calculation method |
Methods
generate(output: :console, csv_path: nil)
Generate the amortization schedule.
Parameters:
-
output(Symbol)::consoleor:csv -
csv_path(String): Required if output is:csv
Returns: nil (outputs to console or file)
Example:
# Console output
schedule.generate
# CSV output
schedule.generate(output: :csv, csv_path: "my_schedule.csv")Fee Treatment Options
1. Distributed (:distributed)
The fee is spread evenly across all payments.
additional_fee_treatment: :distributedBest for: Keeping individual payments manageable while recovering fees over time
2. Add to Principal (:add_to_principal)
The fee is added to the loan principal upfront, increasing the base amount financed.
additional_fee_treatment: :add_to_principalBest for: Rolling all costs into the loan amount
3. Separate Payment (:separate_payment)
The fee is collected as a separate first payment before regular amortization begins.
additional_fee_treatment: :separate_paymentBest for: Collecting fees upfront separately from the loan repayment
Interest Calculation Methods
Simple Interest (:simple)
Interest accrues daily on the remaining principal balance. As you pay down the principal, interest payments decrease over time.
Formula: Daily interest = (Principal Balance × Annual Rate) / 365
Characteristics:
- Interest decreases as principal is paid down
- Lower total interest cost
- More principal goes toward balance reduction in later payments
Best for: Traditional amortizing loans, consumer loans
interest_method: :simplePrecomputed Interest (:precomputed)
Total interest is calculated upfront based on the original principal and divided equally across all payments. Interest per payment stays constant regardless of principal reduction.
Formula: Total interest calculated at start, then divided by number of payments
Characteristics:
- Interest payment stays constant throughout loan
- Higher total interest cost
- Simpler payment structure
Best for: Fixed payment structures, certain consumer loan types
interest_method: :precomputedFederal Bank Holidays
When bank_days_only: true, the schedule automatically skips:
Weekends
- Saturday
- Sunday
US Federal Reserve Holidays (11 total)
- New Year's Day (January 1)
- Martin Luther King Jr. Birthday (Third Monday in January)
- Presidents' Day / Washington's Birthday (Third Monday in February)
- Memorial Day (Last Monday in May)
- Juneteenth National Independence Day (June 19)
- Independence Day (July 4)
- Labor Day (First Monday in September)
- Columbus Day (Second Monday in October)
- Veterans Day (November 11)
- Thanksgiving Day (Fourth Thursday in November)
- Christmas Day (December 25)
Weekend Observation Rules:
- Holidays falling on Saturday → observed on preceding Friday
- Holidays falling on Sunday → observed on following Monday
These rules are automatically handled by the holidays gem.
Usage Examples
Example 1: Simple Daily Loan
require 'amortizy'
schedule = Amortizy::AmortizationSchedule.new(
start_date: "2025-01-15",
principal: 50000.00,
term_months: 6,
annual_rate: 12.0,
frequency: :daily
)
schedule.generateExample 2: Weekly Loan with Grace Period
require 'amortizy'
schedule = Amortizy::AmortizationSchedule.new(
start_date: "2025-01-15",
principal: 75000.00,
term_months: 12,
annual_rate: 15.0,
frequency: :weekly,
grace_period_days: 7 # One week grace period
)
schedule.generateExample 3: Interest-Only with Bank Days
require 'amortizy'
schedule = Amortizy::AmortizationSchedule.new(
start_date: "2025-01-15",
principal: 100000.00,
term_months: 18,
annual_rate: 10.0,
frequency: :weekly,
interest_only_periods: 8, # First 8 weeks interest-only
bank_days_only: true # Skip weekends and holidays
)
schedule.generateExample 4: Complex Commercial Loan
require 'amortizy'
schedule = Amortizy::AmortizationSchedule.new(
start_date: "2025-01-15",
principal: 250000.00,
term_months: 18,
annual_rate: 14.5,
frequency: :daily,
origination_fee: 25000.00,
additional_fee: 5000.00,
additional_fee_label: "Processing Fee",
additional_fee_treatment: :distributed,
bank_days_only: true,
interest_only_periods: 20,
grace_period_days: 5,
interest_method: :simple
)
schedule.generate(output: :csv, csv_path: "commercial_loan.csv")Programmatic Access
Access schedule data directly for custom processing:
require 'amortizy'
schedule = Amortizy::AmortizationSchedule.new(
start_date: "2025-01-15",
principal: 50000.00,
term_months: 12,
annual_rate: 10.0,
frequency: :daily
)
# Get raw schedule data
schedule_data = schedule.send(:generate_schedule_data)
# Process each payment
schedule_data.each do |payment|
puts "Payment #{payment[:payment_number]}"
puts " Date: #{payment[:date]}"
puts " Principal: $#{'%.2f' % payment[:principal_payment]}"
puts " Interest: $#{'%.2f' % payment[:interest_payment]}"
puts " Balance: $#{'%.2f' % payment[:principal_balance]}"
end
# Calculate totals
total_interest = schedule_data.sum { |row| row[:interest_payment] || 0 }
total_principal = schedule_data.sum { |row| row[:principal_payment] || 0 }
puts "\nLoan Summary:"
puts "Total Interest Paid: $#{'%.2f' % total_interest}"
puts "Total Principal Paid: $#{'%.2f' % total_principal}"
puts "Total Amount Paid: $#{'%.2f' % (total_interest + total_principal)}"Output Formats
Console Output
Formatted table display with columns:
- Payment number
- Payment date
- Days in period
- Principal payment
- Interest payment
- Additional fee payment (if applicable)
- Total payment
- Principal balance
- Accrued interest
- Total balance
- Payment type (Regular, Interest Only, Grace Period, etc.)
CSV Output
Same data as console output in spreadsheet-compatible CSV format. Suitable for:
- Excel/Google Sheets import
- Financial analysis and reporting
- Data visualization
- Record keeping and audits
- Integration with other systems
Requirements
- Ruby 2.7 or higher
-
holidaysgem (~> 8.0) - automatically installed as a dependency
Development
After checking out the repo, run:
# Install dependencies
bundle install
# Run tests
bundle exec rspec
# Run interactive console
bin/console
# Install gem locally for testing
gem install ./amortizy-1.0.0.gemTesting
Amortizy includes a comprehensive RSpec test suite with 29 test cases covering:
- Initialization and validation
- Payment calculations
- Effective principal calculations
- Schedule generation
- Interest methods (simple vs precomputed)
- Grace periods
- Interest-only periods
- Bank day functionality
- Federal holiday detection
- Fee treatments
- CSV generation
- Total payment calculations
Run the test suite:
bundle exec rspecUse Cases
Amortizy is perfect for:
- Financial service applications - Build loan calculators and amortization tools
- Lending platforms - Generate accurate payment schedules for borrowers
- Consumer lending - Handle personal loans, installment loans, and lines of credit
- Business lending - Manage commercial loans with complex terms
- Financial modeling - Analyze different loan scenarios and structures
- Payment processing systems - Generate schedules for automated payment processing
- Financial education - Demonstrate how loan payments and interest work
- Comparison tools - Help users compare different loan options
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/zapatify/amortizy.
How to Contribute
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Add tests for new functionality
- Ensure all tests pass (
bundle exec rspec) - Commit your changes (
git commit -m 'Add amazing feature') - Push to your branch (
git push origin feature/amazing-feature) - Open a Pull Request
Reporting Issues
When reporting issues, please include:
- Ruby version (
ruby -v) - Gem version
- Steps to reproduce
- Expected vs actual behavior
- Any error messages
License
The gem is available as open source under the terms of the MIT License.
Changelog
See CHANGELOG.md for version history and release notes.
Author
Rich Zapata - @zapatify
Acknowledgments
- Built with Bundler gem structure
- Uses the holidays gem for accurate federal holiday detection
- Inspired by the need for flexible, accurate loan amortization tools in Ruby
Support
- 📫 Report issues: GitHub Issues
- 📖 Documentation: GitHub Repository
- 💎 RubyGems: rubygems.org/gems/amortizy
Made with ❤️ for the Ruby community