finrb 0.1.0 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +117 -63
- data/lib/finrb/amortization.rb +33 -33
- data/lib/finrb/cashflows.rb +51 -46
- data/lib/finrb/config.rb +2 -2
- data/lib/finrb/decimal.rb +8 -9
- data/lib/finrb/rates.rb +52 -51
- data/lib/finrb/transaction.rb +5 -5
- data/lib/finrb/utils.rb +388 -462
- data/lib/finrb.rb +9 -9
- metadata +18 -42
- data/.dockerignore +0 -2
- data/.gitattributes +0 -83
- data/.github/dependabot.yml +0 -7
- data/.github/issue_template.md +0 -15
- data/.github/pull_request_template.md +0 -17
- data/.github/workflows/ci.yml +0 -21
- data/.github/workflows/codeql.yml +0 -72
- data/.github/workflows/rubocop.yml +0 -24
- data/.gitignore +0 -114
- data/.rubocop.yml +0 -284
- data/.ruby-version +0 -1
- data/.semver +0 -5
- data/.yardopts +0 -1
- data/Dockerfile +0 -35
- data/Gemfile +0 -5
- data/Gemfile.lock +0 -119
- data/Rakefile +0 -33
- data/docs/.gitkeep +0 -0
- data/docs/api.md +0 -1086
- data/finrb.gemspec +0 -42
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ccdd649275425f90381f0836259a3f054db4a1f6e115bcd2f2a70a3460669cb4
|
4
|
+
data.tar.gz: ef0a8b3cae6e610be1e6eb5d191bf2a182086768af3272be1ca93126ff2b29f5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c8e35323bab165cca2e888ae745a85a9ee7a7a1ff348fa50e4929d44680a6383e13a15cc3a842d1aa2ba1804c14590f44cea406b7bf4706b36c131a7bd187492
|
7
|
+
data.tar.gz: c42221400c4d86b865541cb2df0c1a215b04c903536cd76d1bbc2a297cddb5de3276b568d196b5b4cb9b0c156cbe5433226db0764d21612b25e455dbafb25265
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -4,6 +4,18 @@
|
|
4
4
|
[![CodeQL](https://github.com/ncs1/finrb/actions/workflows/codeql.yml/badge.svg)](https://github.com/ncs1/finrb/actions/workflows/codeql.yml)
|
5
5
|
[![RuboCop](https://github.com/ncs1/finrb/actions/workflows/rubocop.yml/badge.svg)](https://github.com/ncs1/finrb/actions/workflows/rubocop.yml)
|
6
6
|
|
7
|
+
<!-- TOC depthfrom:2 -->
|
8
|
+
|
9
|
+
- [Overview](#overview)
|
10
|
+
- [Features](#features)
|
11
|
+
- [Configuration](#configuration)
|
12
|
+
- [API and examples](#api-and-examples)
|
13
|
+
- [Resources](#resources)
|
14
|
+
- [Acknowledgements](#acknowledgements)
|
15
|
+
- [License](#license)
|
16
|
+
|
17
|
+
<!-- /TOC -->
|
18
|
+
|
7
19
|
Ruby gem for financial calculations/modeling.
|
8
20
|
|
9
21
|
finrb forked from the ruby [finance](https://github.com/Edward-Intelligence/finance) gem.
|
@@ -14,66 +26,103 @@ finrb forked from the ruby [finance](https://github.com/Edward-Intelligence/fina
|
|
14
26
|
|
15
27
|
Currently implemented features include:
|
16
28
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
29
|
+
- Uses the [flt](https://github.com/jgoizueta/flt) gem to ensure precision decimal arithmetic in all calculations.
|
30
|
+
- Fixed-rate mortgage amortization (30/360).
|
31
|
+
- Interest rates
|
32
|
+
- Various cash flow computations, such as NPV and IRR.
|
33
|
+
- Adjustable rate mortgage amortization.
|
34
|
+
- Payment modifications (i.e., how does paying an additional $75 per month affect the amortization?)
|
35
|
+
- Utils class provides basic financial calculation utilities (ported from R's [FinCal](https://github.com/felixfan/FinCal) library):
|
36
|
+
|
37
|
+
- Basic Earnings Per Share
|
38
|
+
|
39
|
+
- Bond-equivalent yield (BEY), 2 x the semiannual discount rate
|
40
|
+
|
41
|
+
- Calculate the net increase in common shares from the potential exercise of stock options or warrants
|
42
|
+
|
43
|
+
- Calculate weighted average shares - weighted average number of common shares
|
44
|
+
|
45
|
+
- Cash ratio - Liquidity ratios measure the firm's ability to satisfy its short-term obligations as they come due.
|
46
|
+
|
47
|
+
- Computing Coefficient of variation
|
48
|
+
|
49
|
+
- Computing HPR, the holding period return
|
50
|
+
|
51
|
+
- Computing IRR, the internal rate of return
|
52
|
+
|
53
|
+
- Computing NPV, the PV of the cash flows less the initial (time = 0) outlay
|
54
|
+
|
55
|
+
- Computing Roy's safety-first ratio
|
56
|
+
|
57
|
+
- Computing Sampling error
|
58
|
+
|
59
|
+
- Computing Sharpe Ratio
|
60
|
+
|
61
|
+
- Computing TWRR, the time-weighted rate of return
|
62
|
+
|
63
|
+
- Computing bank discount yield (BDY) for a T-bill
|
64
|
+
|
65
|
+
- Computing money market yield (MMY) for a T-bill
|
66
|
+
|
67
|
+
- Computing the future value of an uneven cash flow series
|
68
|
+
|
69
|
+
- Computing the present value of an uneven cash flow series
|
70
|
+
|
71
|
+
- Computing the rate of return for each period
|
72
|
+
|
73
|
+
- Convert a given continuous compounded rate to a norminal rate
|
74
|
+
|
75
|
+
- Convert a given norminal rate to a continuous compounded rate
|
76
|
+
|
77
|
+
- Convert holding period return to the effective annual rate
|
78
|
+
|
79
|
+
- Convert stated annual rate to the effective annual rate (with continuous compounding)
|
80
|
+
|
81
|
+
- Cost of goods sold and ending inventory under three methods (FIFO,LIFO,Weighted average)
|
82
|
+
|
83
|
+
- Current ratio - Liquidity ratios measure the firm's ability to satisfy its short-term obligations as they come due.
|
84
|
+
|
85
|
+
- Debt ratio - Solvency ratios measure the firm's ability to satisfy its long-term obligations.
|
86
|
+
|
87
|
+
- Depreciation Expense Recognition - Straight-line depreciation (SL) allocates an equal amount of depreciation each year over the asset's useful life
|
88
|
+
|
89
|
+
- Depreciation Expense Recognition - double-declining balance (DDB), the most common declining balance method, which applies two times the straight-line rate to the declining balance.
|
90
|
+
|
91
|
+
- Diluted Earnings Per Share
|
92
|
+
|
93
|
+
- Equivalent/proportional Interest Rates
|
94
|
+
|
95
|
+
- Estimate future value (fv) (of a single sum)
|
96
|
+
|
97
|
+
- Estimate future value of an annuity
|
98
|
+
|
99
|
+
- Estimate period payment
|
100
|
+
|
101
|
+
- Estimate present value (pv) (of a single sum) (of an annuity)
|
102
|
+
|
103
|
+
- Estimate present value of a perpetuity
|
104
|
+
|
105
|
+
- Estimate the number of periods
|
106
|
+
|
107
|
+
- Financial leverage - Solvency ratios measure the firm's ability to satisfy its long-term obligations.
|
108
|
+
|
109
|
+
- Geometric mean return
|
110
|
+
|
111
|
+
- Gross profit margin - Evaluate a company's financial performance
|
112
|
+
|
113
|
+
- Harmonic mean, average price
|
114
|
+
|
115
|
+
- Long-term debt-to-equity - Solvency ratios measure the firm's ability to satisfy its long-term obligations.
|
116
|
+
|
117
|
+
- Net profit margin - Evaluate a company's financial performance
|
118
|
+
|
119
|
+
- Quick ratio - Liquidity ratios measure the firm's ability to satisfy its short-term obligations as they come due.
|
120
|
+
|
121
|
+
- Rate of return for a perpetuity
|
122
|
+
|
123
|
+
- Total debt-to-equity - Solvency ratios measure the firm's ability to satisfy its long-term obligations.
|
124
|
+
|
125
|
+
- Weighted mean as a portfolio return
|
77
126
|
|
78
127
|
### Configuration
|
79
128
|
|
@@ -94,9 +143,14 @@ See [api.md](docs/api.md)
|
|
94
143
|
|
95
144
|
## Resources
|
96
145
|
|
97
|
-
|
98
|
-
|
99
|
-
|
146
|
+
- [RubyGems Page](https://rubygems.org/gems/finrb)
|
147
|
+
- [Source Code](https://github.com/ncs1/finrb)
|
148
|
+
- [Bug Tracker](https://github.com/ncs1/finrb/issues)
|
149
|
+
|
150
|
+
## Acknowledgements
|
151
|
+
|
152
|
+
- Martin Bjeldbak Madsen (@martinbjeldbak), Bill Kranec (@wkranec) - original [finance](https://github.com/Edward-Intelligence/finance) gem maintainers.
|
153
|
+
- Yanhui Fan (@felixfan) - maintainer of [FinCal](https://github.com/felixfan/FinCal) library.
|
100
154
|
|
101
155
|
## License
|
102
156
|
|
data/lib/finrb/amortization.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
4
|
-
require_relative
|
5
|
-
require_relative
|
3
|
+
require_relative 'cashflows'
|
4
|
+
require_relative 'decimal'
|
5
|
+
require_relative 'transaction'
|
6
6
|
|
7
7
|
module Finrb
|
8
8
|
# the Amortization class provides an interface for working with loan amortizations.
|
@@ -21,22 +21,42 @@ module Finrb
|
|
21
21
|
# extra_payments = 250000.amortize(rate){ |period| period.payment - 150 }
|
22
22
|
# @api public
|
23
23
|
class Amortization
|
24
|
-
# @return [DecNum] the balance of the loan at the end of the amortization period (usually zero)
|
24
|
+
# @return [Flt::DecNum] the balance of the loan at the end of the amortization period (usually zero)
|
25
25
|
# @api public
|
26
26
|
attr_reader :balance
|
27
|
-
# @return [DecNum] the required monthly payment. For loans with more than one rate, returns nil
|
27
|
+
# @return [Flt::DecNum] the required monthly payment. For loans with more than one rate, returns nil
|
28
28
|
# @api public
|
29
29
|
attr_reader :payment
|
30
|
-
# @return [DecNum] the principal amount of the loan
|
30
|
+
# @return [Flt::DecNum] the principal amount of the loan
|
31
31
|
# @api public
|
32
32
|
attr_reader :principal
|
33
33
|
# @return [Array] the interest rates used for calculating the amortization
|
34
34
|
# @api public
|
35
35
|
attr_reader :rates
|
36
36
|
|
37
|
+
# @return [Flt::DecNum] the periodic payment due on a loan
|
38
|
+
# @param [Flt::DecNum] principal the initial amount of the loan or investment
|
39
|
+
# @param [Rate] rate the applicable interest rate (per period)
|
40
|
+
# @param [Integer] periods the number of periods needed for repayment
|
41
|
+
# @note in most cases, you will probably want to use rate.monthly when calling this function outside of an Amortization instance.
|
42
|
+
# @example
|
43
|
+
# rate = Rate.new(0.0375, :apr, :duration => (30 * 12))
|
44
|
+
# rate.duration #=> 360
|
45
|
+
# Amortization.payment(200000, rate.monthly, rate.duration) #=> Flt::DecNum('-926.23')
|
46
|
+
# @see https://en.wikipedia.org/wiki/Amortization_calculator
|
47
|
+
# @api public
|
48
|
+
def self.payment(principal, rate, periods)
|
49
|
+
if rate.zero?
|
50
|
+
# simplified formula to avoid division-by-zero when interest rate is zero
|
51
|
+
-(principal / periods).round(2)
|
52
|
+
else
|
53
|
+
-(principal * (rate + (rate / (((rate + 1)**periods) - 1)))).round(2)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
37
57
|
# create a new Amortization instance
|
38
58
|
# @return [Amortization]
|
39
|
-
# @param [DecNum] principal the initial amount of the loan or investment
|
59
|
+
# @param [Flt::DecNum] principal the initial amount of the loan or investment
|
40
60
|
# @param [Rate] rates the applicable interest rates
|
41
61
|
# @param [Proc] block
|
42
62
|
# @api public
|
@@ -54,7 +74,7 @@ module Finrb
|
|
54
74
|
|
55
75
|
# compare two Amortization instances
|
56
76
|
# @return [Numeric] -1, 0, or +1
|
57
|
-
# @param [Amortization]
|
77
|
+
# @param [Amortization] other
|
58
78
|
# @api public
|
59
79
|
def ==(other)
|
60
80
|
(principal == other.principal) && (rates == other.rates) && (payments == other.payments)
|
@@ -64,7 +84,7 @@ module Finrb
|
|
64
84
|
# @example
|
65
85
|
# rate = Rate.new(0.0375, :apr, :duration => (30 * 12))
|
66
86
|
# amt = 300000.amortize(rate){ |payment| payment.amount-100}
|
67
|
-
# amt.additional_payments #=> [DecNum('-100.00'), DecNum('-100.00'), ... ]
|
87
|
+
# amt.additional_payments #=> [Flt::DecNum('-100.00'), Flt::DecNum('-100.00'), ... ]
|
68
88
|
# @api public
|
69
89
|
def additional_payments
|
70
90
|
@transactions.filter_map { |trans| trans.difference if trans.payment? }
|
@@ -115,7 +135,7 @@ module Finrb
|
|
115
135
|
end
|
116
136
|
|
117
137
|
# Add any remaining balance due to rounding error to the last payment.
|
118
|
-
|
138
|
+
if @balance.nonzero?
|
119
139
|
@transactions.reverse.find(&:payment?).amount -= @balance
|
120
140
|
@balance = 0
|
121
141
|
end
|
@@ -148,41 +168,21 @@ module Finrb
|
|
148
168
|
# @example find the total cost of interest for a loan
|
149
169
|
# rate = Rate.new(0.0375, :apr, :duration => (30 * 12))
|
150
170
|
# amt = 300000.amortize(rate)
|
151
|
-
# amt.interest.sum #=> DecNum('200163.94')
|
171
|
+
# amt.interest.sum #=> Flt::DecNum('200163.94')
|
152
172
|
# @example find the total interest charges in the first six months
|
153
173
|
# rate = Rate.new(0.0375, :apr, :duration => (30 * 12))
|
154
174
|
# amt = 300000.amortize(rate)
|
155
|
-
# amt.interest[0,6].sum #=> DecNum('5603.74')
|
175
|
+
# amt.interest[0,6].sum #=> Flt::DecNum('5603.74')
|
156
176
|
# @api public
|
157
177
|
def interest
|
158
178
|
@transactions.filter_map { |trans| trans.amount if trans.interest? }
|
159
179
|
end
|
160
180
|
|
161
|
-
# @return [DecNum] the periodic payment due on a loan
|
162
|
-
# @param [DecNum] principal the initial amount of the loan or investment
|
163
|
-
# @param [Rate] rate the applicable interest rate (per period)
|
164
|
-
# @param [Integer] periods the number of periods needed for repayment
|
165
|
-
# @note in most cases, you will probably want to use rate.monthly when calling this function outside of an Amortization instance.
|
166
|
-
# @example
|
167
|
-
# rate = Rate.new(0.0375, :apr, :duration => (30 * 12))
|
168
|
-
# rate.duration #=> 360
|
169
|
-
# Amortization.payment(200000, rate.monthly, rate.duration) #=> DecNum('-926.23')
|
170
|
-
# @see https://en.wikipedia.org/wiki/Amortization_calculator
|
171
|
-
# @api public
|
172
|
-
def self.payment(principal, rate, periods)
|
173
|
-
if rate.zero?
|
174
|
-
# simplified formula to avoid division-by-zero when interest rate is zero
|
175
|
-
-(principal / periods).round(2)
|
176
|
-
else
|
177
|
-
-(principal * (rate + (rate / (((1 + rate)**periods) - 1)))).round(2)
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
181
|
# @return [Array] the amount of the payment in each period
|
182
182
|
# @example find the total payments for a loan
|
183
183
|
# rate = Rate.new(0.0375, :apr, :duration => (30 * 12))
|
184
184
|
# amt = 300000.amortize(rate)
|
185
|
-
# amt.payments.sum #=> DecNum('-500163.94')
|
185
|
+
# amt.payments.sum #=> Flt::DecNum('-500163.94')
|
186
186
|
# @api public
|
187
187
|
def payments
|
188
188
|
@transactions.filter_map { |trans| trans.amount if trans.payment? }
|
data/lib/finrb/cashflows.rb
CHANGED
@@ -1,21 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
4
|
-
require_relative
|
3
|
+
require_relative 'config'
|
4
|
+
require_relative 'decimal'
|
5
|
+
require_relative 'rates'
|
5
6
|
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
include Newton
|
7
|
+
require 'bigdecimal'
|
8
|
+
require 'bigdecimal/newton'
|
9
|
+
require 'business_time'
|
10
10
|
|
11
11
|
module Finrb
|
12
|
+
include Newton
|
13
|
+
|
12
14
|
# Provides methods for working with cash flows (collections of transactions)
|
13
15
|
# @api public
|
14
16
|
module Cashflow
|
15
17
|
# Base class for working with Newton's Method.
|
16
18
|
# @api private
|
17
19
|
class Function
|
18
|
-
values = { eps: Finrb.config.eps, one:
|
20
|
+
values = { eps: Finrb.config.eps, one: '1.0', two: '2.0', ten: '10.0', zero: '0.0' }
|
19
21
|
|
20
22
|
values.each do |key, value|
|
21
23
|
define_method key do
|
@@ -29,7 +31,7 @@ module Finrb
|
|
29
31
|
end
|
30
32
|
|
31
33
|
def values(x)
|
32
|
-
value = @transactions.
|
34
|
+
value = @transactions.public_send(@function, Flt::DecNum.new(x[0].to_s))
|
33
35
|
begin
|
34
36
|
[BigDecimal(value.to_s)]
|
35
37
|
rescue ArgumentError
|
@@ -39,8 +41,8 @@ module Finrb
|
|
39
41
|
end
|
40
42
|
|
41
43
|
# calculate the internal rate of return for a sequence of cash flows
|
42
|
-
# @return [DecNum] the internal rate of return
|
43
|
-
# @param [Numeric] Initial guess rate, Defaults to 1.0
|
44
|
+
# @return [Flt::DecNum] the internal rate of return
|
45
|
+
# @param [Numeric] guess Initial guess rate, Defaults to 1.0
|
44
46
|
# @example
|
45
47
|
# [-4000,1200,1410,1875,1050].irr #=> 0.143
|
46
48
|
# @see https://en.wikipedia.org/wiki/Internal_rate_of_return
|
@@ -48,7 +50,7 @@ module Finrb
|
|
48
50
|
def irr(guess = nil)
|
49
51
|
# Make sure we have a valid sequence of cash flows.
|
50
52
|
positives, negatives = partition { |i| i >= 0 }
|
51
|
-
raise(ArgumentError,
|
53
|
+
raise(ArgumentError, 'Calculation does not converge.') if positives.empty? || negatives.empty?
|
52
54
|
|
53
55
|
func = Function.new(self, :npv)
|
54
56
|
rate = [valid(guess)]
|
@@ -57,13 +59,17 @@ module Finrb
|
|
57
59
|
end
|
58
60
|
|
59
61
|
def method_missing(name, *args, &block)
|
60
|
-
return sum if name.to_s ==
|
62
|
+
return sum if name.to_s == 'sum'
|
61
63
|
|
62
64
|
super
|
63
65
|
end
|
64
66
|
|
67
|
+
def respond_to_missing?(name, include_private = false)
|
68
|
+
name.to_s == 'sum' || super
|
69
|
+
end
|
70
|
+
|
65
71
|
# calculate the net present value of a sequence of cash flows
|
66
|
-
# @return [DecNum] the net present value
|
72
|
+
# @return [Flt::DecNum] the net present value
|
67
73
|
# @param [Numeric] rate the discount rate to be applied
|
68
74
|
# @example
|
69
75
|
# [-100.0, 60, 60, 60].npv(0.1) #=> 49.211
|
@@ -75,7 +81,7 @@ module Finrb
|
|
75
81
|
rate = Flt::DecNum.new(rate.to_s)
|
76
82
|
total = Flt::DecNum.new(0.to_s)
|
77
83
|
cashflows.each_with_index do |cashflow, index|
|
78
|
-
total += cashflow / ((
|
84
|
+
total += cashflow / ((rate + 1)**index)
|
79
85
|
end
|
80
86
|
|
81
87
|
total
|
@@ -97,7 +103,7 @@ module Finrb
|
|
97
103
|
if positives.empty? || negatives.empty?
|
98
104
|
raise(
|
99
105
|
ArgumentError,
|
100
|
-
|
106
|
+
'Calculation does not converge. Cashflow needs to have a least one positive and one negative value.'
|
101
107
|
)
|
102
108
|
end
|
103
109
|
|
@@ -108,7 +114,7 @@ module Finrb
|
|
108
114
|
end
|
109
115
|
|
110
116
|
# calculate the net present value of a sequence of cash flows
|
111
|
-
# @return [DecNum]
|
117
|
+
# @return [Flt::DecNum]
|
112
118
|
# @example
|
113
119
|
# @transactions = []
|
114
120
|
# @transactions << Transaction.new(-1000, :date => Time.new(1985,01,01))
|
@@ -120,48 +126,47 @@ module Finrb
|
|
120
126
|
rate = Flt::DecNum.new(rate.to_s)
|
121
127
|
|
122
128
|
sum do |t|
|
123
|
-
t.amount / ((
|
129
|
+
t.amount / ((rate + 1)**(date_diff(start, t.date) / days_in_period))
|
124
130
|
end
|
125
131
|
end
|
126
132
|
|
127
133
|
private
|
128
|
-
def date_diff(from, to)
|
129
|
-
if Finrb.config.business_days
|
130
|
-
from.to_date.business_days_until(to)
|
131
|
-
else
|
132
|
-
to - from
|
133
|
-
end
|
134
|
-
end
|
135
134
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
end
|
135
|
+
def date_diff(from, to)
|
136
|
+
if Finrb.config.business_days
|
137
|
+
from.to_date.business_days_until(to)
|
138
|
+
else
|
139
|
+
to - from
|
142
140
|
end
|
141
|
+
end
|
143
142
|
|
144
|
-
|
145
|
-
|
143
|
+
def days_in_period
|
144
|
+
if Finrb.config.periodic_compound && Finrb.config.business_days
|
145
|
+
start.to_date.business_days_until(stop).to_f
|
146
|
+
else
|
147
|
+
Flt::DecNum.new(365.days.to_s)
|
146
148
|
end
|
149
|
+
end
|
147
150
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
+
def start
|
152
|
+
@start ||= self[0].date
|
153
|
+
end
|
151
154
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
raise(ArgumentError, "Invalid Guess. Default guess should be a [Numeric] value.")
|
156
|
-
end
|
155
|
+
def stop
|
156
|
+
@stop ||= self[-1].date.to_date
|
157
|
+
end
|
157
158
|
|
158
|
-
|
159
|
-
|
160
|
-
|
159
|
+
def valid(guess)
|
160
|
+
if guess.nil?
|
161
|
+
raise(ArgumentError, 'Invalid Guess. Default guess should be a [Numeric] value.') unless Finrb.config.guess.is_a?(Numeric)
|
161
162
|
|
162
|
-
|
163
|
-
|
164
|
-
|
163
|
+
Finrb.config.guess
|
164
|
+
else
|
165
|
+
raise(ArgumentError, 'Invalid Guess. Use a [Numeric] value.') unless guess.is_a?(Numeric)
|
166
|
+
|
167
|
+
guess
|
168
|
+
end.to_f
|
169
|
+
end
|
165
170
|
end
|
166
171
|
end
|
167
172
|
|
data/lib/finrb/config.rb
CHANGED
@@ -3,9 +3,9 @@
|
|
3
3
|
module Finrb
|
4
4
|
include ActiveSupport::Configurable
|
5
5
|
|
6
|
-
default_values = { eps:
|
6
|
+
default_values = { eps: '1.0e-16', guess: 1.0, business_days: false, periodic_compound: false }
|
7
7
|
|
8
8
|
default_values.each do |key, value|
|
9
|
-
config.
|
9
|
+
config.__send__("#{key.to_sym}=", value)
|
10
10
|
end
|
11
11
|
end
|
data/lib/finrb/decimal.rb
CHANGED
@@ -1,23 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
include Flt
|
3
|
+
require 'flt'
|
4
|
+
require 'rubygems'
|
6
5
|
|
7
|
-
DecNum.context.define_conversion_from(BigDecimal) do |x, _context|
|
8
|
-
DecNum(x.to_s)
|
6
|
+
Flt::DecNum.context.define_conversion_from(BigDecimal) do |x, _context|
|
7
|
+
Flt::DecNum(x.to_s)
|
9
8
|
end
|
10
9
|
|
11
|
-
DecNum.context.define_conversion_to(BigDecimal) do |x|
|
10
|
+
Flt::DecNum.context.define_conversion_to(BigDecimal) do |x|
|
12
11
|
BigDecimal(x.to_s)
|
13
12
|
end
|
14
13
|
|
15
14
|
class Numeric
|
16
|
-
def
|
17
|
-
if instance_of?(DecNum)
|
15
|
+
def to_dec
|
16
|
+
if instance_of?(Flt::DecNum)
|
18
17
|
self
|
19
18
|
else
|
20
|
-
DecNum(to_s)
|
19
|
+
Flt::DecNum(to_s)
|
21
20
|
end
|
22
21
|
end
|
23
22
|
end
|