finance_velocity 2.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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