finance_rb 0.2.2 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +9 -1
- data/lib/finance/calculations.rb +2 -0
- data/lib/finance/loan.rb +56 -4
- data/lib/finance/version.rb +1 -1
- data/spec/finance/loan_spec.rb +11 -0
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0abc599e1b7158a3095f3b9ac1627c54a0a85a9808a9afcc915a98fadfaff42d
|
4
|
+
data.tar.gz: f4417a96a3226bf76574e37fcf4c7f7e2bba9a92ea6586f43087444f4ecc239a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fd17e47f2b8418ef8e1e1c7b24385bb6aff9f6d4342915a901f5590a4b3dc25c0d6154bf8af273bc377fa743e5104391ce05a67c80fbd93b9509f38bbf678ec4
|
7
|
+
data.tar.gz: 69ed50d7d91a8b416af2796ef0232dbf32bcae226e7cc71c174de163f4ddab4169af9f09952b7b5104367848b892fcafa971c737b50384bba8019dc0c71fa6bd
|
data/CHANGELOG.md
CHANGED
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 |
|
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:
|
data/lib/finance/calculations.rb
CHANGED
@@ -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]
|
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]
|
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]
|
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,
|
data/lib/finance/version.rb
CHANGED
data/spec/finance/loan_spec.rb
CHANGED
@@ -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
|