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 +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
|