finance_rb 0.2.2 → 1.0.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 07e154f5ba5d444fe1e2c782c39a3d21a79b9fd3d413fba6e7c5285fa5f07df4
4
- data.tar.gz: bef7aea3a7f54df1fc69d05619e9416637c717ce7e8b4d3a211573fbfbf5a6df
3
+ metadata.gz: 0abc599e1b7158a3095f3b9ac1627c54a0a85a9808a9afcc915a98fadfaff42d
4
+ data.tar.gz: f4417a96a3226bf76574e37fcf4c7f7e2bba9a92ea6586f43087444f4ecc239a
5
5
  SHA512:
6
- metadata.gz: bf67fafbda3defb85d73581d02b3dc00b26f83c6b03e4f35bd5c2d3a0ac661a823cd737d8055c54309b8a6d6feba8be7d03675b39ddb95b2e8f7ceaa94a7e472
7
- data.tar.gz: 4f429be0368ac5e986c689fcd6afd146cec1676741d149ced828ae6d03e38e2d2e1ebdfeae88fce1d76de1a31c51a08fb0809577362f07f1de0e70e761bfa8b1
6
+ metadata.gz: fd17e47f2b8418ef8e1e1c7b24385bb6aff9f6d4342915a901f5590a4b3dc25c0d6154bf8af273bc377fa743e5104391ce05a67c80fbd93b9509f38bbf678ec4
7
+ data.tar.gz: 69ed50d7d91a8b416af2796ef0232dbf32bcae226e7cc71c174de163f4ddab4169af9f09952b7b5104367848b892fcafa971c737b50384bba8019dc0c71fa6bd
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## [1.0.0] - 2021-05-01
2
+
3
+ ### Added
4
+ * Implement `Finance::Loan#rate`
5
+
1
6
  ## [0.2.2] - 2021-05-01
2
7
 
3
8
  ### Added
data/README.md CHANGED
@@ -17,11 +17,19 @@ which are as follows:
17
17
  | ppmt | ✅ | Computes principal payment for a loan|
18
18
  | nper | ✅ | Computes the number of periodic payments|
19
19
  | pv | ✅ | Computes the present value of a payment|
20
- | rate | | Computes the rate of interest per period|
20
+ | rate || Computes the rate of interest per period|
21
21
  | irr | ✅ | Computes the internal rate of return|
22
22
  | npv | ✅ | Computes the net present value of a series of cash flow|
23
23
  | mirr | ✅ | Computes the modified internal rate of return|
24
24
 
25
+
26
+ Things to be done:
27
+
28
+ 1. Xirr
29
+ 2. More specs for edge cases
30
+ 3. Fee, currency protection and other cool stuff for advanced usage
31
+ 4. Better errors
32
+
25
33
  ## Installation
26
34
 
27
35
  finance_rb is available as a gem, to install it just install the gem:
@@ -98,6 +98,7 @@ module Finance
98
98
 
99
99
  private
100
100
 
101
+ # @api private
101
102
  def correct_cashflows?(values)
102
103
  inflows, outflows = values.partition{ |i| i >= 0 }
103
104
  !(inflows.empty? || outflows.empty?)
@@ -105,6 +106,7 @@ module Finance
105
106
 
106
107
  # Base class for working with Newton's Method.
107
108
  # For more details, see Bigdecimal::Newton.
109
+ #
108
110
  # @api private
109
111
  class Function
110
112
  def initialize(values)
data/lib/finance/loan.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Finance
4
4
  class Loan
5
- PAYMENT_TYPE_MAPPING = { end: 0, beginning: 1 }.freeze
5
+ PAYMENT_TYPE_MAPPING = { end: 0.0, beginning: 1.0 }.freeze
6
6
 
7
7
  # @return [Float] The amount of loan request (I.e. a present value)
8
8
  # You can use #pv method to calculate value if param is not defined.
@@ -88,7 +88,7 @@ module Finance
88
88
  #
89
89
  # Required Loan arguments: period, nominal_rate, duration, amount, future_value*
90
90
  #
91
- # @return [Float] Interest payment for a loan.
91
+ # @return [Float] The interest payment for a loan.
92
92
  #
93
93
  # @example
94
94
  # require 'finance_rb'
@@ -116,7 +116,7 @@ module Finance
116
116
  #
117
117
  # Required Loan arguments: period, nominal_rate, duration, amount, future_value*
118
118
  #
119
- # @return [Float] Principal payment for a loan under a given period.
119
+ # @return [Float] The principal payment for a loan under a given period.
120
120
  #
121
121
  # @example
122
122
  # require 'finance_rb'
@@ -137,7 +137,7 @@ module Finance
137
137
  #
138
138
  # Required Loan arguments: payment, nominal_rate, period, amount, future_value*
139
139
  #
140
- # @return [Float] Number of periodic payments.
140
+ # @return [Float] The number of periodic payments.
141
141
  #
142
142
  # @example
143
143
  # require 'finance_rb'
@@ -202,8 +202,59 @@ module Finance
202
202
  -(future_value + (payment.to_f * second_factor)) / factor
203
203
  end
204
204
 
205
+ # Rate computes the interest rate per period
206
+ # by running Newton Rapson to find an approximate value.
207
+ #
208
+ # @return [Float] The interest rate.
209
+ #
210
+ # @param tolerance [Float] Required tolerance for the solution.
211
+ # @param initial_guess [Float] Starting guess for solving the rate of interest.
212
+ # @param iterations [Integer] Maximum iterations in finding the solution.
213
+ #
214
+ # @example
215
+ # require 'finance_rb'
216
+ # Finance::Loan.new(nominal_rate: 10, amount: -3500, payment: 0, duration: 10, future_value: 10000).rate
217
+ # #=> 0.11069085371426901
218
+ #
219
+ # @see http://www.oasis-open.org/committees/documents.php?wg_abbrev=office-formulaOpenDocument-formula-20090508.odt
220
+ # @see [WRW] Wheeler, D. A., E. Rathke, and R. Weir (Eds.) (2009, May).
221
+ # Open Document Format for Office Applications (OpenDocument)v1.2,
222
+ # Part 2: Recalculated Formula (OpenFormula) Format - Annotated Version,
223
+ # Pre-Draft 12. Organization for the Advancement of Structured Information
224
+ # Standards (OASIS). Billerica, MA, USA. [ODT Document].
225
+ def rate(tolerance: 1e-6, iterations: 100, initial_guess: 0.1)
226
+ next_iteration_rate = nil
227
+ current_iteration_rate = initial_guess
228
+
229
+ (0..iterations).each do |iteration|
230
+ next_iteration_rate = current_iteration_rate - rate_ratio(current_iteration_rate)
231
+ break if (next_iteration_rate - current_iteration_rate).abs <= tolerance
232
+ current_iteration_rate = next_iteration_rate
233
+ end
234
+
235
+ next_iteration_rate
236
+ end
237
+
205
238
  private
206
239
 
240
+ # rate_ratio computes the ratio
241
+ # that is used to find a single value that sets the non-liner equation to zero.
242
+ #
243
+ # @api private
244
+ def rate_ratio(rate)
245
+ t1 = (rate+1.0) ** duration
246
+ t2 = (rate+1.0) ** (duration-1.0)
247
+ g = future_value + t1 * amount + payment * (t1 - 1.0) * (rate * ptype + 1.0) / rate
248
+ derivative_g = \
249
+ (duration * t2 * amount)
250
+ - (payment * (t1 - 1.0) * (rate * ptype + 1.0) / (rate ** 2.0))
251
+ + (duration * payment * t2 * (rate * ptype + 1.0) / rate)
252
+ + (payment * (t1 - 1.0) * ptype/rate)
253
+
254
+ g / derivative_g
255
+ end
256
+
257
+ # @api private
207
258
  def initialize_payment_type(ptype)
208
259
  @ptype =
209
260
  if ptype.nil? || !PAYMENT_TYPE_MAPPING.keys.include?(ptype)
@@ -213,6 +264,7 @@ module Finance
213
264
  end
214
265
  end
215
266
 
267
+ # @api private
216
268
  def remaining_balance
217
269
  self.class.new(
218
270
  nominal_rate: nominal_rate.to_f, duration: period - 1.0,
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Finance
4
- VERSION = "0.2.2"
4
+ VERSION = "1.0.0"
5
5
  end
@@ -186,4 +186,15 @@ RSpec.describe Finance::Loan do
186
186
  end
187
187
  end
188
188
  end
189
+
190
+ describe '#rate' do
191
+ context 'with default arguments' do
192
+ it 'calculates correct rate value' do
193
+ loan = Finance::Loan.new(
194
+ nominal_rate: 10, amount: -3500, payment: 0, duration: 10, future_value: 10000
195
+ )
196
+ expect(loan.rate).to eq(0.11069085371426901)
197
+ end
198
+ end
199
+ end
189
200
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: finance_rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vlad Dyachenko