finrb 0.1.0 → 0.1.2
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 +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
|
[](https://github.com/ncs1/finrb/actions/workflows/codeql.yml)
|
5
5
|
[](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
|