finance_rb 0.0.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3a0dc37279e3b577acb13a90c61ad4f232573a4d8c0eccdf19a267d42001a9ea
4
- data.tar.gz: ca6db2175dd770056d7539d555b239127bcc5836ae79826edc6807a4f5bd4311
3
+ metadata.gz: d76ff15f6be262332aa729708a548d775f1caaaefaa3135c1d545660c34717ca
4
+ data.tar.gz: 2d75e526b34bf1704686e3fb9bf5198b4b2d302f05e714207d8d06833ce96acf
5
5
  SHA512:
6
- metadata.gz: 395383e7e7c9b2b564a738aae13bc6f95d7180652b951a2fa4cf90118e551cb0cba6e87badb4ca23c7b5ab790be2de0ff5bef0e3736c50c18a7246262b2ae496
7
- data.tar.gz: 5c9a8d1e5b8726234fafa45ed747dcf881f7ae92a9157abf34e9186594775a4e651fc8c09395cdd9fd30e21426e217c4216f2b13644ee15f324a967325d4bf6a
6
+ metadata.gz: 9545eebb0c540d6e5f3d75cdbf8a5b7fabe0ed75860601dd278f2c0b13ca05285a9d0865d978837532c92c2fb70815c5f450a10d6ff7bd008330ae81ac4d915b
7
+ data.tar.gz: bffcb93c73279bea34db04dbc39d0b6747e9d609e91a3a5f8006aaefe6ca08be2a4109b033b622a3382a4232a4e3ffba4d1a2eb168fbf6f1e6fe73fd971ab20c
data/CHANGELOG.md CHANGED
@@ -1,7 +1,29 @@
1
+ ## [0.1.2] - 2021-04-05
2
+
3
+ ### Added
4
+ * Implement `Finance::Loan#ipmt`
5
+
6
+ ## [0.1.1] - 2021-03-30
7
+
8
+ ### Added
9
+ * Implement `Finance::Loan#fv`
10
+
11
+ ## [0.1.0] - 2021-03-28
12
+
13
+ ### Added
14
+ * Create a basic structure for `Finance::Loan`
15
+ * Implement `Finance::Loan#pmt`
16
+
17
+
18
+ ## [0.0.4] - 2021-03-25
19
+
20
+ ### Added
21
+ * Implement `Finance::Calculations#mirr`
22
+
1
23
  ## [0.0.3] - 2021-03-23
2
24
 
3
25
  ### Added
4
- * Implement Finance::Calculations#irr using Newton's method
26
+ * Implement `Finance::Calculations#irr` using Newton's method
5
27
 
6
28
  ## [0.0.2] - 2021-03-22
7
29
 
data/README.md CHANGED
@@ -2,20 +2,50 @@
2
2
 
3
3
  This package is a ruby native port of the numpy-financial package with some helpful additional functions.
4
4
 
5
- The functions in this package are a scalar version of their vectorised counterparts in the [numpy-financial](https://github.com/numpy/numpy-financial) library.
5
+ The functions in this package are a scalar version of their vectorised counterparts in the [numpy-financial](https://github.com/numpy/numpy-financial) library.
6
+
7
+ [![Release](https://img.shields.io/github/v/release/wowinter13/finance_rb.svg?style=flat-square)](https://github.com/wowinter13/finance_rb/releases) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) [![Maintainability](https://api.codeclimate.com/v1/badges/bbca82ad7815794c6718/maintainability)](https://codeclimate.com/github/wowinter13/finance_rb/maintainability)
6
8
 
7
9
  Currently, only some functions are ported,
8
10
  which are as follows:
9
11
 
10
12
  | numpy-financial function | ruby native function ported? | info|
11
13
  |:------------------------: |:------------------: | :------------------|
12
- | fv | | Computes the future value|
13
- | ipmt | | Computes interest payment for a loan|
14
- | pmt | | Computes the fixed periodic payment(principal + interest) made against a loan amount|
15
- | ppmt | | Computes principal payment for a loan|
14
+ | fv || Computes the future value|
15
+ | ipmt || Computes interest payment for a loan|
16
+ | pmt || Computes the fixed periodic payment(principal + interest) made against a loan amount|
17
+ | ppmt || Computes principal payment for a loan|
16
18
  | nper | | Computes the number of periodic payments|
17
19
  | pv | | Computes the present value of a payment|
18
- | rate || Computes the rate of interest per period|
19
- | irr | | Computes the internal rate of return|
20
+ | rate | | Computes the rate of interest per period|
21
+ | irr || Computes the internal rate of return|
20
22
  | npv | ✅ | Computes the net present value of a series of cash flow|
21
- | mirr | | Computes the modified internal rate of return|
23
+ | mirr || Computes the modified internal rate of return|
24
+
25
+ ## Installation
26
+
27
+ finance_rb is available as a gem, to install it just install the gem:
28
+
29
+ gem install finance_rb
30
+
31
+ If you're using Bundler, add the gem to Gemfile.
32
+
33
+ gem 'finance_rb'
34
+
35
+ Run `bundle install`.
36
+
37
+ ## Running tests
38
+
39
+ bundle exec rspec spec/
40
+
41
+ ## Contributing
42
+
43
+ 1. Fork it ( https://github.com/wowinter13/finance_rb/fork )
44
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
45
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
46
+ 4. Push to the branch (`git push origin my-new-feature`)
47
+ 5. Create a new Pull Request
48
+
49
+ ## License
50
+
51
+ MIT License. See LICENSE for details.
@@ -35,6 +35,8 @@ module Finance
35
35
  # @return [Float] Internal Rate of Return for periodic input values.
36
36
  #
37
37
  # @param [Array<Numeric>] :values Input cash flows per time period.
38
+ # At least, must contain one positive and one negative value.
39
+ # Otherwise, irr equals zero.
38
40
  #
39
41
  # @example
40
42
  # require 'finance_rb'
@@ -44,10 +46,7 @@ module Finance
44
46
  # @see L. J. Gitman, "Principles of Managerial Finance, Brief," 3rd ed.,
45
47
  # Addison-Wesley, 2003, pg. 348.
46
48
  def irr(values)
47
- inflows, outflows = values.partition{ |i| i >= 0 }
48
- if inflows.empty? || outflows.empty?
49
- return 0.0
50
- end
49
+ return 0.0 unless correct_cashflows?(values)
51
50
 
52
51
  func = BigDecimal.limit(100)
53
52
  func = Function.new(values)
@@ -56,11 +55,54 @@ module Finance
56
55
  rate[0].to_f
57
56
  end
58
57
 
58
+ # MIRR computes the modified Rate of Interest.
59
+ #
60
+ # @return [Float] Modified Internal Rate of Return.
61
+ #
62
+ # @param [Array<Numeric>] :values
63
+ # At least, must contain one positive and one negative value.
64
+ # Otherwise, mirr equals zero.
65
+ # @param [Numeric] :rate Interest rate paid on the cash flows
66
+ # @param [Numeric] :reinvest_rate Interest rate received on the cash flows upon reinvestment
67
+ #
68
+ # @example
69
+ # require 'finance_rb'
70
+ # Finance::Calculations.mirr([100, 200, -50, 300, -200], 0.05, 0.06) => 0.2979256979689131
71
+ #
72
+ # @see https://en.wikipedia.org/wiki/Modified_internal_rate_of_return
73
+ def mirr(values, rate, reinvest_rate)
74
+ inflows = [];
75
+ outflows = [];
76
+ # We prefer manual enumeration over the partition
77
+ # because of the need to replace outflows with zeros.
78
+ values.each do |val|
79
+ if val >= 0
80
+ inflows << val
81
+ outflows << 0.0
82
+ else
83
+ outflows << val
84
+ inflows << 0.0
85
+ end
86
+ end
87
+ if outflows.all?(0.0) || inflows.all?(0.0)
88
+ return 0.0
89
+ end
90
+ fv = npv(reinvest_rate, inflows).abs
91
+ pv = npv(rate, outflows).abs
92
+
93
+ return (fv/pv) ** (1.0/(values.size - 1)) * (1 + reinvest_rate) - 1
94
+ end
95
+
59
96
  alias net_present_value npv
60
97
  alias internal_return_rate irr
61
98
 
62
99
  private
63
100
 
101
+ def correct_cashflows?(values)
102
+ inflows, outflows = values.partition{ |i| i >= 0 }
103
+ !(inflows.empty? || outflows.empty?)
104
+ end
105
+
64
106
  # Base class for working with Newton's Method.
65
107
  # For more details, see Bigdecimal::Newton.
66
108
  # @api private
data/lib/finance/loan.rb CHANGED
@@ -2,12 +2,182 @@
2
2
 
3
3
  module Finance
4
4
  class Loan
5
- def initialize; end
5
+ PAYMENT_TYPE_MAPPING = { end: 0, beginning: 1 }.freeze
6
6
 
7
- def pmt; end
7
+ # @return [Float] The amount of loan request (I.e. a present value)
8
+ # You can use #pv method to calculate value if param is not defined.
9
+ # Defaults to 0.
10
+ attr_accessor :amount
8
11
 
9
- def ipmt; end
12
+ # @return [Integer] Specification of whether payment is made
13
+ # at the beginning (ptype = 1) or the end (ptype = 0) of each period.
14
+ # Defaults to {:end, 0}.
15
+ attr_accessor :ptype
10
16
 
11
- def ppmt; end
17
+ # @return [Float] The nominal annual rate of interest as decimal (not per cent).
18
+ # (e.g., 13% -> 0.13)
19
+ # Defaults to 0.
20
+ attr_accessor :nominal_rate
21
+
22
+ # @return [Float] The monthly rate is the nominal annual rate divided by 12.
23
+ # Defaults to 0.
24
+ attr_reader :monthly_rate
25
+
26
+ # @return [Float] The number of periods to be compounded for. (I.e. Nper())
27
+ # Defaults to 1.
28
+ attr_accessor :duration
29
+
30
+ # @return [Float] Future value.
31
+ # You can use #fv method to calculate value if param is not defined.
32
+ # Defaults to 0.
33
+ attr_accessor :future_value
34
+
35
+ # @return [Float] The (fixed) periodic payment.
36
+ # You can use #pmt method to calculate value if param is not defined.
37
+ attr_accessor :payment
38
+
39
+ # @return [Float] Period under consideration.
40
+ attr_accessor :period
41
+
42
+ # Create a new Loan instance.
43
+ def initialize(**options)
44
+ initialize_payment_type(options[:ptype])
45
+ @nominal_rate = options.fetch(:nominal_rate, 0).to_f
46
+ @duration = options.fetch(:duration, 1).to_f
47
+ @amount = options.fetch(:amount, 0).to_f
48
+ @future_value = options.fetch(:future_value, 0).to_f
49
+ @period = options[:period]
50
+ @payment = options[:payment]
51
+ @monthly_rate = @nominal_rate / 12
52
+ end
53
+
54
+ # Pmt computes the payment against a loan principal plus interest (future_value = 0).
55
+ # It can also be used to calculate the recurring payments needed to achieve
56
+ # a certain future value given an initial deposit,
57
+ # a fixed periodically compounded interest rate, and the total number of periods.
58
+ #
59
+ # Required Loan arguments: nominal_rate, duration, amount, future_value*
60
+ #
61
+ # @return [Numeric] The (fixed) periodic payment.
62
+ #
63
+ # @example
64
+ # require 'finance_rb'
65
+ # Finance::Loan.new(nominal_rate: 0.1, duration: 12, amount: 1000, ptype: :end).pmt
66
+ # #=> 87.9158872300099
67
+ #
68
+ # @see http://www.oasis-open.org/committees/documents.php?wg_abbrev=office-formulaOpenDocument-formula-20090508.odt
69
+ # @see [WRW] Wheeler, D. A., E. Rathke, and R. Weir (Eds.) (2009, May).
70
+ # Open Document Format for Office Applications (OpenDocument)v1.2,
71
+ # Part 2: Recalculated Formula (OpenFormula) Format - Annotated Version,
72
+ # Pre-Draft 12. Organization for the Advancement of Structured Information
73
+ # Standards (OASIS). Billerica, MA, USA. [ODT Document].
74
+ def pmt
75
+ factor = (1.0 + monthly_rate)**duration
76
+ second_factor =
77
+ if monthly_rate.zero?
78
+ duration
79
+ else
80
+ (factor - 1) * (1 + monthly_rate * ptype) / monthly_rate
81
+ end
82
+
83
+ -((future_value + amount * factor) / second_factor)
84
+ end
85
+
86
+ # IPmt computes interest payment for a loan under a given period.
87
+ #
88
+ # Required Loan arguments: period, nominal_rate, duration, amount, future_value*
89
+ #
90
+ # @return [Float] Interest payment for a loan.
91
+ #
92
+ # @example
93
+ # require 'finance_rb'
94
+ # Finance::Loan.new(nominal_rate: 0.0824, duration: 12, amount: 2500, period: 1).ipmt
95
+ # #=> -17.166666666666668
96
+ #
97
+ # @see http://www.oasis-open.org/committees/documents.php?wg_abbrev=office-formulaOpenDocument-formula-20090508.odt
98
+ # @see [WRW] Wheeler, D. A., E. Rathke, and R. Weir (Eds.) (2009, May).
99
+ # Open Document Format for Office Applications (OpenDocument)v1.2,
100
+ # Part 2: Recalculated Formula (OpenFormula) Format - Annotated Version,
101
+ # Pre-Draft 12. Organization for the Advancement of Structured Information
102
+ # Standards (OASIS). Billerica, MA, USA. [ODT Document].
103
+ def ipmt
104
+ raise ArgumentError, 'no period given' if period.nil?
105
+
106
+ ipmt_val = remaining_balance * monthly_rate
107
+ if ptype == PAYMENT_TYPE_MAPPING[:beginning]
108
+ period == 1 ? 0.0 : (ipmt_val / 1 + monthly_rate)
109
+ else
110
+ ipmt_val
111
+ end
112
+ end
113
+
114
+ # PPmt computes principal payment for a loan under a given period.
115
+ #
116
+ # Required Loan arguments: period, nominal_rate, duration, amount, future_value*
117
+ #
118
+ # @return [Float] Principal payment for a loan under a given period.
119
+ #
120
+ # @example
121
+ # require 'finance_rb'
122
+ # Finance::Loan.new(nominal_rate: 0.0824, duration: 12, amount: 2500, period: 1).ppmt
123
+ # #=> -200.58192368678277
124
+ #
125
+ # @see http://www.oasis-open.org/committees/documents.php?wg_abbrev=office-formulaOpenDocument-formula-20090508.odt
126
+ # @see [WRW] Wheeler, D. A., E. Rathke, and R. Weir (Eds.) (2009, May).
127
+ # Open Document Format for Office Applications (OpenDocument)v1.2,
128
+ # Part 2: Recalculated Formula (OpenFormula) Format - Annotated Version,
129
+ # Pre-Draft 12. Organization for the Advancement of Structured Information
130
+ # Standards (OASIS). Billerica, MA, USA. [ODT Document].
131
+ def ppmt
132
+ pmt - ipmt
133
+ end
134
+
135
+ # Fv computes future value at the end of some periods (duration).
136
+ # Required Loan arguments: nominal_rate, duration, payment, amount*
137
+ #
138
+ # @param payment [Float] The (fixed) periodic payment.
139
+ # In case you don't want to modify the original loan, use this parameter to recalculate fv.
140
+ #
141
+ # @return [Float] The value at the end of the `duration` periods.
142
+ #
143
+ # @example
144
+ # require 'finance_rb'
145
+ # Finance::Loan.new(nominal_rate: 0.05, duration: 120, amount: -100, payment: -200).fv
146
+ # #=> 15692.928894335748
147
+ #
148
+ # @see http://www.oasis-open.org/committees/documents.php?wg_abbrev=office-formulaOpenDocument-formula-20090508.odt
149
+ # @see [WRW] Wheeler, D. A., E. Rathke, and R. Weir (Eds.) (2009, May).
150
+ # Open Document Format for Office Applications (OpenDocument)v1.2,
151
+ # Part 2: Recalculated Formula (OpenFormula) Format - Annotated Version,
152
+ # Pre-Draft 12. Organization for the Advancement of Structured Information
153
+ # Standards (OASIS). Billerica, MA, USA. [ODT Document].
154
+ def fv(payment: nil)
155
+ raise ArgumentError, 'no payment given' if self.payment.nil? && payment.nil?
156
+
157
+ final_payment = payment || self.payment
158
+
159
+ factor = (1.0 + monthly_rate)**duration
160
+ second_factor = (factor - 1) * (1 + monthly_rate * ptype) / monthly_rate
161
+
162
+ -((amount * factor) + (final_payment.to_f * second_factor))
163
+ end
164
+
165
+ private
166
+
167
+ def initialize_payment_type(ptype)
168
+ @ptype =
169
+ if ptype.nil? || !PAYMENT_TYPE_MAPPING.keys.include?(ptype)
170
+ PAYMENT_TYPE_MAPPING[:end]
171
+ else
172
+ PAYMENT_TYPE_MAPPING[ptype]
173
+ end
174
+ end
175
+
176
+ def remaining_balance
177
+ self.class.new(
178
+ nominal_rate: nominal_rate.to_f, duration: period - 1.0,
179
+ amount: amount.to_f, ptype: PAYMENT_TYPE_MAPPING.key(ptype)
180
+ ).fv(payment: pmt)
181
+ end
12
182
  end
13
183
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Finance
4
- VERSION = "0.0.3"
4
+ VERSION = "0.2.0"
5
5
  end
@@ -26,7 +26,7 @@ RSpec.describe Finance::Calculations do
26
26
  ).to eq(0.14299344106053188)
27
27
  end
28
28
 
29
- it 'calculates zero value for cashflows w/o any inflows' do
29
+ it 'calculates zero for cashflows w/o any inflows' do
30
30
  expect(
31
31
  Finance::Calculations.irr([100,500,200,50])
32
32
  ).to eq(0.0)
@@ -38,4 +38,46 @@ RSpec.describe Finance::Calculations do
38
38
  ).to eq(-0.09549583035161031)
39
39
  end
40
40
  end
41
+
42
+ describe '#mirr' do
43
+ it 'calculates correct mirr value' do
44
+ expect(
45
+ Finance::Calculations.mirr(
46
+ [-120000.0, 39000.0, 30000.0, 21000.0, 37000.0, 46000.0], 0.10, 0.12
47
+ )
48
+ ).to eq(0.1260941303659051)
49
+ end
50
+
51
+ it 'calculates correct mirr value with integers' do
52
+ expect(
53
+ Finance::Calculations.mirr(
54
+ [-4500, -800, 800, 800, 600, 600, 800, 800, 700, 3000], 0.08, 0.055
55
+ )
56
+ ).to eq(0.06659717503155349)
57
+ end
58
+
59
+ it 'calculates zero for cashflows w/o any outflows' do
60
+ expect(
61
+ Finance::Calculations.mirr(
62
+ [39000, 30000, 21000, 37000, 46000], 0.10, 0.12
63
+ )
64
+ ).to eq(0.0)
65
+ end
66
+
67
+ it 'calculates zero for cashflows w/o any inflows' do
68
+ expect(
69
+ Finance::Calculations.mirr(
70
+ [-1000, -5000, -2000, -100, -50], 0.10, 0.12
71
+ )
72
+ ).to eq(0.0)
73
+ end
74
+
75
+ it 'calculates correct mirr value for a shuffled order' do
76
+ expect(
77
+ Finance::Calculations.mirr(
78
+ [100, 200, -50, 300, -200], 0.05, 0.06
79
+ )
80
+ ).to eq(0.3428233878421769)
81
+ end
82
+ end
41
83
  end
@@ -0,0 +1,149 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Finance::Loan do
4
+ describe '#pmt' do
5
+ context 'w/o a full set of params' do
6
+ it 'calculates correct pmt value w/o :ptype' do
7
+ loan = Finance::Loan.new(nominal_rate: 0.1, duration: 12, amount: 1000)
8
+ expect(loan.pmt).to eq(-87.9158872300099)
9
+ end
10
+
11
+ it 'calculates correct pmt value w/o :nominal_rate' do
12
+ loan = Finance::Loan.new(duration: 12, amount: 1200, ptype: :end)
13
+ expect(loan.pmt).to eq(-100)
14
+ end
15
+ end
16
+
17
+ context 'with zero rates' do
18
+ it 'calculates correct pmt value for 3 years' do
19
+ loan = Finance::Loan.new(nominal_rate: 0, duration: 36, amount: 10_000, ptype: :end)
20
+ expect(loan.pmt).to eq(-277.77777777777777)
21
+ end
22
+
23
+ it 'calculates correct pmt value for 6 months' do
24
+ loan = Finance::Loan.new(nominal_rate: 0, duration: 6, amount: 10_000, ptype: :end)
25
+ expect(loan.pmt).to eq(-1666.6666666666667)
26
+ end
27
+ end
28
+
29
+ context 'with :beginning ptype' do
30
+ it 'calculates correct pmt value' do
31
+ loan = Finance::Loan.new(nominal_rate: 0.12, duration: 6, amount: 1000, ptype: :beginning)
32
+ expect(loan.pmt).to eq(-170.8399670404763)
33
+ end
34
+ end
35
+
36
+ it 'calculates correct pmt value' do
37
+ loan = Finance::Loan.new(nominal_rate: 0.13, duration: 90, amount: 1_000_000, ptype: :end)
38
+ expect(loan.pmt).to eq(-17_449.90775727763)
39
+ end
40
+ end
41
+
42
+ describe '#fv' do
43
+ context 'with loan arguments' do
44
+ it 'calculates correct fv value' do
45
+ loan = Finance::Loan.new(nominal_rate: 0.05, duration: 120, amount: -100, payment: -100)
46
+ expect(loan.fv).to eq(15_692.928894335748)
47
+ end
48
+
49
+ context 'with :ptype' do
50
+ it 'calculates correct fv value' do
51
+ loan = Finance::Loan.new(
52
+ nominal_rate: 0.9, duration: 20, amount: 0, payment: -2000, ptype: :beginning
53
+ )
54
+ expect(loan.fv).to eq(93_105.06487352113)
55
+ end
56
+ end
57
+ end
58
+
59
+ context 'with an optional :payment argument' do
60
+ it 'calculates correct fv value' do
61
+ loan = Finance::Loan.new(nominal_rate: 0.05, duration: 120, amount: -100, payment: -200)
62
+ expect(loan.fv(payment: -100)).to eq(15_692.928894335748)
63
+ end
64
+ end
65
+
66
+ context 'w/o any payments' do
67
+ it 'raises an ArgumentError exception w/o loan arguments' do
68
+ loan = Finance::Loan.new(nominal_rate: 0.05, duration: 120, amount: -100)
69
+ expect { loan.fv }.to raise_error(ArgumentError, "no payment given")
70
+ end
71
+ end
72
+ end
73
+
74
+ describe '#ipmt' do
75
+ context 'when 1 period' do
76
+ it 'calculates correct ipmt value' do
77
+ loan = Finance::Loan.new(
78
+ nominal_rate: 0.0824, duration: 12, amount: 2500, period: 1
79
+ )
80
+ expect(loan.ipmt).to eq(-17.166666666666668)
81
+ end
82
+ end
83
+
84
+ context 'when 2 periods' do
85
+ it 'calculates correct ipmt value' do
86
+ loan = Finance::Loan.new(
87
+ nominal_rate: 0.0824, duration: 12, amount: 2500, period: 2
88
+ )
89
+ expect(loan.ipmt).to eq(-15.789337457350777)
90
+ end
91
+ end
92
+
93
+ context 'when 3 periods' do
94
+ it 'calculates correct ipmt value' do
95
+ loan = Finance::Loan.new(
96
+ nominal_rate: 0.0824, duration: 12.0, amount: 2500.0, period: 3.0, fv: 0.0
97
+ )
98
+ expect(loan.ipmt).to eq(-14.402550587464257)
99
+ end
100
+ end
101
+ end
102
+
103
+ describe '#ppmt' do
104
+ context 'when 1 period' do
105
+ it 'calculates correct ppmt value' do
106
+ loan = Finance::Loan.new(
107
+ nominal_rate: 0.0824, duration: 12, amount: 2500, period: 1
108
+ )
109
+ expect(loan.ppmt).to eq(-200.58192368678277)
110
+ end
111
+ end
112
+
113
+ context 'when 2 periods' do
114
+ it 'calculates correct ppmt value' do
115
+ loan = Finance::Loan.new(
116
+ nominal_rate: 0.0824, duration: 12, amount: 2500, period: 2
117
+ )
118
+ expect(loan.ppmt).to eq(-201.95925289609866)
119
+ end
120
+ end
121
+
122
+ context 'when 3 periods' do
123
+ it 'calculates correct ppmt value' do
124
+ loan = Finance::Loan.new(
125
+ nominal_rate: 0.0824, duration: 12, amount: 2500, period: 3
126
+ )
127
+ expect(loan.ppmt).to eq(-203.34603976598518)
128
+ end
129
+ end
130
+
131
+ context 'when 4 periods' do
132
+ it 'calculates correct ppmt value' do
133
+ loan = Finance::Loan.new(
134
+ nominal_rate: 0.0824, duration: 12, amount: 2500, period: 4
135
+ )
136
+ expect(loan.ppmt).to eq(-204.7423492390449)
137
+ end
138
+ end
139
+
140
+ context 'when 5 periods' do
141
+ it 'calculates correct ppmt value' do
142
+ loan = Finance::Loan.new(
143
+ nominal_rate: 0.0824, duration: 12, amount: 2500, period: 5
144
+ )
145
+ expect(loan.ppmt).to eq(-206.1482467038197)
146
+ end
147
+ end
148
+ end
149
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: finance_rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vlad Dyachenko
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-03-22 00:00:00.000000000 Z
11
+ date: 2021-04-30 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A ruby port of numpy-financial functions. This library provides a Ruby
14
14
  interface for working with interest rates, mortgage amortization, and cashflows
@@ -27,6 +27,7 @@ files:
27
27
  - lib/finance/version.rb
28
28
  - lib/finance_rb.rb
29
29
  - spec/finance/calculations_spec.rb
30
+ - spec/finance/loan_spec.rb
30
31
  - spec/spec_helper.rb
31
32
  homepage: https://github.com/wowinter13/finance_rb
32
33
  licenses:
@@ -57,4 +58,5 @@ specification_version: 4
57
58
  summary: A library for finance manipulations in Ruby.
58
59
  test_files:
59
60
  - spec/finance/calculations_spec.rb
61
+ - spec/finance/loan_spec.rb
60
62
  - spec/spec_helper.rb