finance_velocity 2.0.3

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.
@@ -0,0 +1,127 @@
1
+ require_relative 'decimal'
2
+ require_relative 'rates'
3
+
4
+ require 'bigdecimal'
5
+ require 'bigdecimal/newton'
6
+ include Newton
7
+
8
+ module Finance
9
+ # Provides methods for working with cash flows (collections of transactions)
10
+ # @api public
11
+ module Cashflow
12
+ # Base class for working with Newton's Method.
13
+ # @api private
14
+ class Function
15
+ values = {
16
+ eps: "1.0e-16",
17
+ one: "1.0",
18
+ two: "2.0",
19
+ ten: "10.0",
20
+ zero: "0.0"
21
+ }
22
+
23
+ values.each do |key, value|
24
+ define_method key do
25
+ BigDecimal value
26
+ end
27
+ end
28
+
29
+ def initialize(transactions, function)
30
+ @transactions = transactions
31
+ @function = function
32
+ end
33
+
34
+ def values(x)
35
+ value = @transactions.send(@function, Flt::DecNum.new(x[0].to_s))
36
+ [ BigDecimal(value.to_s) ]
37
+ end
38
+ end
39
+
40
+ # calculate the internal rate of return for a sequence of cash flows
41
+ # @return [DecNum] the internal rate of return
42
+ # @example
43
+ # [-4000,1200,1410,1875,1050].irr #=> 0.143
44
+ # @see http://en.wikipedia.org/wiki/Internal_rate_of_return
45
+ # @api public
46
+ def irr
47
+ # Make sure we have a valid sequence of cash flows.
48
+ positives, negatives = self.partition{ |i| i >= 0 }
49
+ if positives.empty? || negatives.empty?
50
+ raise ArgumentError, "Calculation does not converge."
51
+ end
52
+
53
+ func = Function.new(self, :npv)
54
+ rate = [ func.one ]
55
+ nlsolve( func, rate )
56
+ rate[0]
57
+ end
58
+
59
+ def method_missing(name, *args, &block)
60
+ return self.inject(:+) if name.to_s == "sum"
61
+ super
62
+ end
63
+
64
+ # calculate the net present value of a sequence of cash flows
65
+ # @return [DecNum] the net present value
66
+ # @param [Numeric] rate the discount rate to be applied
67
+ # @example
68
+ # [-100.0, 60, 60, 60].npv(0.1) #=> 49.211
69
+ # @see http://en.wikipedia.org/wiki/Net_present_value
70
+ # @api public
71
+ def npv(rate)
72
+ self.collect! { |entry| Flt::DecNum.new(entry.to_s) }
73
+
74
+ rate, total = Flt::DecNum.new(rate.to_s), Flt::DecNum.new(0.to_s)
75
+ self.each_with_index do |cashflow, index|
76
+ total += cashflow / (1 + rate) ** index
77
+ end
78
+
79
+ total
80
+ end
81
+
82
+ # calculate the internal rate of return for a sequence of cash flows with dates
83
+ # @return [Rate] the internal rate of return
84
+ # @example
85
+ # @transactions = []
86
+ # @transactions << Transaction.new(-1000, :date => Time.new(1985,01,01))
87
+ # @transactions << Transaction.new( 600, :date => Time.new(1990,01,01))
88
+ # @transactions << Transaction.new( 600, :date => Time.new(1995,01,01))
89
+ # @transactions.xirr(0.6) #=> Rate("0.024851", :apr, :compounds => :annually)
90
+ # @api public
91
+ def xirr(iterations=100)
92
+ # Make sure we have a valid sequence of cash flows.
93
+ positives, negatives = self.partition{ |t| t.amount >= 0 }
94
+ if positives.empty? || negatives.empty?
95
+ raise ArgumentError, "Calculation does not converge."
96
+ end
97
+
98
+ func = Function.new(self, :xnpv)
99
+ rate = [ func.one ]
100
+ nlsolve( func, rate )
101
+ Rate.new(rate[0], :apr, :compounds => :annually)
102
+ end
103
+
104
+ # calculate the net present value of a sequence of cash flows
105
+ # @return [DecNum]
106
+ # @example
107
+ # @transactions = []
108
+ # @transactions << Transaction.new(-1000, :date => Time.new(1985,01,01))
109
+ # @transactions << Transaction.new( 600, :date => Time.new(1990,01,01))
110
+ # @transactions << Transaction.new( 600, :date => Time.new(1995,01,01))
111
+ # @transactions.xnpv(0.6).round(2) #=> -937.41
112
+ # @api public
113
+ def xnpv(rate)
114
+ rate = Flt::DecNum.new(rate.to_s)
115
+ start = self[0].date
116
+
117
+ self.inject(0) do |sum, t|
118
+ n = t.amount / ( (1 + rate) ** ((t.date-start) / Flt::DecNum.new(31536000.to_s))) # 365 * 86400
119
+ sum + n
120
+ end
121
+ end
122
+ end
123
+ end
124
+
125
+ class Array
126
+ include Finance::Cashflow
127
+ end
@@ -0,0 +1,21 @@
1
+ require 'rubygems'
2
+ require 'flt'
3
+ include Flt
4
+
5
+ DecNum.context.define_conversion_from(BigDecimal) do |x, context|
6
+ DecNum(x.to_s)
7
+ end
8
+
9
+ DecNum.context.define_conversion_to(BigDecimal) do |x|
10
+ BigDecimal(x.to_s)
11
+ end
12
+
13
+ class Numeric
14
+ def to_d
15
+ if self.instance_of? DecNum
16
+ self
17
+ else
18
+ DecNum self.to_s
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,167 @@
1
+ require_relative 'decimal'
2
+
3
+ module Finance
4
+ # the Rate class provides an interface for working with interest rates.
5
+ # {render:Rate#new}
6
+ # @api public
7
+ class Rate
8
+ include Comparable
9
+
10
+ # Accepted rate types
11
+ TYPES = { :apr => "effective",
12
+ :apy => "effective",
13
+ :effective => "effective",
14
+ :nominal => "nominal"
15
+ }
16
+
17
+ # @return [Integer] the duration for which the rate is valid, in months
18
+ # @api public
19
+ attr_accessor :duration
20
+ # @return [DecNum] the effective interest rate
21
+ # @api public
22
+ attr_reader :effective
23
+ # @return [DecNum] the nominal interest rate
24
+ # @api public
25
+ attr_reader :nominal
26
+
27
+ # compare two Rates, using the effective rate
28
+ # @return [Numeric] one of -1, 0, +1
29
+ # @param [Rate] rate the comparison Rate
30
+ # @example Which is better, a nominal rate of 15% compounded monthly, or 15.5% compounded semiannually?
31
+ # r1 = Rate.new(0.15, :nominal) #=> Rate.new(0.160755, :apr)
32
+ # r2 = Rate.new(0.155, :nominal, :compounds => :semiannually) #=> Rate.new(0.161006, :apr)
33
+ # r1 <=> r2 #=> -1
34
+ # @api public
35
+ def <=>(rate)
36
+ @effective <=> rate.effective
37
+ end
38
+
39
+ # (see #effective)
40
+ # @api public
41
+ def apr
42
+ self.effective
43
+ end
44
+
45
+ # (see #effective)
46
+ # @api public
47
+ def apy
48
+ self.effective
49
+ end
50
+
51
+ # a convenience method which sets the value of @periods
52
+ # @return none
53
+ # @param [Symbol, Numeric] input the compounding frequency
54
+ # @raise [ArgumentError] if input is not an accepted keyword or Numeric
55
+ # @api private
56
+ def compounds=(input)
57
+ @periods = case input
58
+ when :annually then Flt::DecNum.new(1)
59
+ when :continuously then Flt::DecNum.infinity
60
+ when :daily then Flt::DecNum.new(365)
61
+ when :monthly then Flt::DecNum.new(12)
62
+ when :quarterly then Flt::DecNum.new(4)
63
+ when :semiannually then Flt::DecNum.new(2)
64
+ when Numeric then Flt::DecNum.new(input.to_s)
65
+ else raise ArgumentError
66
+ end
67
+ end
68
+
69
+ # set the effective interest rate
70
+ # @return none
71
+ # @param [DecNum] rate the effective interest rate
72
+ # @api private
73
+ def effective=(rate)
74
+ @effective = rate
75
+ @nominal = Rate.to_nominal(rate, @periods)
76
+ end
77
+
78
+ # create a new Rate instance
79
+ # @return [Rate]
80
+ # @param [Numeric] rate the decimal value of the interest rate
81
+ # @param [Symbol] type a valid {TYPES rate type}
82
+ # @param [optional, Hash] opts set optional attributes
83
+ # @option opts [String] :duration a time interval for which the rate is valid
84
+ # @option opts [String] :compounds (:monthly) the number of compounding periods per year
85
+ # @example create a 3.5% APR rate
86
+ # Rate.new(0.035, :apr) #=> Rate(0.035, :apr)
87
+ # @see http://en.wikipedia.org/wiki/Effective_interest_rate
88
+ # @see http://en.wikipedia.org/wiki/Nominal_interest_rate
89
+ # @api public
90
+ def initialize(rate, type, opts={})
91
+ # Default monthly compounding.
92
+ opts = { :compounds => :monthly }.merge opts
93
+
94
+ # Set optional attributes..
95
+ opts.each do |key, value|
96
+ send("#{key}=", value)
97
+ end
98
+
99
+ # Set the rate in the proper way, based on the value of type.
100
+ begin
101
+ send("#{TYPES.fetch(type)}=", Flt::DecNum.new(rate.to_s))
102
+ rescue KeyError
103
+ raise ArgumentError, "type must be one of #{TYPES.keys.join(', ')}", caller
104
+ end
105
+ end
106
+
107
+ def inspect
108
+ "Rate.new(#{self.apr.round(6)}, :apr)"
109
+ end
110
+
111
+ # @return [DecNum] the monthly effective interest rate
112
+ # @example
113
+ # rate = Rate.new(0.15, :nominal)
114
+ # rate.apr.round(6) #=> DecNum('0.160755')
115
+ # rate.monthly.round(6) #=> DecNum('0.013396')
116
+ # @api public
117
+ def monthly
118
+ (self.effective / 12).round(15)
119
+ end
120
+
121
+ # set the nominal interest rate
122
+ # @return none
123
+ # @param [DecNum] rate the nominal interest rate
124
+ # @api private
125
+ def nominal=(rate)
126
+ @nominal = rate
127
+ @effective = Rate.to_effective(rate, @periods)
128
+ end
129
+
130
+ # convert a nominal interest rate to an effective interest rate
131
+ # @return [DecNum] the effective interest rate
132
+ # @param [Numeric] rate the nominal interest rate
133
+ # @param [Numeric] periods the number of compounding periods per year
134
+ # @example
135
+ # Rate.to_effective(0.05, 4) #=> DecNum('0.05095')
136
+ # @api public
137
+ def Rate.to_effective(rate, periods)
138
+ rate, periods = Flt::DecNum.new(rate.to_s), Flt::DecNum.new(periods.to_s)
139
+
140
+ if periods.infinite?
141
+ rate.exp - 1
142
+ else
143
+ (1 + rate / periods) ** periods - 1
144
+ end
145
+ end
146
+
147
+ # convert an effective interest rate to a nominal interest rate
148
+ # @return [DecNum] the nominal interest rate
149
+ # @param [Numeric] rate the effective interest rate
150
+ # @param [Numeric] periods the number of compounding periods per year
151
+ # @example
152
+ # Rate.to_nominal(0.06, 365) #=> DecNum('0.05827')
153
+ # @see http://www.miniwebtool.com/nominal-interest-rate-calculator/
154
+ # @api public
155
+ def Rate.to_nominal(rate, periods)
156
+ rate, periods = Flt::DecNum.new(rate.to_s), Flt::DecNum.new(periods.to_s)
157
+
158
+ if periods.infinite?
159
+ (rate + 1).log
160
+ else
161
+ periods * ((1 + rate) ** (1 / periods) - 1)
162
+ end
163
+ end
164
+
165
+ private :compounds=, :effective=, :nominal=
166
+ end
167
+ end
@@ -0,0 +1,122 @@
1
+ require_relative 'decimal'
2
+
3
+ module Finance
4
+ # the Transaction class provides a general interface for working with individual cash flows.
5
+ # @api public
6
+ class Transaction
7
+ # @return [DecNum] the cash value of the transaction
8
+ # @api public
9
+ attr_reader :amount
10
+ # @return [Integer] the period number of the transaction
11
+ # @note this attribute is mainly used in the case of mortgage amortization with no dates
12
+ # @api public
13
+ attr_accessor :period
14
+ # @return [Date] the date of the transaction
15
+ # @api public
16
+ attr_accessor :date
17
+
18
+ # Set the cash value of the transaction
19
+ # @return None
20
+ # @param [Numeric] value the cash value
21
+ # @example
22
+ # t = Transaction.new(500)
23
+ # t.amount = 750
24
+ # t.amount #=> 750
25
+ # @api public
26
+ def amount=(value)
27
+ @amount = Flt::DecNum.new(value.to_s)
28
+ end
29
+
30
+ # @return [DecNum] the difference between the original transaction
31
+ # amount and the current amount
32
+ # @example
33
+ # t = Transaction.new(500)
34
+ # t.amount = 750
35
+ # t.difference #=> DecNum('250')
36
+ # @api public
37
+ def difference
38
+ @amount - @original
39
+ end
40
+
41
+ # create a new Transaction
42
+ # @return [Transaction]
43
+ # @param [Numeric] amount the cash value of the transaction
44
+ # @param [optional, Hash] opts sets optional attributes
45
+ # @option opts [String] :period the period number of the transaction
46
+ # @example a simple transaction
47
+ # t = Transaction.new(400)
48
+ # @example a transaction with a period number
49
+ # t = Transaction.new(400, :period => 3)
50
+ # @api public
51
+ def initialize(amount, opts={})
52
+ @amount = amount
53
+ @original = amount
54
+
55
+ # Set optional attributes..
56
+ opts.each do |key, value|
57
+ send("#{key}=", value)
58
+ end
59
+ end
60
+
61
+ # @return [Boolean] whether or not the Transaction is an Interest transaction
62
+ # @example
63
+ # pmt = Payment.new(500)
64
+ # int = Interest.new(500)
65
+ # pmt.interest? #=> False
66
+ # int.interest? #=> True
67
+ # @api public
68
+ def interest?
69
+ self.instance_of? Interest
70
+ end
71
+
72
+ # @api public
73
+ def inspect
74
+ "Transaction(#{@amount})"
75
+ end
76
+
77
+ # Modify a Transaction's amount by passing a block
78
+ # @return none
79
+ # @note self is passed as the argument to the block. This makes any public attribute available.
80
+ # @example add $100 to a monthly payment
81
+ # pmt = Payment.new(-500)
82
+ # pmt.modify { |t| t.amount-100 }
83
+ # pmt.amount #=> -600
84
+ # @api public
85
+ def modify
86
+ @amount = yield(self)
87
+ end
88
+
89
+ # (see #amount)
90
+ # @deprecated Provided for backwards compatibility
91
+ def payment
92
+ @amount
93
+ end
94
+
95
+ # @return [Boolean] whether or not the Transaction is a Payment transaction
96
+ # @example
97
+ # pmt = Payment.new(500)
98
+ # int = Interest.new(500)
99
+ # pmt.payment? #=> True
100
+ # int.payment? #=> False
101
+ # @api public
102
+ def payment?
103
+ self.instance_of? Payment
104
+ end
105
+ end
106
+
107
+ # Represent an interest charge as a Transaction
108
+ # @see Transaction
109
+ class Interest < Transaction
110
+ def inspect
111
+ "Interest(#{@amount})"
112
+ end
113
+ end
114
+
115
+ # Represent a loan payment as a Transaction
116
+ # @see Transaction
117
+ class Payment < Transaction
118
+ def inspect
119
+ "Payment(#{@amount})"
120
+ end
121
+ end
122
+ end
data/lib/finance.rb ADDED
@@ -0,0 +1,15 @@
1
+ require 'finance/decimal'
2
+ require 'finance/cashflows'
3
+
4
+ # The *Finance* module adheres to the following conventions for
5
+ # financial calculations:
6
+ #
7
+ # * Positive values represent cash inflows (money received); negative
8
+ # values represent cash outflows (payments).
9
+ # * *principal* represents the outstanding balance of a loan or annuity.
10
+ # * *rate* represents the interest rate _per period_.
11
+ module Finance
12
+ autoload :Amortization, 'finance/amortization'
13
+ autoload :Rate, 'finance/rates'
14
+ autoload :Transaction, 'finance/transaction'
15
+ end
@@ -0,0 +1,171 @@
1
+ require_relative 'test_helper'
2
+
3
+ # @see http://tinyurl.com/6zroqvd for detailed calculations for the
4
+ # examples in these unit tests.
5
+ describe "Amortization" do
6
+ def ipmt(principal, rate, payment, period)
7
+ -(-rate*principal*(1+rate)**(period-1) - payment*((1+rate)**(period-1)-1)).round(2)
8
+ end
9
+
10
+ describe "amortization with a 0% rate" do
11
+ it "should not raise a divide-by-zero error" do
12
+ rate = Rate.new(0, :apr, :duration => 30 * 12)
13
+ Amortization.new(D(10000), rate) # should not raise an error
14
+ end
15
+ end
16
+
17
+ describe "a fixed-rate amortization of 200000 at 3.75% over 30 years" do
18
+ before(:all) do
19
+ @rate = Rate.new(0.0375, :apr, :duration => (30 * 12))
20
+ @principal = D(200000)
21
+ @std = Amortization.new(@principal, @rate)
22
+ end
23
+
24
+ it "should have a principal of $200,000" do
25
+ assert_equal @principal, @std.principal
26
+ end
27
+
28
+ it "should have a final balance of zero" do
29
+ assert @std.balance.zero?
30
+ end
31
+
32
+ it "should have a duration of 360 months" do
33
+ assert_equal 360, @std.duration
34
+ end
35
+
36
+ it "should have a monthly payment of $926.23" do
37
+ assert_equal D('-926.23'), @std.payment
38
+ end
39
+
40
+ it "should have a final payment of $926.96 (due to rounding)" do
41
+ assert_equal D('-926.96'), @std.payments[-1]
42
+ end
43
+
44
+ it "should have total payments of $333,443.53" do
45
+ assert_equal D('-333443.53'), @std.payments.sum
46
+ end
47
+
48
+ it "should have interest charges which agree with the standard formula" do
49
+ 0.upto 359 do |period|
50
+ assert_equal @std.interest[period], ipmt(@principal, @rate.monthly, @std.payment, period+1)
51
+ end
52
+ end
53
+
54
+ it "should have total interest charges of $133,433.33" do
55
+ assert_equal D('133443.53'), @std.interest.sum
56
+ end
57
+ end
58
+
59
+ describe "an adjustable rate amortization of 200000 starting at 3.75% and increasing by 1% every 3 years" do
60
+ before(:all) do
61
+ @rates = []
62
+ 0.upto 9 do |adj|
63
+ @rates << Rate.new(0.0375 + (D('0.01') * adj), :apr, :duration => (3 * 12))
64
+ end
65
+ @principal = D(200000)
66
+ @arm = Amortization.new(@principal, *@rates)
67
+ end
68
+
69
+ it "should have a principal of $200,000" do
70
+ assert_equal @principal, @arm.principal
71
+ end
72
+
73
+ it "should have a final balance of zero" do
74
+ assert @arm.balance.zero?
75
+ end
76
+
77
+ it "should have a duration of 360 months" do
78
+ assert_equal 360, @arm.duration
79
+ end
80
+
81
+ it "should not have a fixed monthly payment (since it changes)" do
82
+ assert_nil @arm.payment
83
+ end
84
+
85
+ it "should have payments which increase every three years" do
86
+ values = %w{926.23 1033.73 1137.32 1235.39 1326.30 1408.27 1479.28 1537.03 1578.84 1601.66 }
87
+ values.collect!{ |v| -D(v) }
88
+
89
+ payments = []
90
+ values[0,9].each do |v|
91
+ 36.times do
92
+ payments << v
93
+ end
94
+ end
95
+
96
+ 35.times { payments << values[9] }
97
+
98
+ payments[0..-2].each_with_index do |payment, index|
99
+ assert_equal payment, @arm.payments[index]
100
+ end
101
+ end
102
+
103
+ it "should have a final payment of $1601.78 (due to rounding)" do
104
+ assert_equal D('-1601.78'), @arm.payments[-1]
105
+ end
106
+
107
+ it "should have total payments of $47,505.92" do
108
+ assert_equal D('-477505.92'), @arm.payments.sum
109
+ end
110
+
111
+ it "should have total interest charges of $277,505.92" do
112
+ assert_equal D('277505.92'), @arm.interest.sum
113
+ end
114
+ end
115
+
116
+ describe "a fixed-rate amortization of 200000 at 3.75% over 30 years, where an additional 100 is paid each month" do
117
+ before(:all) do
118
+ @rate = Rate.new(0.0375, :apr, :duration => (30 * 12))
119
+ @principal = D(200000)
120
+ @exp = Amortization.new(@principal, @rate){ |period| period.payment - 100 }
121
+ end
122
+
123
+ it "should have a principal of $200,000" do
124
+ assert_equal @principal, @exp.principal
125
+ end
126
+
127
+ it "should have a final balance of zero" do
128
+ assert @exp.balance.zero?
129
+ end
130
+
131
+ it "should have a duration of 301 months" do
132
+ assert_equal 301, @exp.duration
133
+ end
134
+
135
+ it "should have a monthly payment of $1026.23" do
136
+ assert_equal D('-1026.23'), @exp.payment
137
+ end
138
+
139
+ it "should have a final payment of $1011.09" do
140
+ assert_equal D('-1011.09'), @exp.payments[-1]
141
+ end
142
+
143
+ it "should have total payments of $308,880.09" do
144
+ assert_equal D('-308880.09'), @exp.payments.sum
145
+ end
146
+
147
+ it "should have total additional payments of $30,084.86" do
148
+ assert_equal D('-30084.86'), @exp.additional_payments.sum
149
+ end
150
+
151
+ it "should have total interest charges of $108880.09" do
152
+ assert_equal D('108880.09'), @exp.interest.sum
153
+ end
154
+ end
155
+ end
156
+
157
+ describe "Numeric Method" do
158
+ it 'works with simple invocation' do
159
+ rate = Rate.new(0.0375, :apr, :duration => (30 * 12))
160
+ amt_method = 300000.amortize(rate)
161
+ amt_class = Amortization.new(300000, rate)
162
+ assert_equal amt_method, amt_class
163
+ end
164
+
165
+ it 'works with block invocation' do
166
+ rate = Rate.new(0.0375, :apr, :duration => (30 * 12))
167
+ amt_method = 300000.amortize(rate){ |period| period.payment-300 }
168
+ amt_class = Amortization.new(300000, rate){ |period| period.payment-300 }
169
+ assert_equal amt_method, amt_class
170
+ end
171
+ end
@@ -0,0 +1,32 @@
1
+ require_relative 'test_helper'
2
+
3
+ describe "Cashflows" do
4
+ describe "an array of numeric cashflows" do
5
+ it "should have an Internal Rate of Return" do
6
+ assert_equal D("0.143"), [-4000,1200,1410,1875,1050].irr.round(3)
7
+ assert_raises(ArgumentError) { [10,20,30].irr }
8
+ end
9
+
10
+ it "should have a Net Present Value" do
11
+ assert_equal D("49.211"), [-100.0, 60, 60, 60].npv(0.1).round(3)
12
+ end
13
+ end
14
+
15
+ describe "an array of Transactions" do
16
+ before(:all) do
17
+ @xactions=[]
18
+ @xactions << Transaction.new(-1000, :date => Time.new(1985, 1, 1))
19
+ @xactions << Transaction.new( 600, :date => Time.new(1990, 1, 1))
20
+ @xactions << Transaction.new( 600, :date => Time.new(1995, 1, 1))
21
+ end
22
+
23
+ it "should have an Internal Rate of Return" do
24
+ assert_equal D("0.024851"), @xactions.xirr.effective.round(6)
25
+ assert_raises(ArgumentError) { @xactions[1, 2].xirr }
26
+ end
27
+
28
+ it "should have a Net Present Value" do
29
+ assert_equal D("-937.41"), @xactions.xnpv(0.6).round(2)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,15 @@
1
+ require 'minitest/autorun'
2
+ require 'minitest/spec'
3
+
4
+ require 'active_support/all'
5
+
6
+ require 'pry'
7
+
8
+ require 'flt'
9
+ require 'flt/d'
10
+
11
+ require_relative '../lib/finance/amortization.rb'
12
+ require_relative '../lib/finance/cashflows.rb'
13
+ require_relative '../lib/finance/rates.rb'
14
+ require_relative '../lib/finance/transaction.rb'
15
+ include Finance