eodhd.rb 0.16.0 → 0.18.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 +94 -0
- data/README.md +86 -14
- data/Rakefile +28 -0
- data/eodhd.rb.gemspec +31 -13
- data/lib/Eodhd/Client.rb +21 -3
- data/lib/Eodhd/EodBulkLastDay.rb +2 -0
- data/lib/Eodhd/EodData.rb +2 -0
- data/lib/Eodhd/Exchange.rb +2 -0
- data/lib/Eodhd/ExchangeSymbol.rb +2 -0
- data/lib/Eodhd/Fundamentals/AnalystRatings.rb +29 -0
- data/lib/Eodhd/Fundamentals/ESGScores.rb +37 -0
- data/lib/Eodhd/Fundamentals/Earnings.rb +21 -0
- data/lib/Eodhd/Fundamentals/Financials/Statement.rb +21 -0
- data/lib/Eodhd/Fundamentals/Financials.rb +23 -0
- data/lib/Eodhd/Fundamentals/General.rb +85 -0
- data/lib/Eodhd/Fundamentals/Highlights.rb +63 -0
- data/lib/Eodhd/Fundamentals/Holders.rb +19 -0
- data/lib/Eodhd/Fundamentals/SharesStats.rb +33 -0
- data/lib/Eodhd/Fundamentals/SplitsDividends.rb +31 -0
- data/lib/Eodhd/Fundamentals/Technicals.rb +33 -0
- data/lib/Eodhd/Fundamentals/Valuation.rb +29 -0
- data/lib/Eodhd/Fundamentals.rb +85 -0
- data/lib/Eodhd/Intraday.rb +76 -0
- data/lib/Eodhd/VERSION.rb +1 -1
- data/lib/Eodhd/Validations.rb +10 -1
- data/lib/{Eodhd.rb → eodhd.rb} +29 -18
- data/test/{client_test.rb → Eodhd/Client_test.rb} +46 -6
- data/test/Eodhd/Fundamentals_test.rb +78 -0
- data/test/{validations_test.rb → Eodhd/Validations_test.rb} +19 -2
- data/test/{web_socket_client_test.rb → Eodhd/WebSocketClient_test.rb} +9 -7
- data/test/{eodhd_test.rb → Eodhd_test.rb} +23 -0
- data/test/helper.rb +3 -0
- metadata +41 -11
- data/test/test_all.rb +0 -5
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Eodhd/Fundamentals/Highlights.rb
|
|
2
|
+
# Eodhd::Fundamentals::Highlights
|
|
3
|
+
|
|
4
|
+
class Eodhd
|
|
5
|
+
class Fundamentals
|
|
6
|
+
class Highlights
|
|
7
|
+
attr_reader\
|
|
8
|
+
:market_capitalization,
|
|
9
|
+
:ebitda,
|
|
10
|
+
:pe_ratio,
|
|
11
|
+
:peg_ratio,
|
|
12
|
+
:wall_street_target_price,
|
|
13
|
+
:book_value,
|
|
14
|
+
:dividend_share,
|
|
15
|
+
:dividend_yield,
|
|
16
|
+
:earnings_share,
|
|
17
|
+
:eps_estimate_current_year,
|
|
18
|
+
:eps_estimate_next_year,
|
|
19
|
+
:eps_estimate_next_quarter,
|
|
20
|
+
:eps_estimate_current_quarter,
|
|
21
|
+
:most_recent_quarter,
|
|
22
|
+
:profit_margin,
|
|
23
|
+
:operating_margin_ttm,
|
|
24
|
+
:return_on_assets_ttm,
|
|
25
|
+
:return_on_equity_ttm,
|
|
26
|
+
:revenue_ttm,
|
|
27
|
+
:revenue_per_share_ttm,
|
|
28
|
+
:quarterly_revenue_growth_yoy,
|
|
29
|
+
:gross_profit_ttm,
|
|
30
|
+
:diluted_eps_ttm,
|
|
31
|
+
:quarterly_earnings_growth_yoy
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def initialize(data)
|
|
36
|
+
@market_capitalization = data['MarketCapitalization']
|
|
37
|
+
@ebitda = data['EBITDA']
|
|
38
|
+
@pe_ratio = data['PERatio']
|
|
39
|
+
@peg_ratio = data['PEGRatio']
|
|
40
|
+
@wall_street_target_price = data['WallStreetTargetPrice']
|
|
41
|
+
@book_value = data['BookValue']
|
|
42
|
+
@dividend_share = data['DividendShare']
|
|
43
|
+
@dividend_yield = data['DividendYield']
|
|
44
|
+
@earnings_share = data['EarningsShare']
|
|
45
|
+
@eps_estimate_current_year = data['EPSEstimateCurrentYear']
|
|
46
|
+
@eps_estimate_next_year = data['EPSEstimateNextYear']
|
|
47
|
+
@eps_estimate_next_quarter = data['EPSEstimateNextQuarter']
|
|
48
|
+
@eps_estimate_current_quarter = data['EPSEstimateCurrentQuarter']
|
|
49
|
+
@most_recent_quarter = data['MostRecentQuarter']
|
|
50
|
+
@profit_margin = data['ProfitMargin']
|
|
51
|
+
@operating_margin_ttm = data['OperatingMarginTTM']
|
|
52
|
+
@return_on_assets_ttm = data['ReturnOnAssetsTTM']
|
|
53
|
+
@return_on_equity_ttm = data['ReturnOnEquityTTM']
|
|
54
|
+
@revenue_ttm = data['RevenueTTM']
|
|
55
|
+
@revenue_per_share_ttm = data['RevenuePerShareTTM']
|
|
56
|
+
@quarterly_revenue_growth_yoy = data['QuarterlyRevenueGrowthYOY']
|
|
57
|
+
@gross_profit_ttm = data['GrossProfitTTM']
|
|
58
|
+
@diluted_eps_ttm = data['DilutedEpsTTM']
|
|
59
|
+
@quarterly_earnings_growth_yoy = data['QuarterlyEarningsGrowthYOY']
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Eodhd/Fundamentals/Holders.rb
|
|
2
|
+
# Eodhd::Fundamentals::Holders
|
|
3
|
+
|
|
4
|
+
class Eodhd
|
|
5
|
+
class Fundamentals
|
|
6
|
+
class Holders
|
|
7
|
+
attr_reader\
|
|
8
|
+
:institutions,
|
|
9
|
+
:funds
|
|
10
|
+
|
|
11
|
+
private
|
|
12
|
+
|
|
13
|
+
def initialize(data)
|
|
14
|
+
@institutions = data['Institutions']
|
|
15
|
+
@funds = data['Funds']
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Eodhd/Fundamentals/SharesStats.rb
|
|
2
|
+
# Eodhd::Fundamentals::SharesStats
|
|
3
|
+
|
|
4
|
+
class Eodhd
|
|
5
|
+
class Fundamentals
|
|
6
|
+
class SharesStats
|
|
7
|
+
attr_reader\
|
|
8
|
+
:shares_outstanding,
|
|
9
|
+
:shares_float,
|
|
10
|
+
:percent_insiders,
|
|
11
|
+
:percent_institutions,
|
|
12
|
+
:shares_short,
|
|
13
|
+
:shares_short_prior_month,
|
|
14
|
+
:short_ratio,
|
|
15
|
+
:short_percent_outstanding,
|
|
16
|
+
:short_percent_float
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def initialize(data)
|
|
21
|
+
@shares_outstanding = data['SharesOutstanding']
|
|
22
|
+
@shares_float = data['SharesFloat']
|
|
23
|
+
@percent_insiders = data['PercentInsiders']
|
|
24
|
+
@percent_institutions = data['PercentInstitutions']
|
|
25
|
+
@shares_short = data['SharesShort']
|
|
26
|
+
@shares_short_prior_month = data['SharesShortPriorMonth']
|
|
27
|
+
@short_ratio = data['ShortRatio']
|
|
28
|
+
@short_percent_outstanding = data['ShortPercentOutstanding']
|
|
29
|
+
@short_percent_float = data['ShortPercentFloat']
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Eodhd/Fundamentals/SplitsDividends.rb
|
|
2
|
+
# Eodhd::Fundamentals::SplitsDividends
|
|
3
|
+
|
|
4
|
+
class Eodhd
|
|
5
|
+
class Fundamentals
|
|
6
|
+
class SplitsDividends
|
|
7
|
+
attr_reader\
|
|
8
|
+
:forward_annual_dividend_rate,
|
|
9
|
+
:forward_annual_dividend_yield,
|
|
10
|
+
:payout_ratio,
|
|
11
|
+
:dividend_date,
|
|
12
|
+
:ex_dividend_date,
|
|
13
|
+
:last_split_factor,
|
|
14
|
+
:last_split_date,
|
|
15
|
+
:number_dividends_by_year
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def initialize(data)
|
|
20
|
+
@forward_annual_dividend_rate = data['ForwardAnnualDividendRate']
|
|
21
|
+
@forward_annual_dividend_yield = data['ForwardAnnualDividendYield']
|
|
22
|
+
@payout_ratio = data['PayoutRatio']
|
|
23
|
+
@dividend_date = data['DividendDate']
|
|
24
|
+
@ex_dividend_date = data['ExDividendDate']
|
|
25
|
+
@last_split_factor = data['LastSplitFactor']
|
|
26
|
+
@last_split_date = data['LastSplitDate']
|
|
27
|
+
@number_dividends_by_year = data['NumberDividendsByYear']
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Eodhd/Fundamentals/Technicals.rb
|
|
2
|
+
# Eodhd::Fundamentals::Technicals
|
|
3
|
+
|
|
4
|
+
class Eodhd
|
|
5
|
+
class Fundamentals
|
|
6
|
+
class Technicals
|
|
7
|
+
attr_reader\
|
|
8
|
+
:beta,
|
|
9
|
+
:fifty_two_week_high,
|
|
10
|
+
:fifty_two_week_low,
|
|
11
|
+
:fifty_day_ma,
|
|
12
|
+
:two_hundred_day_ma,
|
|
13
|
+
:shares_short,
|
|
14
|
+
:shares_short_prior_month,
|
|
15
|
+
:short_ratio,
|
|
16
|
+
:short_percent
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def initialize(data)
|
|
21
|
+
@beta = data['Beta']
|
|
22
|
+
@fifty_two_week_high = data['52WeekHigh']
|
|
23
|
+
@fifty_two_week_low = data['52WeekLow']
|
|
24
|
+
@fifty_day_ma = data['50DayMA']
|
|
25
|
+
@two_hundred_day_ma = data['200DayMA']
|
|
26
|
+
@shares_short = data['SharesShort']
|
|
27
|
+
@shares_short_prior_month = data['SharesShortPriorMonth']
|
|
28
|
+
@short_ratio = data['ShortRatio']
|
|
29
|
+
@short_percent = data['ShortPercent']
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Eodhd/Fundamentals/Valuation.rb
|
|
2
|
+
# Eodhd::Fundamentals::Valuation
|
|
3
|
+
|
|
4
|
+
class Eodhd
|
|
5
|
+
class Fundamentals
|
|
6
|
+
class Valuation
|
|
7
|
+
attr_reader\
|
|
8
|
+
:trailing_pe,
|
|
9
|
+
:forward_pe,
|
|
10
|
+
:price_sales_ttm,
|
|
11
|
+
:price_book_mrq,
|
|
12
|
+
:enterprise_value,
|
|
13
|
+
:enterprise_value_revenue,
|
|
14
|
+
:enterprise_value_ebitda
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def initialize(data)
|
|
19
|
+
@trailing_pe = data['TrailingPE']
|
|
20
|
+
@forward_pe = data['ForwardPE']
|
|
21
|
+
@price_sales_ttm = data['PriceSalesTTM']
|
|
22
|
+
@price_book_mrq = data['PriceBookMRQ']
|
|
23
|
+
@enterprise_value = data['EnterpriseValue']
|
|
24
|
+
@enterprise_value_revenue = data['EnterpriseValueRevenue']
|
|
25
|
+
@enterprise_value_ebitda = data['EnterpriseValueEbitda']
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Eodhd/Fundamentals.rb
|
|
2
|
+
# Eodhd::Fundamentals
|
|
3
|
+
|
|
4
|
+
require_relative './Fundamentals/AnalystRatings'
|
|
5
|
+
require_relative './Fundamentals/Earnings'
|
|
6
|
+
require_relative './Fundamentals/ESGScores'
|
|
7
|
+
require_relative './Fundamentals/Financials'
|
|
8
|
+
require_relative './Fundamentals/General'
|
|
9
|
+
require_relative './Fundamentals/Highlights'
|
|
10
|
+
require_relative './Fundamentals/Holders'
|
|
11
|
+
require_relative './Fundamentals/SharesStats'
|
|
12
|
+
require_relative './Fundamentals/SplitsDividends'
|
|
13
|
+
require_relative './Fundamentals/Technicals'
|
|
14
|
+
require_relative './Fundamentals/Valuation'
|
|
15
|
+
|
|
16
|
+
class Eodhd
|
|
17
|
+
class Fundamentals
|
|
18
|
+
class << self
|
|
19
|
+
def all(client: nil, api_token: nil, exchange_code:, symbol:, filter: nil)
|
|
20
|
+
load(client: client, api_token: api_token, exchange_code: exchange_code, symbol: symbol, filter: filter)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def load(client: nil, api_token: nil, exchange_code:, symbol:, filter:)
|
|
26
|
+
client ||= Client.new(api_token: api_token)
|
|
27
|
+
response = client.fundamentals(exchange_code: exchange_code, symbol: symbol, filter: filter)
|
|
28
|
+
self.new(
|
|
29
|
+
exchange_code: exchange_code,
|
|
30
|
+
symbol: symbol,
|
|
31
|
+
general: response['General'],
|
|
32
|
+
highlights: response['Highlights'],
|
|
33
|
+
valuation: response['Valuation'],
|
|
34
|
+
shares_stats: response['SharesStats'],
|
|
35
|
+
technicals: response['Technicals'],
|
|
36
|
+
splits_dividends: response['SplitsDividends'],
|
|
37
|
+
analyst_ratings: response['AnalystRatings'],
|
|
38
|
+
holders: response['Holders'],
|
|
39
|
+
insider_transactions: response['InsiderTransactions'],
|
|
40
|
+
esg_scores: response['ESGScores'],
|
|
41
|
+
outstanding_shares: response['outstandingShares'],
|
|
42
|
+
earnings: response['Earnings'],
|
|
43
|
+
financials: response['Financials']
|
|
44
|
+
)
|
|
45
|
+
end
|
|
46
|
+
end # class << self
|
|
47
|
+
|
|
48
|
+
attr_reader\
|
|
49
|
+
:exchange_code,
|
|
50
|
+
:symbol,
|
|
51
|
+
:general,
|
|
52
|
+
:highlights,
|
|
53
|
+
:valuation,
|
|
54
|
+
:shares_stats,
|
|
55
|
+
:technicals,
|
|
56
|
+
:splits_dividends,
|
|
57
|
+
:analyst_ratings,
|
|
58
|
+
:holders,
|
|
59
|
+
:insider_transactions,
|
|
60
|
+
:esg_scores,
|
|
61
|
+
:outstanding_shares,
|
|
62
|
+
:earnings,
|
|
63
|
+
:financials
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def initialize(exchange_code:, symbol:, general:, highlights:, valuation:, shares_stats:, technicals:, splits_dividends:, analyst_ratings:, holders:, insider_transactions:, esg_scores:, outstanding_shares:, earnings:, financials:)
|
|
68
|
+
@exchange_code = exchange_code
|
|
69
|
+
@symbol = symbol
|
|
70
|
+
@general = General.new(general) if general
|
|
71
|
+
@highlights = Highlights.new(highlights) if highlights
|
|
72
|
+
@valuation = Valuation.new(valuation) if valuation
|
|
73
|
+
@shares_stats = SharesStats.new(shares_stats) if shares_stats
|
|
74
|
+
@technicals = Technicals.new(technicals) if technicals
|
|
75
|
+
@splits_dividends = SplitsDividends.new(splits_dividends) if splits_dividends
|
|
76
|
+
@analyst_ratings = AnalystRatings.new(analyst_ratings) if analyst_ratings
|
|
77
|
+
@holders = Holders.new(holders) if holders
|
|
78
|
+
@insider_transactions = insider_transactions
|
|
79
|
+
@esg_scores = ESGScores.new(esg_scores) if esg_scores
|
|
80
|
+
@outstanding_shares = outstanding_shares
|
|
81
|
+
@earnings = Earnings.new(earnings) if earnings
|
|
82
|
+
@financials = Financials.new(financials) if financials
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Eodhd/Intraday.rb
|
|
2
|
+
# Eodhd::Intraday
|
|
3
|
+
|
|
4
|
+
class Eodhd
|
|
5
|
+
class Intraday
|
|
6
|
+
class << self
|
|
7
|
+
def all(client: nil, api_token: nil, exchange_code: 'US', symbol:, interval:, from: nil, to: nil)
|
|
8
|
+
load(
|
|
9
|
+
client: client,
|
|
10
|
+
api_token: api_token,
|
|
11
|
+
exchange_code: exchange_code,
|
|
12
|
+
symbol: symbol,
|
|
13
|
+
interval: interval,
|
|
14
|
+
from: from,
|
|
15
|
+
to: to
|
|
16
|
+
)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def load(client: nil, api_token: nil, exchange_code: 'US', symbol:, interval:, from:, to:)
|
|
22
|
+
client ||= Client.new(api_token: api_token)
|
|
23
|
+
client.intraday(
|
|
24
|
+
exchange_code: exchange_code,
|
|
25
|
+
symbol: symbol,
|
|
26
|
+
interval: interval,
|
|
27
|
+
from: from,
|
|
28
|
+
to: to
|
|
29
|
+
).collect do |intraday_data|
|
|
30
|
+
self.new(
|
|
31
|
+
exchange_code: exchange_code,
|
|
32
|
+
symbol: symbol,
|
|
33
|
+
interval: interval,
|
|
34
|
+
timestamp: intraday_data['timestamp'],
|
|
35
|
+
gmtoffset: intraday_data['gmtoffset'],
|
|
36
|
+
datetime: intraday_data['datetime'],
|
|
37
|
+
open: intraday_data['open'],
|
|
38
|
+
high: intraday_data['high'],
|
|
39
|
+
low: intraday_data['low'],
|
|
40
|
+
close: intraday_data['close'],
|
|
41
|
+
volume: intraday_data['volume']
|
|
42
|
+
)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end # class << self
|
|
46
|
+
|
|
47
|
+
attr_reader\
|
|
48
|
+
:exchange_code,
|
|
49
|
+
:symbol,
|
|
50
|
+
:interval,
|
|
51
|
+
:timestamp,
|
|
52
|
+
:gmtoffset,
|
|
53
|
+
:datetime,
|
|
54
|
+
:open,
|
|
55
|
+
:high,
|
|
56
|
+
:low,
|
|
57
|
+
:close,
|
|
58
|
+
:volume
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
def initialize(exchange_code:, symbol:, interval:, timestamp:, gmtoffset:, datetime:, open:, high:, low:, close:, volume:)
|
|
63
|
+
@exchange_code = exchange_code
|
|
64
|
+
@symbol = symbol
|
|
65
|
+
@interval = interval
|
|
66
|
+
@timestamp = timestamp
|
|
67
|
+
@gmtoffset = gmtoffset
|
|
68
|
+
@datetime = datetime
|
|
69
|
+
@open = open
|
|
70
|
+
@high = high
|
|
71
|
+
@low = low
|
|
72
|
+
@close = close
|
|
73
|
+
@volume = volume
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
data/lib/Eodhd/VERSION.rb
CHANGED
data/lib/Eodhd/Validations.rb
CHANGED
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
|
|
4
4
|
class Eodhd
|
|
5
5
|
module Validations
|
|
6
|
-
def validate_arguments(exchange_code: nil, exchange_id: nil, symbol: nil, period: nil, from: nil, to: nil, date: nil)
|
|
6
|
+
def validate_arguments(exchange_code: nil, exchange_id: nil, symbol: nil, period: nil, interval: nil, from: nil, to: nil, date: nil)
|
|
7
7
|
exchange_code ||= exchange_id
|
|
8
8
|
validate_exchange_code(exchange_code)
|
|
9
9
|
validate_symbol(symbol)
|
|
10
10
|
validate_period(period)
|
|
11
|
+
validate_interval(interval)
|
|
11
12
|
validate_date(from, 'from')
|
|
12
13
|
validate_date(to, 'to')
|
|
13
14
|
validate_date_range(from, to)
|
|
@@ -38,6 +39,14 @@ class Eodhd
|
|
|
38
39
|
end
|
|
39
40
|
end
|
|
40
41
|
|
|
42
|
+
def validate_interval(interval)
|
|
43
|
+
return unless interval
|
|
44
|
+
valid_intervals = %w[1m 5m 15m 30m 1h 4h 1d 1w 1mo]
|
|
45
|
+
unless valid_intervals.include?(interval)
|
|
46
|
+
raise ArgumentError, "Invalid interval: #{interval}. Must be one of: #{valid_intervals.join(', ')}"
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
41
50
|
def validate_date(date, param_name = 'date')
|
|
42
51
|
return unless date
|
|
43
52
|
case date
|
data/lib/{Eodhd.rb → eodhd.rb}
RENAMED
|
@@ -6,45 +6,41 @@ require_relative './Eodhd/EodBulkLastDay'
|
|
|
6
6
|
require_relative './Eodhd/EodData'
|
|
7
7
|
require_relative './Eodhd/Exchange'
|
|
8
8
|
require_relative './Eodhd/ExchangeSymbol'
|
|
9
|
+
require_relative './Eodhd/Intraday'
|
|
10
|
+
require_relative './Eodhd/Fundamentals'
|
|
9
11
|
require_relative './Eodhd/WebSocketClient'
|
|
10
12
|
|
|
11
13
|
class Eodhd
|
|
12
|
-
def initialize(api_token:, consumer: nil)
|
|
13
|
-
@api_token = api_token
|
|
14
|
-
@consumer = consumer
|
|
15
|
-
end
|
|
16
|
-
|
|
17
14
|
def exchanges
|
|
18
15
|
Eodhd::Exchange.all(api_token: @api_token)
|
|
19
16
|
end
|
|
20
17
|
|
|
21
18
|
def exchange_symbols(exchange: nil, exchange_code: nil)
|
|
22
|
-
exchange_code ||= exchange
|
|
19
|
+
exchange_code ||= exchange&.code
|
|
23
20
|
Eodhd::ExchangeSymbol.all(api_token: @api_token, exchange_code: exchange_code)
|
|
24
21
|
end
|
|
25
22
|
|
|
26
23
|
def eod_data(exchange: nil, exchange_code: nil, exchange_symbol: nil, symbol: nil, period: nil, from: nil, to: nil)
|
|
27
|
-
exchange_code ||= exchange
|
|
28
|
-
symbol ||= exchange_symbol
|
|
24
|
+
exchange_code ||= exchange&.code
|
|
25
|
+
symbol ||= exchange_symbol&.code
|
|
29
26
|
Eodhd::EodData.all(api_token: @api_token, exchange_code: exchange_code, symbol: symbol, period: period, from: from, to: to)
|
|
30
27
|
end
|
|
31
28
|
|
|
32
29
|
def eod_bulk_last_day(exchange: nil, exchange_code: nil, date:)
|
|
33
|
-
exchange_code ||= exchange
|
|
30
|
+
exchange_code ||= exchange&.code
|
|
34
31
|
Eodhd::EodBulkLastDay.all(api_token: @api_token, exchange_code: exchange_code, date: date)
|
|
35
32
|
end
|
|
36
33
|
|
|
37
|
-
def
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
symbols: symbols,
|
|
42
|
-
consumer: @consumer,
|
|
43
|
-
)
|
|
34
|
+
def intraday(exchange: nil, exchange_code: nil, exchange_symbol: nil, symbol: nil, interval:, from: nil, to: nil)
|
|
35
|
+
exchange_code ||= exchange&.code
|
|
36
|
+
symbol ||= exchange_symbol&.code
|
|
37
|
+
Eodhd::Intraday.all(api_token: @api_token, exchange_code: exchange_code, symbol: symbol, interval: interval, from: from, to: to)
|
|
44
38
|
end
|
|
45
39
|
|
|
46
|
-
def
|
|
47
|
-
|
|
40
|
+
def fundamentals(exchange: nil, exchange_code: nil, exchange_symbol: nil, symbol: nil, filter: nil)
|
|
41
|
+
exchange_code ||= exchange&.code
|
|
42
|
+
symbol ||= exchange_symbol&.code
|
|
43
|
+
Eodhd::Fundamentals.all(api_token: @api_token, exchange_code: exchange_code, symbol: symbol, filter: filter)
|
|
48
44
|
end
|
|
49
45
|
|
|
50
46
|
def us_trade_stream(symbols)
|
|
@@ -63,4 +59,19 @@ class Eodhd
|
|
|
63
59
|
def crypto_stream(symbols)
|
|
64
60
|
stream(asset_class: 'crypto', symbols: symbols)
|
|
65
61
|
end
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
def initialize(api_token:, consumer: nil)
|
|
66
|
+
@api_token = api_token
|
|
67
|
+
@consumer = consumer
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def web_socket(asset_class:, symbols:)
|
|
71
|
+
Eodhd::WebSocketClient.new(api_token: @api_token, asset_class: asset_class, symbols: symbols, consumer: @consumer)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def stream(asset_class:, symbols:)
|
|
75
|
+
web_socket(asset_class: asset_class, symbols: symbols).run
|
|
76
|
+
end
|
|
66
77
|
end
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
# Eodhd/Client_test.rb
|
|
2
|
+
|
|
3
|
+
require_relative '../helper'
|
|
2
4
|
|
|
3
5
|
describe Eodhd::Client do
|
|
4
6
|
let(:api_token){ENV.fetch('EODHD_API_TOKEN', '<API_TOKEN>')}
|
|
5
|
-
|
|
6
7
|
let(:client){Eodhd::Client.new(api_token: api_token)}
|
|
7
8
|
|
|
8
9
|
describe "#exchanges_list" do
|
|
9
|
-
it "
|
|
10
|
+
it "returns parsed JSON array" do
|
|
10
11
|
VCR.use_cassette("client_exchanges_list") do
|
|
11
12
|
result = client.exchanges_list
|
|
12
13
|
_(result).must_be_kind_of(Array)
|
|
@@ -22,7 +23,7 @@ describe Eodhd::Client do
|
|
|
22
23
|
end
|
|
23
24
|
|
|
24
25
|
describe "#exchange_symbol_list" do
|
|
25
|
-
it "
|
|
26
|
+
it "returns parsed JSON array" do
|
|
26
27
|
VCR.use_cassette("client_exchange_symbol_list") do
|
|
27
28
|
result = client.exchange_symbol_list(exchange_code: 'AU')
|
|
28
29
|
_(result).must_be_kind_of(Array)
|
|
@@ -38,7 +39,7 @@ describe Eodhd::Client do
|
|
|
38
39
|
end
|
|
39
40
|
|
|
40
41
|
describe "#eod_data" do
|
|
41
|
-
it "
|
|
42
|
+
it "returns parsed JSON array" do
|
|
42
43
|
VCR.use_cassette('client_eod_data') do
|
|
43
44
|
result = client.eod_data(exchange_id: 'AU', symbol: 'BHP', period: 'd')
|
|
44
45
|
_(result).must_be_kind_of(Array)
|
|
@@ -54,7 +55,7 @@ describe Eodhd::Client do
|
|
|
54
55
|
end
|
|
55
56
|
|
|
56
57
|
describe "#eod_bulk_last_day" do
|
|
57
|
-
it "
|
|
58
|
+
it "returns parsed JSON array" do
|
|
58
59
|
VCR.use_cassette("client_eod_bulk_last_day") do
|
|
59
60
|
result = client.eod_bulk_last_day(exchange_id: 'AU', date: "2024-09-30")
|
|
60
61
|
_(result).must_be_kind_of(Array)
|
|
@@ -68,4 +69,43 @@ describe Eodhd::Client do
|
|
|
68
69
|
end
|
|
69
70
|
end
|
|
70
71
|
end
|
|
72
|
+
|
|
73
|
+
describe "#intraday" do
|
|
74
|
+
it "returns parsed JSON array" do
|
|
75
|
+
VCR.use_cassette('client_intraday') do
|
|
76
|
+
result = client.intraday(exchange_code: 'US', symbol: 'AAPL', interval: '5m')
|
|
77
|
+
_(result).must_be_kind_of(Array)
|
|
78
|
+
_(result.first.keys).must_equal(%w{timestamp gmtoffset datetime open high low close volume})
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it "raises Eodhd::Error on failure" do
|
|
83
|
+
VCR.use_cassette('client_intraday_401_error') do
|
|
84
|
+
_{client.intraday(exchange_code: 'US', symbol: 'AAPL', interval: '5m')}.must_raise(Eodhd::Error)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
describe "#fundamentals" do
|
|
90
|
+
it "returns parsed JSON hash" do
|
|
91
|
+
VCR.use_cassette('client_fundamentals') do
|
|
92
|
+
result = client.fundamentals(exchange_code: 'US', symbol: 'AAPL')
|
|
93
|
+
_(result).must_be_kind_of(Hash)
|
|
94
|
+
_(result['General']).wont_be_nil
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it "supports filter parameter" do
|
|
99
|
+
VCR.use_cassette('client_fundamentals_filtered') do
|
|
100
|
+
result = client.fundamentals(exchange_code: 'US', symbol: 'AAPL', filter: 'General')
|
|
101
|
+
_(result).must_be_kind_of(Hash)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
it "raises Eodhd::Error on failure" do
|
|
106
|
+
VCR.use_cassette('client_fundamentals_401_error') do
|
|
107
|
+
_{client.fundamentals(exchange_code: 'US', symbol: 'AAPL')}.must_raise(Eodhd::Error)
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
71
111
|
end
|
|
@@ -0,0 +1,78 @@
|
|
|
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 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::Statement)
|
|
53
|
+
_(fd.financials.balance_sheet).must_be_kind_of(Eodhd::Fundamentals::Financials::Statement)
|
|
54
|
+
_(fd.financials.cash_flow).must_be_kind_of(Eodhd::Fundamentals::Financials::Statement)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "returns quarterly and yearly data as hashes on financial statements" do
|
|
59
|
+
VCR.use_cassette('fundamentals_aapl') do
|
|
60
|
+
_(fd.financials.income_statement.quarterly).must_be_kind_of(Hash)
|
|
61
|
+
_(fd.financials.income_statement.yearly).must_be_kind_of(Hash)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it "returns Earnings as an Eodhd::Fundamentals::Earnings" do
|
|
66
|
+
VCR.use_cassette('fundamentals_aapl') do
|
|
67
|
+
_(fd.earnings).must_be_kind_of(Eodhd::Fundamentals::Earnings)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it "returns SharesStats as an Eodhd::Fundamentals::SharesStats" do
|
|
72
|
+
VCR.use_cassette('fundamentals_aapl') do
|
|
73
|
+
_(fd.shares_stats).must_be_kind_of(Eodhd::Fundamentals::SharesStats)
|
|
74
|
+
_(fd.shares_stats.shares_outstanding).wont_be_nil
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|