rvgp 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.rubocop.yml +23 -0
- data/LICENSE +504 -0
- data/README.md +223 -0
- data/Rakefile +32 -0
- data/bin/rvgp +8 -0
- data/lib/rvgp/application/config.rb +159 -0
- data/lib/rvgp/application/descendant_registry.rb +122 -0
- data/lib/rvgp/application/status_output.rb +139 -0
- data/lib/rvgp/application.rb +170 -0
- data/lib/rvgp/base/command.rb +457 -0
- data/lib/rvgp/base/grid.rb +531 -0
- data/lib/rvgp/base/reader.rb +29 -0
- data/lib/rvgp/base/reconciler.rb +434 -0
- data/lib/rvgp/base/validation.rb +261 -0
- data/lib/rvgp/commands/cashflow.rb +160 -0
- data/lib/rvgp/commands/grid.rb +70 -0
- data/lib/rvgp/commands/ireconcile.rb +95 -0
- data/lib/rvgp/commands/new_project.rb +296 -0
- data/lib/rvgp/commands/plot.rb +41 -0
- data/lib/rvgp/commands/publish_gsheets.rb +83 -0
- data/lib/rvgp/commands/reconcile.rb +58 -0
- data/lib/rvgp/commands/rotate_year.rb +202 -0
- data/lib/rvgp/commands/validate_journal.rb +59 -0
- data/lib/rvgp/commands/validate_system.rb +44 -0
- data/lib/rvgp/commands.rb +160 -0
- data/lib/rvgp/dashboard.rb +252 -0
- data/lib/rvgp/fakers/fake_feed.rb +245 -0
- data/lib/rvgp/fakers/fake_journal.rb +57 -0
- data/lib/rvgp/fakers/fake_reconciler.rb +88 -0
- data/lib/rvgp/fakers/faker_helpers.rb +25 -0
- data/lib/rvgp/gem.rb +80 -0
- data/lib/rvgp/journal/commodity.rb +453 -0
- data/lib/rvgp/journal/complex_commodity.rb +214 -0
- data/lib/rvgp/journal/currency.rb +101 -0
- data/lib/rvgp/journal/journal.rb +141 -0
- data/lib/rvgp/journal/posting.rb +156 -0
- data/lib/rvgp/journal/pricer.rb +267 -0
- data/lib/rvgp/journal.rb +24 -0
- data/lib/rvgp/plot/gnuplot.rb +478 -0
- data/lib/rvgp/plot/google-drive/output_csv.rb +44 -0
- data/lib/rvgp/plot/google-drive/output_google_sheets.rb +434 -0
- data/lib/rvgp/plot/google-drive/sheet.rb +67 -0
- data/lib/rvgp/plot.rb +293 -0
- data/lib/rvgp/pta/hledger.rb +237 -0
- data/lib/rvgp/pta/ledger.rb +308 -0
- data/lib/rvgp/pta.rb +311 -0
- data/lib/rvgp/reconcilers/csv_reconciler.rb +424 -0
- data/lib/rvgp/reconcilers/journal_reconciler.rb +41 -0
- data/lib/rvgp/reconcilers/shorthand/finance_gem_hacks.rb +48 -0
- data/lib/rvgp/reconcilers/shorthand/international_atm.rb +152 -0
- data/lib/rvgp/reconcilers/shorthand/investment.rb +144 -0
- data/lib/rvgp/reconcilers/shorthand/mortgage.rb +195 -0
- data/lib/rvgp/utilities/grid_query.rb +190 -0
- data/lib/rvgp/utilities/yaml.rb +131 -0
- data/lib/rvgp/utilities.rb +44 -0
- data/lib/rvgp/validations/balance_validation.rb +68 -0
- data/lib/rvgp/validations/duplicate_tags_validation.rb +48 -0
- data/lib/rvgp/validations/uncategorized_validation.rb +15 -0
- data/lib/rvgp.rb +66 -0
- data/resources/README.MD/2022-cashflow-google.png +0 -0
- data/resources/README.MD/2022-cashflow.png +0 -0
- data/resources/README.MD/all-wealth-growth-google.png +0 -0
- data/resources/README.MD/all-wealth-growth.png +0 -0
- data/resources/gnuplot/default.yml +80 -0
- data/resources/i18n/en.yml +192 -0
- data/resources/iso-4217-currencies.json +171 -0
- data/resources/skel/Rakefile +5 -0
- data/resources/skel/app/grids/cashflow_grid.rb +27 -0
- data/resources/skel/app/grids/monthly_income_and_expenses_grid.rb +25 -0
- data/resources/skel/app/grids/wealth_growth_grid.rb +35 -0
- data/resources/skel/app/plots/cashflow.yml +33 -0
- data/resources/skel/app/plots/monthly-income-and-expenses.yml +17 -0
- data/resources/skel/app/plots/wealth-growth.yml +20 -0
- data/resources/skel/config/csv-format-acme-checking.yml +9 -0
- data/resources/skel/config/google-secrets.yml +5 -0
- data/resources/skel/config/rvgp.yml +0 -0
- data/resources/skel/journals/prices.db +0 -0
- data/rvgp.gemspec +6 -0
- data/test/assets/ledger_total_monthly_liabilities_with_empty.xml +383 -0
- data/test/assets/ledger_total_monthly_liabilities_with_empty2.xml +428 -0
- data/test/test_command_base.rb +61 -0
- data/test/test_commodity.rb +270 -0
- data/test/test_csv_reconciler.rb +60 -0
- data/test/test_currency.rb +24 -0
- data/test/test_fake_feed.rb +228 -0
- data/test/test_fake_journal.rb +98 -0
- data/test/test_fake_reconciler.rb +60 -0
- data/test/test_journal_parse.rb +545 -0
- data/test/test_ledger.rb +102 -0
- data/test/test_plot.rb +133 -0
- data/test/test_posting.rb +50 -0
- data/test/test_pricer.rb +139 -0
- data/test/test_pta_adapter.rb +575 -0
- data/test/test_utilities.rb +45 -0
- metadata +268 -0
data/test/test_plot.rb
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'csv'
|
5
|
+
require 'minitest/autorun'
|
6
|
+
|
7
|
+
require_relative '../lib/rvgp'
|
8
|
+
require_relative '../lib/rvgp/plot'
|
9
|
+
|
10
|
+
# Tests for RVGP::Plot
|
11
|
+
class TestPlot < Minitest::Test
|
12
|
+
YEAR_ONLY_CORPUS = [
|
13
|
+
'/path/to/ledger/2018-wealth-growth.csv',
|
14
|
+
'/path/to/ledger/2019-wealth-growth.csv',
|
15
|
+
'/path/to/ledger/2020-wealth-growth.csv',
|
16
|
+
'/path/to/ledger/2021-wealth-growth.csv',
|
17
|
+
'/path/to/ledger/2022-wealth-growth.csv',
|
18
|
+
# These are meant to be ignored:
|
19
|
+
'/path/to/ledger/2018-profit-and-loss.csv',
|
20
|
+
'/path/to/ledger/2019-profit-and-loss.csv',
|
21
|
+
'/path/to/ledger/2020-profit-and-loss.csv',
|
22
|
+
'/path/to/ledger/2021-profit-and-loss.csv'
|
23
|
+
].freeze
|
24
|
+
|
25
|
+
YEAR_AND_INTENTION_CORPUS = [
|
26
|
+
'build/grids/2018-cashflow-burgershop.csv',
|
27
|
+
'build/grids/2018-cashflow-multiplex.csv',
|
28
|
+
'build/grids/2018-cashflow-ignored.csv',
|
29
|
+
'build/grids/2018-cashflow-personal.csv',
|
30
|
+
# NOTE: We sold the frozenbananastand in 2018, so, there's no 2019 grid
|
31
|
+
'build/grids/2018-cashflow-frozenbananastand.csv',
|
32
|
+
'build/grids/2019-cashflow-burgershop.csv',
|
33
|
+
'build/grids/2019-cashflow-multiplex.csv',
|
34
|
+
'build/grids/2019-cashflow-ignored.csv',
|
35
|
+
'build/grids/2019-cashflow-personal.csv',
|
36
|
+
# These are meant to be ignored:
|
37
|
+
'/path/to/ledger/2018-profit-and-loss.csv',
|
38
|
+
'/path/to/ledger/2019-profit-and-loss.csv',
|
39
|
+
'/path/to/ledger/2020-profit-and-loss.csv',
|
40
|
+
'/path/to/ledger/2021-profit-and-loss.csv'
|
41
|
+
].freeze
|
42
|
+
|
43
|
+
def test_globber
|
44
|
+
matches = RVGP::Plot.glob_variants '%{year}-wealth-growth.csv', YEAR_ONLY_CORPUS # rubocop:disable Style/FormatStringToken
|
45
|
+
|
46
|
+
assert_equal 5, matches.length
|
47
|
+
|
48
|
+
0.upto(4).map do |i|
|
49
|
+
year = 2018 + i
|
50
|
+
assert_equal [format('/path/to/ledger/%d-wealth-growth.csv', year)], matches[i][:files]
|
51
|
+
assert_equal format('%d-wealth-growth', year), matches[i][:name]
|
52
|
+
assert_equal({ year: year.to_s }, matches[i][:pairs])
|
53
|
+
end
|
54
|
+
|
55
|
+
matches = RVGP::Plot.glob_variants '%{year}-cashflow-%{intention}.csv', YEAR_AND_INTENTION_CORPUS # rubocop:disable Style/FormatStringToken
|
56
|
+
|
57
|
+
assert_equal 9, matches.length
|
58
|
+
|
59
|
+
assert_equal ['build/grids/2018-cashflow-burgershop.csv'], matches[0][:files]
|
60
|
+
assert_equal '2018-cashflow-burgershop', matches[0][:name]
|
61
|
+
assert_equal({ year: '2018', intention: 'burgershop' }, matches[0][:pairs])
|
62
|
+
|
63
|
+
assert_equal ['build/grids/2018-cashflow-multiplex.csv'], matches[1][:files]
|
64
|
+
assert_equal '2018-cashflow-multiplex', matches[1][:name]
|
65
|
+
assert_equal({ year: '2018', intention: 'multiplex' }, matches[1][:pairs])
|
66
|
+
|
67
|
+
assert_equal ['build/grids/2018-cashflow-ignored.csv'], matches[2][:files]
|
68
|
+
assert_equal '2018-cashflow-ignored', matches[2][:name]
|
69
|
+
assert_equal({ year: '2018', intention: 'ignored' }, matches[2][:pairs])
|
70
|
+
|
71
|
+
assert_equal ['build/grids/2018-cashflow-personal.csv'], matches[3][:files]
|
72
|
+
assert_equal '2018-cashflow-personal', matches[3][:name]
|
73
|
+
assert_equal({ year: '2018', intention: 'personal' }, matches[3][:pairs])
|
74
|
+
|
75
|
+
assert_equal ['build/grids/2018-cashflow-frozenbananastand.csv'], matches[4][:files]
|
76
|
+
assert_equal '2018-cashflow-frozenbananastand', matches[4][:name]
|
77
|
+
assert_equal({ year: '2018', intention: 'frozenbananastand' }, matches[4][:pairs])
|
78
|
+
|
79
|
+
assert_equal ['build/grids/2019-cashflow-burgershop.csv'], matches[5][:files]
|
80
|
+
assert_equal '2019-cashflow-burgershop', matches[5][:name]
|
81
|
+
assert_equal({ year: '2019', intention: 'burgershop' }, matches[5][:pairs])
|
82
|
+
|
83
|
+
assert_equal ['build/grids/2019-cashflow-multiplex.csv'], matches[6][:files]
|
84
|
+
assert_equal '2019-cashflow-multiplex', matches[6][:name]
|
85
|
+
assert_equal({ year: '2019', intention: 'multiplex' }, matches[6][:pairs])
|
86
|
+
|
87
|
+
assert_equal ['build/grids/2019-cashflow-ignored.csv'], matches[7][:files]
|
88
|
+
assert_equal '2019-cashflow-ignored', matches[7][:name]
|
89
|
+
assert_equal({ year: '2019', intention: 'ignored' }, matches[7][:pairs])
|
90
|
+
|
91
|
+
assert_equal ['build/grids/2019-cashflow-personal.csv'], matches[8][:files]
|
92
|
+
assert_equal '2019-cashflow-personal', matches[8][:name]
|
93
|
+
assert_equal({ year: '2019', intention: 'personal' }, matches[8][:pairs])
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_all_year_globber
|
97
|
+
matches = RVGP::Plot.glob_variants '%{year}-wealth-growth.csv', YEAR_ONLY_CORPUS, year: 'all' # rubocop:disable Style/FormatStringToken
|
98
|
+
|
99
|
+
assert_equal 1, matches.length
|
100
|
+
|
101
|
+
assert_equal ['/path/to/ledger/2018-wealth-growth.csv',
|
102
|
+
'/path/to/ledger/2019-wealth-growth.csv',
|
103
|
+
'/path/to/ledger/2020-wealth-growth.csv',
|
104
|
+
'/path/to/ledger/2021-wealth-growth.csv',
|
105
|
+
'/path/to/ledger/2022-wealth-growth.csv'], matches[0][:files]
|
106
|
+
assert_equal 'all-wealth-growth', matches[0][:name]
|
107
|
+
assert_equal({ year: 'all' }, matches[0][:pairs])
|
108
|
+
|
109
|
+
matches = RVGP::Plot.glob_variants '%{year}-cashflow-%{intention}.csv', YEAR_AND_INTENTION_CORPUS, year: 'all' # rubocop:disable Style/FormatStringToken
|
110
|
+
|
111
|
+
assert_equal 5, matches.length
|
112
|
+
|
113
|
+
assert_equal(%w[2018 2019].map { |y| format('build/grids/%s-cashflow-burgershop.csv', y) }, matches[0][:files])
|
114
|
+
assert_equal 'all-cashflow-burgershop', matches[0][:name]
|
115
|
+
assert_equal({ year: 'all', intention: 'burgershop' }, matches[0][:pairs])
|
116
|
+
|
117
|
+
assert_equal(%w[2018 2019].map { |y| format('build/grids/%s-cashflow-multiplex.csv', y) }, matches[1][:files])
|
118
|
+
assert_equal 'all-cashflow-multiplex', matches[1][:name]
|
119
|
+
assert_equal({ year: 'all', intention: 'multiplex' }, matches[1][:pairs])
|
120
|
+
|
121
|
+
assert_equal(%w[2018 2019].map { |y| format('build/grids/%s-cashflow-ignored.csv', y) }, matches[2][:files])
|
122
|
+
assert_equal 'all-cashflow-ignored', matches[2][:name]
|
123
|
+
assert_equal({ year: 'all', intention: 'ignored' }, matches[2][:pairs])
|
124
|
+
|
125
|
+
assert_equal(%w[2018 2019].map { |y| format('build/grids/%s-cashflow-personal.csv', y) }, matches[3][:files])
|
126
|
+
assert_equal 'all-cashflow-personal', matches[3][:name]
|
127
|
+
assert_equal({ year: 'all', intention: 'personal' }, matches[3][:pairs])
|
128
|
+
|
129
|
+
assert_equal ['build/grids/2018-cashflow-frozenbananastand.csv'], matches[4][:files]
|
130
|
+
assert_equal 'all-cashflow-frozenbananastand', matches[4][:name]
|
131
|
+
assert_equal({ year: 'all', intention: 'frozenbananastand' }, matches[4][:pairs])
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'date'
|
5
|
+
require 'minitest/autorun'
|
6
|
+
|
7
|
+
require_relative '../lib/rvgp'
|
8
|
+
require_relative '../lib/rvgp/journal'
|
9
|
+
|
10
|
+
# Tests for RVGP::Journal::Posting
|
11
|
+
class TestPosting < Minitest::Test
|
12
|
+
def test_posting_to_ledger
|
13
|
+
posting = RVGP::Journal::Posting.new(
|
14
|
+
Date.new(2021, 10, 2),
|
15
|
+
'Heroes R Us',
|
16
|
+
tags: ['Vacation: Seattle'.to_tag],
|
17
|
+
transfers: [
|
18
|
+
['Expenses:Comics', { commodity: '$ 5.00'.to_commodity, tags: ['Publisher: Marvel'.to_tag] }],
|
19
|
+
['Expenses:Cards', { commodity: '$ 9.00'.to_commodity, tags: ['Collection: Baseball'.to_tag] }],
|
20
|
+
['Cash']
|
21
|
+
].collect { |args| RVGP::Journal::Posting::Transfer.new(*args) }
|
22
|
+
)
|
23
|
+
|
24
|
+
assert_equal [
|
25
|
+
'2021-10-02 Heroes R Us',
|
26
|
+
' ; Vacation: Seattle',
|
27
|
+
' Expenses:Comics $ 5.00',
|
28
|
+
' ; Publisher: Marvel',
|
29
|
+
' Expenses:Cards $ 9.00',
|
30
|
+
' ; Collection: Baseball',
|
31
|
+
' Cash'
|
32
|
+
].join("\n"), posting.to_ledger
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_posting_with_complex_commodity_to_ledger
|
36
|
+
complex_commodity = RVGP::Journal::ComplexCommodity.from_s(['-1000.0001 VBTLX', '@@', '$ 100000.00'].join(' '))
|
37
|
+
|
38
|
+
posting = RVGP::Journal::Posting.new(
|
39
|
+
'2022-03-28',
|
40
|
+
'VANGUARD TOTAL BOND MARKET INDEX Sell',
|
41
|
+
transfers: [RVGP::Journal::Posting::Transfer.new('Personal:Assets:Vanguard:VBTLX', commodity: complex_commodity),
|
42
|
+
RVGP::Journal::Posting::Transfer.new('Personal:Assets:Vanguard:MoneyMarket')]
|
43
|
+
)
|
44
|
+
|
45
|
+
assert_equal ['2022-03-28 VANGUARD TOTAL BOND MARKET INDEX Sell',
|
46
|
+
' Personal:Assets:Vanguard:VBTLX -1000.0001 VBTLX @@ $ 100000.00',
|
47
|
+
' Personal:Assets:Vanguard:MoneyMarket'].join("\n"),
|
48
|
+
posting.to_ledger
|
49
|
+
end
|
50
|
+
end
|
data/test/test_pricer.rb
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'time'
|
5
|
+
require 'minitest/autorun'
|
6
|
+
|
7
|
+
require_relative '../lib/rvgp'
|
8
|
+
|
9
|
+
# Tests for RVGP::Journal::Pricer
|
10
|
+
class TestPricer < Minitest::Test
|
11
|
+
TEST_PRICES_DB_FORMAT1 = <<~DB_FORMAT1
|
12
|
+
P 2004/06/25 00:00:00 FEQTX $24.00
|
13
|
+
P 2004/06/21 02:18:01 FEQTX $22.49
|
14
|
+
P 2004/06/21 02:18:01 BORL $6.20
|
15
|
+
P 2004/06/21 02:18:02 AAPL $32.91
|
16
|
+
P 2004/06/21 02:18:02 AU $400.00
|
17
|
+
P 2004/06/21 14:15:00 FEQTX $ 22.75
|
18
|
+
P 2004/06/25 01:00:00 BORL $6.20
|
19
|
+
P 2004/06/25 02:00:00 AAPL $32.91
|
20
|
+
P 2004/06/25 03:18:02 AU $400.00
|
21
|
+
DB_FORMAT1
|
22
|
+
|
23
|
+
TEST_PRICES_DB_FORMAT2 = <<~DB_FORMAT2
|
24
|
+
P 2020-01-01 USD 0.893179 EUR
|
25
|
+
P 2020-02-01 EUR 1.109275 USD
|
26
|
+
P 2020-03-01 USD 0.907082 EUR
|
27
|
+
DB_FORMAT2
|
28
|
+
|
29
|
+
TEST_PRICES_LARGE_ASSETS = <<~LARGE_ASSETS
|
30
|
+
P 2018/01/01 FLORIDAHOME $500,000.00
|
31
|
+
P 2018/01/01 CORVETTE $50,000.00
|
32
|
+
LARGE_ASSETS
|
33
|
+
|
34
|
+
def test_price_format1
|
35
|
+
p = RVGP::Journal::Pricer.new TEST_PRICES_DB_FORMAT1
|
36
|
+
|
37
|
+
assert_raises(RVGP::Journal::Pricer::NoPriceError) { price_on p, '1900-01-01', 'FEQTX', 'USD' }
|
38
|
+
assert_raises(RVGP::Journal::Pricer::NoPriceError) { price_on p, '2004-06-20', 'FEQTX', '$' }
|
39
|
+
assert_raises(RVGP::Journal::Pricer::NoPriceError) { price_on p, '2004-06-21', 'FEQTX', 'USD' }
|
40
|
+
|
41
|
+
assert_equal '$ 22.49', price_on(p, '2004-06-21 12:00:00', 'FEQTX', '$')
|
42
|
+
assert_equal '$ 22.49', price_on(p, '2004-06-21 14:14:59', 'FEQTX', 'USD')
|
43
|
+
assert_equal '$ 22.75', price_on(p, '2004-06-21 14:15:00', 'FEQTX', '$')
|
44
|
+
assert_equal '$ 22.75', price_on(p, '2004-06-21 14:15:01', 'FEQTX', 'USD')
|
45
|
+
assert_equal '$ 22.75', price_on(p, '2004-06-22', 'FEQTX', '$')
|
46
|
+
assert_equal '$ 24.00', price_on(p, '2004-06-25', 'FEQTX', 'USD')
|
47
|
+
assert_equal '$ 24.00', price_on(p, '2300-01-01', 'FEQTX', '$')
|
48
|
+
|
49
|
+
# This is the same set of tests as above, but ,inverted:
|
50
|
+
# Probably this doesn't make much sense in production, but, we use it with
|
51
|
+
# fiat currencies later:
|
52
|
+
assert_raises(RVGP::Journal::Pricer::NoPriceError) { price_on p, '1900-01-01', 'USD', 'FEQTX' }
|
53
|
+
assert_raises(RVGP::Journal::Pricer::NoPriceError) { price_on p, '2004-06-20', '$', 'FEQTX' }
|
54
|
+
assert_raises(RVGP::Journal::Pricer::NoPriceError) { price_on p, '2004-06-21', 'USD', 'FEQTX' }
|
55
|
+
|
56
|
+
assert_equal '0.0444642063139173 FEQTX', price_on(p, '2004-06-21 12:00:00', 'USD', 'FEQTX')
|
57
|
+
assert_equal '0.0444642063139173 FEQTX', price_on(p, '2004-06-21 14:14:59', '$', 'FEQTX')
|
58
|
+
assert_equal '0.04395604395604396 FEQTX', price_on(p, '2004-06-21 14:15:00', 'USD', 'FEQTX')
|
59
|
+
assert_equal '0.04395604395604396 FEQTX', price_on(p, '2004-06-21 14:15:01', '$', 'FEQTX')
|
60
|
+
assert_equal '0.04395604395604396 FEQTX', price_on(p, '2004-06-22', 'USD', 'FEQTX')
|
61
|
+
assert_equal '0.04166666666666667 FEQTX', price_on(p, '2004-06-25', '$', 'FEQTX')
|
62
|
+
assert_equal '0.04166666666666667 FEQTX', price_on(p, '2300-01-01', 'USD', 'FEQTX')
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_price_format2
|
66
|
+
p = RVGP::Journal::Pricer.new TEST_PRICES_DB_FORMAT2
|
67
|
+
|
68
|
+
assert_raises(RVGP::Journal::Pricer::NoPriceError) { price_on p, '2019-12-31', 'EUR', 'USD' }
|
69
|
+
assert_raises(RVGP::Journal::Pricer::NoPriceError) { price_on p, '2019-12-31', 'USD', 'EUR' }
|
70
|
+
|
71
|
+
assert_equal '1.11959640788688494 USD', price_on(p, '2020-01-01', 'EUR', 'USD')
|
72
|
+
assert_equal '0.893179 EUR', price_on(p, '2020-01-01', 'USD', 'EUR')
|
73
|
+
|
74
|
+
assert_equal '1.11959640788688494 USD', price_on(p, '2020-01-15', 'EUR', 'USD')
|
75
|
+
assert_equal '0.893179 EUR', price_on(p, '2020-01-15', 'USD', 'EUR')
|
76
|
+
|
77
|
+
assert_equal '1.109275 USD', price_on(p, '2020-02-01', 'EUR', 'USD')
|
78
|
+
assert_equal '0.90148971174866467 EUR', price_on(p, '2020-02-01', 'USD', 'EUR')
|
79
|
+
|
80
|
+
assert_equal '1.10243616343395636 USD', price_on(p, '2020-03-01', 'EUR', 'USD')
|
81
|
+
assert_equal '0.907082 EUR', price_on(p, '2020-03-01', 'USD', 'EUR')
|
82
|
+
|
83
|
+
assert_equal '1.10243616343395636 USD', price_on(p, '2020-03-01', 'EUR', 'USD')
|
84
|
+
assert_equal '0.907082 EUR', price_on(p, '2020-03-15', 'USD', 'EUR')
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_price_format3
|
88
|
+
p = RVGP::Journal::Pricer.new TEST_PRICES_LARGE_ASSETS
|
89
|
+
|
90
|
+
# Make sure the database is parsed ok:
|
91
|
+
assert_equal '$ 500000.00', price_on(p, '2020-01-01 12:00:00', 'FLORIDAHOME', '$')
|
92
|
+
assert_equal '$ 50000.00', price_on(p, '2020-01-01 12:00:00', 'CORVETTE', '$')
|
93
|
+
|
94
|
+
# I don't think anyone will ever do this, but, why not:
|
95
|
+
assert_equal '0.000002 FLORIDAHOME', price_on(p, '2020-01-01 12:00:00', '$', 'FLORIDAHOME')
|
96
|
+
assert_equal '0.00002 CORVETTE', price_on(p, '2020-01-01 12:00:00', '$', 'CORVETTE')
|
97
|
+
|
98
|
+
# And now get fancy with the conversions:
|
99
|
+
at = Date.new(2020, 1, 1).to_time
|
100
|
+
|
101
|
+
dollar = '$ 1.00'.to_commodity
|
102
|
+
home = '1 FLORIDAHOME'.to_commodity
|
103
|
+
minus_home = '-1 FLORIDAHOME'.to_commodity
|
104
|
+
minus_dollar = '$ -1.00'.to_commodity
|
105
|
+
|
106
|
+
assert_equal '$ 500000.00', p.convert(at, home, '$').to_s
|
107
|
+
assert_equal '$ -500000.00', p.convert(at, minus_home, '$').to_s
|
108
|
+
|
109
|
+
assert_equal '0.000002 FLORIDAHOME', p.convert(at, dollar, 'FLORIDAHOME').to_s
|
110
|
+
assert_equal '-0.000002 FLORIDAHOME', p.convert(at, minus_dollar, 'FLORIDAHOME').to_s
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_price_insert
|
114
|
+
pricer = RVGP::Journal::Pricer.new
|
115
|
+
pricer.add(Date.new(2020, 8, 1), 'ABC', '$ 0.80'.to_commodity)
|
116
|
+
pricer.add(Date.new(2020, 1, 1), 'ABC', '0.10 USD'.to_commodity)
|
117
|
+
pricer.add(Date.new(2020, 2, 1), 'ABC', '$0.20'.to_commodity)
|
118
|
+
pricer.add(Date.new(2020, 3, 1), 'ABC', '0.30 USD'.to_commodity)
|
119
|
+
pricer.add(Date.new(2020, 4, 1), 'ABC', '$0.40'.to_commodity)
|
120
|
+
pricer.add(Date.new(2020, 6, 1), 'ABC', '0.60 USD'.to_commodity)
|
121
|
+
pricer.add(Date.new(2020, 7, 1), 'ABC', '$0.70'.to_commodity)
|
122
|
+
pricer.add(Date.new(2020, 5, 1), 'ABC', '0.50 USD'.to_commodity)
|
123
|
+
|
124
|
+
assert_equal '0.10 USD', price_on(pricer, '2020-01-15', 'ABC', '$')
|
125
|
+
assert_equal '$ 0.20', price_on(pricer, '2020-02-15', 'ABC', '$')
|
126
|
+
assert_equal '0.30 USD', price_on(pricer, '2020-03-15', 'ABC', '$')
|
127
|
+
assert_equal '$ 0.40', price_on(pricer, '2020-04-15', 'ABC', '$')
|
128
|
+
assert_equal '0.50 USD', price_on(pricer, '2020-05-15', 'ABC', '$')
|
129
|
+
assert_equal '0.60 USD', price_on(pricer, '2020-06-15', 'ABC', '$')
|
130
|
+
assert_equal '$ 0.70', price_on(pricer, '2020-07-15', 'ABC', '$')
|
131
|
+
assert_equal '$ 0.80', price_on(pricer, '2020-08-15', 'ABC', '$')
|
132
|
+
end
|
133
|
+
|
134
|
+
private
|
135
|
+
|
136
|
+
def price_on(pricer, date_str, code_from, code_to)
|
137
|
+
pricer.price(Time.parse(date_str), code_from, code_to).to_s
|
138
|
+
end
|
139
|
+
end
|