eodhd 0.19.5

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.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG +195 -0
  3. data/Gemfile +3 -0
  4. data/README.md +160 -0
  5. data/Rakefile +28 -0
  6. data/eodhd.gemspec +52 -0
  7. data/lib/Eodhd/Client.rb +143 -0
  8. data/lib/Eodhd/DefaultLogger.rb +30 -0
  9. data/lib/Eodhd/EodBulkLastDay.rb +56 -0
  10. data/lib/Eodhd/EodData.rb +56 -0
  11. data/lib/Eodhd/Error.rb +16 -0
  12. data/lib/Eodhd/Exchange.rb +50 -0
  13. data/lib/Eodhd/ExchangeSymbol.rb +50 -0
  14. data/lib/Eodhd/Fundamentals/AnalystRatings.rb +29 -0
  15. data/lib/Eodhd/Fundamentals/ESGScores.rb +37 -0
  16. data/lib/Eodhd/Fundamentals/Earnings/AnnualEntry.rb +21 -0
  17. data/lib/Eodhd/Fundamentals/Earnings/HistoryEntry.rb +33 -0
  18. data/lib/Eodhd/Fundamentals/Earnings/TrendEntry.rb +65 -0
  19. data/lib/Eodhd/Fundamentals/Earnings.rb +30 -0
  20. data/lib/Eodhd/Fundamentals/Financials/BalanceSheet/Entry.rb +147 -0
  21. data/lib/Eodhd/Fundamentals/Financials/BalanceSheet.rb +28 -0
  22. data/lib/Eodhd/Fundamentals/Financials/CashFlow/Entry.rb +83 -0
  23. data/lib/Eodhd/Fundamentals/Financials/CashFlow.rb +28 -0
  24. data/lib/Eodhd/Fundamentals/Financials/IncomeStatement/Entry.rb +87 -0
  25. data/lib/Eodhd/Fundamentals/Financials/IncomeStatement.rb +28 -0
  26. data/lib/Eodhd/Fundamentals/Financials.rb +25 -0
  27. data/lib/Eodhd/Fundamentals/General.rb +85 -0
  28. data/lib/Eodhd/Fundamentals/Highlights.rb +63 -0
  29. data/lib/Eodhd/Fundamentals/Holders/Fund.rb +31 -0
  30. data/lib/Eodhd/Fundamentals/Holders/Institution.rb +31 -0
  31. data/lib/Eodhd/Fundamentals/Holders.rb +27 -0
  32. data/lib/Eodhd/Fundamentals/InsiderTransaction.rb +35 -0
  33. data/lib/Eodhd/Fundamentals/OutstandingShares/Entry.rb +25 -0
  34. data/lib/Eodhd/Fundamentals/OutstandingShares.rb +26 -0
  35. data/lib/Eodhd/Fundamentals/SharesStats.rb +33 -0
  36. data/lib/Eodhd/Fundamentals/SplitsDividends.rb +31 -0
  37. data/lib/Eodhd/Fundamentals/Technicals.rb +33 -0
  38. data/lib/Eodhd/Fundamentals/Valuation.rb +29 -0
  39. data/lib/Eodhd/Fundamentals.rb +92 -0
  40. data/lib/Eodhd/Intraday.rb +76 -0
  41. data/lib/Eodhd/VERSION.rb +3 -0
  42. data/lib/Eodhd/Validations.rb +78 -0
  43. data/lib/Eodhd/WebSocketClient.rb +130 -0
  44. data/lib/Hash/x_www_form_urlencode.rb +7 -0
  45. data/lib/Thoran/Hash/XWwwFormUrlencode/x_www_form_urlencode.rb +27 -0
  46. data/lib/Thoran/String/Urlencode/urlencode.rb +29 -0
  47. data/lib/eodhd.rb +78 -0
  48. data/test/Eodhd/Client_test.rb +111 -0
  49. data/test/Eodhd/Fundamentals_test.rb +163 -0
  50. data/test/Eodhd/VERSION_test.rb +20 -0
  51. data/test/Eodhd/Validations_test.rb +135 -0
  52. data/test/Eodhd/WebSocketClient_test.rb +99 -0
  53. data/test/Eodhd_test.rb +73 -0
  54. data/test/helper.rb +17 -0
  55. metadata +218 -0
@@ -0,0 +1,163 @@
1
+ # Eodhd/Fundamentals_test.rb
2
+
3
+ require_relative '../helper'
4
+
5
+ describe Eodhd::Fundamentals do
6
+ let(:api_token){ENV.fetch('EODHD_API_TOKEN', '<API_TOKEN>')}
7
+ let(:fd){Eodhd::Fundamentals.all(api_token: api_token, exchange_code: 'US', symbol: 'AAPL')}
8
+
9
+ describe ".all" do
10
+ it "returns an Eodhd::Fundamentals object" do
11
+ VCR.use_cassette('fundamentals_aapl') do
12
+ _(fd).must_be_kind_of(Eodhd::Fundamentals)
13
+ end
14
+ end
15
+
16
+ it "stores exchange_code and symbol" do
17
+ VCR.use_cassette('fundamentals_aapl') do
18
+ _(fd.exchange_code).must_equal('US')
19
+ _(fd.symbol).must_equal('AAPL')
20
+ end
21
+ end
22
+
23
+ it "returns General as an Eodhd::Fundamentals::General" do
24
+ VCR.use_cassette('fundamentals_aapl') do
25
+ _(fd.general).must_be_kind_of(Eodhd::Fundamentals::General)
26
+ _(fd.general.code).must_equal('AAPL')
27
+ _(fd.general.name).wont_be_nil
28
+ end
29
+ end
30
+
31
+ it "returns Highlights as an Eodhd::Fundamentals::Highlights" do
32
+ VCR.use_cassette('fundamentals_aapl') do
33
+ _(fd.highlights).must_be_kind_of(Eodhd::Fundamentals::Highlights)
34
+ _(fd.highlights.market_capitalization).wont_be_nil
35
+ end
36
+ end
37
+
38
+ it "returns Valuation as an Eodhd::Fundamentals::Valuation" do
39
+ VCR.use_cassette('fundamentals_aapl') do
40
+ _(fd.valuation).must_be_kind_of(Eodhd::Fundamentals::Valuation)
41
+ end
42
+ end
43
+
44
+ it "returns Financials as an Eodhd::Fundamentals::Financials" do
45
+ VCR.use_cassette('fundamentals_aapl') do
46
+ _(fd.financials).must_be_kind_of(Eodhd::Fundamentals::Financials)
47
+ end
48
+ end
49
+
50
+ it "returns Financials with typed income_statement, balance_sheet, and cash_flow" do
51
+ VCR.use_cassette('fundamentals_aapl') do
52
+ _(fd.financials.income_statement).must_be_kind_of(Eodhd::Fundamentals::Financials::IncomeStatement)
53
+ _(fd.financials.balance_sheet).must_be_kind_of(Eodhd::Fundamentals::Financials::BalanceSheet)
54
+ _(fd.financials.cash_flow).must_be_kind_of(Eodhd::Fundamentals::Financials::CashFlow)
55
+ end
56
+ end
57
+
58
+ it "returns quarterly and yearly as sorted arrays of typed entries" do
59
+ VCR.use_cassette('fundamentals_aapl') do
60
+ yearly = fd.financials.balance_sheet.yearly
61
+ _(yearly).must_be_kind_of(Array)
62
+ _(yearly.first).must_be_kind_of(Eodhd::Fundamentals::Financials::BalanceSheet::Entry)
63
+ _(fd.financials.balance_sheet.quarterly).must_be_kind_of(Array)
64
+ dates = yearly.map(&:date)
65
+ _(dates).must_equal(dates.sort)
66
+ _(dates.first).must_equal('1985-09-30')
67
+ end
68
+ end
69
+
70
+ it "resolves interpreted and typo-corrected balance sheet accessors" do
71
+ VCR.use_cassette('fundamentals_aapl') do
72
+ latest = fd.financials.balance_sheet.yearly.last
73
+ _(latest.date).must_equal('2025-09-30')
74
+ _(latest.total_liabilities).must_equal('285508000000.00') # totalLiab
75
+ _(latest.capital_surplus).must_equal('93567852270.00') # capitalSurpluse (misspelling corrected)
76
+ _(latest.non_current_assets_other).must_equal('62950000000.00') # nonCurrrentAssetsOther (typo corrected)
77
+ end
78
+ end
79
+
80
+ it "expands abbreviated income statement accessors" do
81
+ VCR.use_cassette('fundamentals_aapl') do
82
+ latest = fd.financials.income_statement.yearly.last
83
+ _(latest.net_income_from_continuing_operations).must_equal('112010000000.00') # netIncomeFromContinuingOps
84
+ end
85
+ end
86
+
87
+ it "returns Earnings as an Eodhd::Fundamentals::Earnings" do
88
+ VCR.use_cassette('fundamentals_aapl') do
89
+ _(fd.earnings).must_be_kind_of(Eodhd::Fundamentals::Earnings)
90
+ end
91
+ end
92
+
93
+ it "returns Earnings annual, history, and trend as arrays of typed entries" do
94
+ VCR.use_cassette('fundamentals_aapl') do
95
+ _(fd.earnings.annual.first).must_be_kind_of(Eodhd::Fundamentals::Earnings::AnnualEntry)
96
+ _(fd.earnings.history.first).must_be_kind_of(Eodhd::Fundamentals::Earnings::HistoryEntry)
97
+ _(fd.earnings.trend.first).must_be_kind_of(Eodhd::Fundamentals::Earnings::TrendEntry)
98
+ dates = fd.earnings.annual.map(&:date)
99
+ _(dates).must_equal(dates.sort)
100
+ end
101
+ end
102
+
103
+ it "returns Holders institutions and funds as arrays of typed entries" do
104
+ VCR.use_cassette('fundamentals_aapl') do
105
+ _(fd.holders.institutions).must_be_kind_of(Array)
106
+ _(fd.holders.funds).must_be_kind_of(Array)
107
+ institution = fd.holders.institutions.first
108
+ _(institution).must_be_kind_of(Eodhd::Fundamentals::Holders::Institution)
109
+ _(institution.name).must_equal('Vanguard Group Inc')
110
+ _(institution.change_percent).must_equal(1.9191) # change_p
111
+ end
112
+ end
113
+
114
+ it "returns insider_transactions as a sorted array of InsiderTransaction" do
115
+ VCR.use_cassette('fundamentals_aapl') do
116
+ _(fd.insider_transactions).must_be_kind_of(Array)
117
+ _(fd.insider_transactions.first).must_be_kind_of(Eodhd::Fundamentals::InsiderTransaction)
118
+ dates = fd.insider_transactions.map(&:date)
119
+ _(dates).must_equal(dates.sort)
120
+ end
121
+ end
122
+
123
+ it "returns outstanding_shares as OutstandingShares with typed annual and quarterly arrays" do
124
+ VCR.use_cassette('fundamentals_aapl') do
125
+ _(fd.outstanding_shares).must_be_kind_of(Eodhd::Fundamentals::OutstandingShares)
126
+ _(fd.outstanding_shares.annual.first).must_be_kind_of(Eodhd::Fundamentals::OutstandingShares::Entry)
127
+ _(fd.outstanding_shares.quarterly.first).must_be_kind_of(Eodhd::Fundamentals::OutstandingShares::Entry)
128
+ end
129
+ end
130
+
131
+ it "returns SharesStats as an Eodhd::Fundamentals::SharesStats" do
132
+ VCR.use_cassette('fundamentals_aapl') do
133
+ _(fd.shares_stats).must_be_kind_of(Eodhd::Fundamentals::SharesStats)
134
+ _(fd.shares_stats.shares_outstanding).wont_be_nil
135
+ end
136
+ end
137
+ end
138
+
139
+ describe ".all with an ASX symbol" do
140
+ let(:fd){Eodhd::Fundamentals.all(api_token: api_token, exchange_code: 'AU', symbol: 'CBA')}
141
+
142
+ it "wraps a real AU fundamentals payload into the same typed objects" do
143
+ VCR.use_cassette('fundamentals_cba_au') do
144
+ _(fd).must_be_kind_of(Eodhd::Fundamentals)
145
+ _(fd.exchange_code).must_equal('AU')
146
+ _(fd.symbol).must_equal('CBA')
147
+ _(fd.general).must_be_kind_of(Eodhd::Fundamentals::General)
148
+
149
+ _(fd.financials.balance_sheet).must_be_kind_of(Eodhd::Fundamentals::Financials::BalanceSheet)
150
+ yearly = fd.financials.balance_sheet.yearly
151
+ _(yearly).must_be_kind_of(Array)
152
+ _(yearly).wont_be_empty
153
+ _(yearly.first).must_be_kind_of(Eodhd::Fundamentals::Financials::BalanceSheet::Entry)
154
+ dates = yearly.map(&:date)
155
+ _(dates).must_equal(dates.sort)
156
+
157
+ _(fd.holders.institutions).must_be_kind_of(Array)
158
+ _(fd.insider_transactions).must_be_kind_of(Array)
159
+ _(fd.outstanding_shares).must_be_kind_of(Eodhd::Fundamentals::OutstandingShares)
160
+ end
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,20 @@
1
+ # test/Eodhd/VERSION_test.rb
2
+
3
+ require_relative '../helper'
4
+
5
+ describe Eodhd do
6
+ describe "VERSION" do
7
+ it "is a string" do
8
+ _(Eodhd::VERSION).must_be_instance_of String
9
+ end
10
+
11
+ it "is three numbers separated by dots" do
12
+ _(Eodhd::VERSION).must_match(/\A\d+\.\d+\.\d+\z/)
13
+ end
14
+
15
+ it "matches the newest entry in the CHANGELOG" do
16
+ changelog = File.read(File.expand_path('../../CHANGELOG', __dir__))
17
+ _(changelog[/^(\d+\.\d+\.\d+):/, 1]).must_equal Eodhd::VERSION
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,135 @@
1
+ # Eodhd/Validations_test.rb
2
+
3
+ require_relative '../helper'
4
+
5
+ class DummyIncludingValidations
6
+ include Eodhd::Validations
7
+ end
8
+
9
+ describe Eodhd::Validations do
10
+ let(:v){DummyIncludingValidations.new}
11
+
12
+ describe "#validate_arguments" do
13
+ it "accepts all valid arguments" do
14
+ _{v.validate_arguments(
15
+ exchange_code: 'AU',
16
+ symbol: 'BHP',
17
+ period: 'd',
18
+ from: '2024-01-01',
19
+ to: '2024-12-31'
20
+ )}.must_be_silent
21
+ end
22
+
23
+ it "accepts exchange_id as alias for exchange_code" do
24
+ _{v.validate_arguments(exchange_id: 'AU')}.must_be_silent
25
+ end
26
+
27
+ it "raises ArgumentError for invalid exchange_code" do
28
+ _{v.validate_arguments(exchange_code: 'au')}.must_raise(ArgumentError)
29
+ end
30
+
31
+ it "raises ArgumentError for invalid symbol" do
32
+ _{v.validate_arguments(symbol: 'bad$')}.must_raise(ArgumentError)
33
+ end
34
+
35
+ it "raises ArgumentError for invalid period" do
36
+ _{v.validate_arguments(period: 'h')}.must_raise(ArgumentError)
37
+ end
38
+
39
+ it "raises ArgumentError for invalid from date" do
40
+ _{v.validate_arguments(from: '2024/01/01')}.must_raise(ArgumentError)
41
+ end
42
+
43
+ it "raises ArgumentError for invalid to date" do
44
+ _{v.validate_arguments(to: '2024-02-30')}.must_raise(ArgumentError)
45
+ end
46
+
47
+ it "raises ArgumentError for reversed date range" do
48
+ _{v.validate_arguments(from: '2024-12-31', to: '2024-01-01')}.must_raise(ArgumentError)
49
+ end
50
+
51
+ it "accepts nil values for all arguments" do
52
+ _{v.validate_arguments}.must_be_silent
53
+ end
54
+ end
55
+
56
+ describe "#validate_exchange_code" do
57
+ it "accepts valid exchange codes" do
58
+ _{v.validate_exchange_code('AU')}.must_be_silent
59
+ _{v.validate_exchange_code('XETRA')}.must_be_silent
60
+ end
61
+
62
+ it "rejects invalid exchange codes" do
63
+ _{v.validate_exchange_code('us')}.must_raise(ArgumentError)
64
+ _{v.validate_exchange_code('U')}.must_raise(ArgumentError)
65
+ _{v.validate_exchange_code('TOOLONG')}.must_raise(ArgumentError)
66
+ end
67
+ end
68
+
69
+ describe "#validate_symbol" do
70
+ it "accepts valid symbols" do
71
+ _{v.validate_symbol('AAPL')}.must_be_silent
72
+ _{v.validate_symbol('BRK.B')}.must_be_silent
73
+ _{v.validate_symbol('RDS-A')}.must_be_silent
74
+ end
75
+
76
+ it "rejects invalid symbols" do
77
+ _{v.validate_symbol('')}.must_raise(ArgumentError)
78
+ _{v.validate_symbol(' ')}.must_raise(ArgumentError)
79
+ _{v.validate_symbol('THIS_SYMBOL_IS_TOO_LONG')}.must_raise(ArgumentError)
80
+ _{v.validate_symbol('bad$')}.must_raise(ArgumentError)
81
+ end
82
+ end
83
+
84
+ describe "#validate_period" do
85
+ it "accepts valid periods" do
86
+ _{v.validate_period('d')}.must_be_silent
87
+ _{v.validate_period('w')}.must_be_silent
88
+ _{v.validate_period('m')}.must_be_silent
89
+ end
90
+
91
+ it "rejects invalid periods" do
92
+ _{v.validate_period('h')}.must_raise(ArgumentError)
93
+ _{v.validate_period('')}.must_raise(ArgumentError)
94
+ end
95
+ end
96
+
97
+ describe "#validate_interval" do
98
+ it "accepts valid intervals" do
99
+ _{v.validate_interval('1m')}.must_be_silent
100
+ _{v.validate_interval('5m')}.must_be_silent
101
+ _{v.validate_interval('1h')}.must_be_silent
102
+ _{v.validate_interval('1d')}.must_be_silent
103
+ end
104
+
105
+ it "rejects invalid intervals" do
106
+ _{v.validate_interval('2m')}.must_raise(ArgumentError)
107
+ _{v.validate_interval('invalid')}.must_raise(ArgumentError)
108
+ _{v.validate_interval('')}.must_raise(ArgumentError)
109
+ end
110
+ end
111
+
112
+ describe "#validate_date" do
113
+ it "accepts valid date formats and Date objects" do
114
+ _{v.validate_date('2024-09-30')}.must_be_silent
115
+ _{v.validate_date(Date.new(2024,9,30))}.must_be_silent
116
+ end
117
+
118
+ it "rejects invalid dates and formats" do
119
+ _{v.validate_date('2024/09/30')}.must_raise(ArgumentError)
120
+ _{v.validate_date('2024-02-30')}.must_raise(ArgumentError)
121
+ _{v.validate_date(12345)}.must_raise(ArgumentError)
122
+ end
123
+ end
124
+
125
+ describe "#validate_date_range" do
126
+ it "accepts valid date ranges" do
127
+ _{v.validate_date_range('2024-01-01','2024-12-31')}.must_be_silent
128
+ _{v.validate_date_range(Date.new(2024,1,1),Date.new(2024,12,31))}.must_be_silent
129
+ end
130
+
131
+ it "rejects reversed date ranges" do
132
+ _{v.validate_date_range('2024-12-31','2024-01-01')}.must_raise(ArgumentError)
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,99 @@
1
+ # Eodhd/WebSocketClient_test.rb
2
+
3
+ require_relative '../helper'
4
+
5
+ describe Eodhd::WebSocketClient do
6
+ let(:api_token){ENV.fetch('EODHD_API_TOKEN', '<API_TOKEN>')}
7
+ let(:consumer){->(data){}}
8
+
9
+ describe "#initialize" do
10
+ it "accepts array of symbols and formats to comma-separated string" do
11
+ client = Eodhd::WebSocketClient.new(api_token: api_token, asset_class: 'us', symbols: ['AAPL', 'MSFT'], consumer: consumer)
12
+ _(client.symbols).must_equal('AAPL,MSFT')
13
+ end
14
+
15
+ it "accepts string of symbols" do
16
+ client = Eodhd::WebSocketClient.new(api_token: api_token, asset_class: 'us', symbols: 'AAPL,MSFT', consumer: consumer)
17
+ _(client.symbols).must_equal('AAPL,MSFT')
18
+ end
19
+ end
20
+
21
+ describe "#url" do
22
+ it "generates correct URL for US trade stream" do
23
+ client = Eodhd::WebSocketClient.new(api_token: api_token, asset_class: 'us', symbols: 'AAPL', consumer: consumer)
24
+ _(client.send(:url)).must_equal("wss://ws.eodhistoricaldata.com/ws/us?api_token=#{api_token}")
25
+ end
26
+
27
+ it "generates correct URL for US quote stream" do
28
+ client = Eodhd::WebSocketClient.new(api_token: api_token, asset_class: 'us-quote', symbols: 'AAPL', consumer: consumer)
29
+ _(client.send(:url)).must_equal("wss://ws.eodhistoricaldata.com/ws/us-quote?api_token=#{api_token}")
30
+ end
31
+
32
+ it "generates correct URL for forex stream" do
33
+ client = Eodhd::WebSocketClient.new(api_token: api_token, asset_class: 'forex', symbols: 'EURUSD', consumer: consumer)
34
+ _(client.send(:url)).must_equal("wss://ws.eodhistoricaldata.com/ws/forex?api_token=#{api_token}")
35
+ end
36
+
37
+ it "generates correct URL for crypto stream" do
38
+ client = Eodhd::WebSocketClient.new(api_token: api_token, asset_class: 'crypto', symbols: 'BTC-USD', consumer: consumer)
39
+ _(client.send(:url)).must_equal("wss://ws.eodhistoricaldata.com/ws/crypto?api_token=#{api_token}")
40
+ end
41
+ end
42
+
43
+ describe "#format_symbols" do
44
+ it "converts array to comma-separated string" do
45
+ client = Eodhd::WebSocketClient.new(api_token: api_token, asset_class: 'us', symbols: ['AAPL', 'MSFT', 'GOOGL'], consumer: consumer)
46
+ _(client.symbols).must_equal('AAPL,MSFT,GOOGL')
47
+ end
48
+
49
+ it "returns string as-is" do
50
+ client = Eodhd::WebSocketClient.new(api_token: api_token, asset_class: 'us', symbols: 'AAPL,MSFT', consumer: consumer)
51
+ _(client.symbols).must_equal('AAPL,MSFT')
52
+ end
53
+ end
54
+
55
+ describe "#run" do
56
+ it "configures Iodine and starts connection" do
57
+ client = Eodhd::WebSocketClient.new(api_token: api_token, asset_class: 'us', symbols: 'AAPL', consumer: consumer)
58
+
59
+ iodine_connect_called = false
60
+ iodine_start_called = false
61
+
62
+ Iodine.stub(:threads=, nil) do
63
+ Iodine.stub(:connect, ->(opts){iodine_connect_called = true}) do
64
+ Iodine.stub(:start, ->{iodine_start_called = true}) do
65
+ client.run
66
+ end
67
+ end
68
+ end
69
+
70
+ _(iodine_connect_called).must_equal(true)
71
+ _(iodine_start_called).must_equal(true)
72
+ end
73
+ end
74
+
75
+ describe "Handler" do
76
+ describe "#on_message" do
77
+ it "parses JSON and calls consumer" do
78
+ received_data = nil
79
+ test_consumer = ->(data){received_data = data}
80
+ handler = Eodhd::WebSocketClient::Handler.new(symbols: 'AAPL', consumer: test_consumer, logger: nil)
81
+
82
+ message = '{"symbol":"AAPL","price":150.0}'
83
+ handler.on_message(nil, message)
84
+
85
+ _(received_data).must_be_kind_of(Hash)
86
+ _(received_data['symbol']).must_equal('AAPL')
87
+ _(received_data['price']).must_equal(150.0)
88
+ end
89
+
90
+ it "raises Eodhd::Error on invalid JSON" do
91
+ test_consumer = ->(data){}
92
+ handler = Eodhd::WebSocketClient::Handler.new(symbols: 'AAPL', consumer: test_consumer, logger: nil)
93
+
94
+ invalid_message = '{invalid json'
95
+ _{handler.on_message(nil, invalid_message)}.must_raise(Eodhd::Error)
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,73 @@
1
+ # Eodhd_test.rb
2
+
3
+ require_relative "helper"
4
+
5
+ describe Eodhd do
6
+ let(:api_token){ENV.fetch('EODHD_API_TOKEN', '<API_TOKEN>')}
7
+ let(:eodhd){Eodhd.new(api_token: api_token)}
8
+
9
+ describe "#exchanges" do
10
+ it "delegates to Eodhd::Exchange.all" do
11
+ VCR.use_cassette('eodhd_exchanges') do
12
+ exchanges = eodhd.exchanges
13
+ _(exchanges).must_be_kind_of(Array)
14
+ _(exchanges).wont_be_empty
15
+ _(exchanges.first).must_be_kind_of(Eodhd::Exchange)
16
+ end
17
+ end
18
+ end
19
+
20
+ describe "#exchange_symbols" do
21
+ it "delegates to Eodhd::ExchangeSymbol.all" do
22
+ VCR.use_cassette('eodhd_exchange_symbols') do
23
+ symbols = eodhd.exchange_symbols(exchange_code: 'AU')
24
+ _(symbols).must_be_kind_of(Array)
25
+ _(symbols).wont_be_empty
26
+ _(symbols.first).must_be_kind_of(Eodhd::ExchangeSymbol)
27
+ end
28
+ end
29
+ end
30
+
31
+ describe "#eod_data" do
32
+ it "delegates to Eodhd::EodData.all" do
33
+ VCR.use_cassette('eodhd_eod_data') do
34
+ eod_data = eodhd.eod_data(exchange_code: 'AU', symbol: 'BHP', period: 'd')
35
+ _(eod_data).must_be_kind_of(Array)
36
+ _(eod_data).wont_be_empty
37
+ _(eod_data.first).must_be_kind_of(Eodhd::EodData)
38
+ end
39
+ end
40
+ end
41
+
42
+ describe "#eod_bulk_last_day" do
43
+ it "delegates to Eodhd::EodBulkLastDay.all" do
44
+ VCR.use_cassette('eodhd_eod_bulk_last_day') do
45
+ bulk_last_day = eodhd.eod_bulk_last_day(exchange_code: 'AU', date: '2024-09-30')
46
+ _(bulk_last_day).must_be_kind_of(Array)
47
+ _(bulk_last_day).wont_be_empty
48
+ _(bulk_last_day.first).must_be_kind_of(Eodhd::EodBulkLastDay)
49
+ end
50
+ end
51
+ end
52
+
53
+ describe "#intraday" do
54
+ it "delegates to Eodhd::Intraday.all" do
55
+ VCR.use_cassette('eodhd_intraday') do
56
+ intraday_data = eodhd.intraday(exchange_code: 'US', symbol: 'AAPL', interval: '5m')
57
+ _(intraday_data).must_be_kind_of(Array)
58
+ _(intraday_data).wont_be_empty
59
+ _(intraday_data.first).must_be_kind_of(Eodhd::Intraday)
60
+ end
61
+ end
62
+ end
63
+
64
+ describe "#fundamentals" do
65
+ it "delegates to Eodhd::Fundamentals.all" do
66
+ VCR.use_cassette('eodhd_fundamentals') do
67
+ fundamental_data = eodhd.fundamentals(exchange_code: 'US', symbol: 'AAPL')
68
+ _(fundamental_data).must_be_kind_of(Eodhd::Fundamentals)
69
+ _(fundamental_data.general).must_be_kind_of(Eodhd::Fundamentals::General)
70
+ end
71
+ end
72
+ end
73
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,17 @@
1
+ # helper.rb
2
+
3
+ require 'minitest/autorun'
4
+ require 'minitest/mock'
5
+ require 'minitest/spec'
6
+ require 'minitest-spec-context'
7
+ require 'vcr'
8
+ require 'webmock/minitest'
9
+
10
+ $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
11
+ require 'Eodhd'
12
+
13
+ VCR.configure do |config|
14
+ config.cassette_library_dir = File.expand_path('./fixtures/vcr_cassettes', __dir__)
15
+ config.hook_into :webmock
16
+ config.filter_sensitive_data('<API_TOKEN>'){ENV['EODHD_API_TOKEN']}
17
+ end