eodhd.rb 0.18.1 → 0.19.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0ab9dcc933d673f6d350ed5566a496ca798feec8c4ed8e7b28461957090cbdd0
4
- data.tar.gz: 55ee2522e79c294c47b1305fc59c7971c8fe2af31d307cae76246736eaea5b36
3
+ metadata.gz: e347f01c6ec9787d6a54688677b37264b7d69eeffcd1e074c1fd13ae87cb4cb5
4
+ data.tar.gz: 7a75d41121973122134371a0a860736c0ce9648b06bf61d9c98f359fc71fe590
5
5
  SHA512:
6
- metadata.gz: f6baa626d45145cf812286efdba98fffe0df2e627ace13e2d63b5237d0131f088031ca34055543b96c3a05a944e5a2cd3ee8ee1c2dad4e5c647079b8213c3e8e
7
- data.tar.gz: 943d415c6809d4cbb2c1438fb6491c72c4b0cb84b3a418bb06055f7e80b788348d2d2a1484887430269f631fe16c00c1cba1be1950885fc754fbdfc226620cf2
6
+ metadata.gz: 1bf08b3757f5f6e6425c4af75475aab51ed62914040389f522a01547c2e4f68b3ef09a74d0000729742545aecfca7c0e04d01121f2d0f61b5e666dee9997a03e
7
+ data.tar.gz: 2532629e1aa4fbb1c22cf35794b506a682b8b616f43e59746f0ee23fd2a38c77693313c61999dc072376690fa7b70c6fb43c7c1dcf128a0556d53691116af7eb
data/CHANGELOG CHANGED
@@ -1,5 +1,30 @@
1
1
  # eodhd.rb/CHANGELOG
2
2
 
3
+ ## [0.19.0] - 2026-07-19, complete the fundamentals model wrapping
4
+ - + Eodhd::Fundamentals::Financials::BalanceSheet::Entry: Typed entry for a balance sheet period (64 fields).
5
+ - + Eodhd::Fundamentals::Financials::IncomeStatement::Entry: Typed entry for an income statement period (34 fields).
6
+ - + Eodhd::Fundamentals::Financials::CashFlow::Entry: Typed entry for a cash flow period (32 fields).
7
+ - + Eodhd::Fundamentals::Earnings::AnnualEntry
8
+ - + Eodhd::Fundamentals::Earnings::HistoryEntry
9
+ - + Eodhd::Fundamentals::Earnings::TrendEntry
10
+ - + Eodhd::Fundamentals::Holders::Institution: Typed entry for an institutional holder.
11
+ - + Eodhd::Fundamentals::Holders::Fund: Typed entry for a fund holder.
12
+ - + Eodhd::Fundamentals::InsiderTransaction: Typed entry for an insider transaction.
13
+ - + Eodhd::Fundamentals::OutstandingShares::Entry: Typed entry for an outstanding shares data point.
14
+ - + Eodhd::Fundamentals::OutstandingShares: Wraps annual and quarterly OutstandingShares::Entry arrays.
15
+ - + Eodhd::Fundamentals::Financials::BalanceSheet
16
+ - + Eodhd::Fundamentals::Financials::IncomeStatement
17
+ - + Eodhd::Fundamentals::Financials::CashFlow
18
+ - ~ Eodhd::Fundamentals::Financials: Build BalanceSheet/IncomeStatement/CashFlow instead of the shared Statement.
19
+ - ~ Eodhd::Fundamentals::Financials::BalanceSheet#yearly, #quarterly: Now sorted arrays of typed entries, was raw hashes.
20
+ - ~ Eodhd::Fundamentals::Earnings#annual, #history, #trend: Now sorted arrays of typed entries, was raw hashes.
21
+ - ~ Eodhd::Fundamentals::Holders#institutions, #funds: Now arrays of typed entries, was raw hashes.
22
+ - ~ Eodhd::Fundamentals#insider_transactions: Now a sorted array of InsiderTransaction, was a raw hash.
23
+ - ~ Eodhd::Fundamentals#outstanding_shares: Now an OutstandingShares object, was a raw hash.
24
+ - + test/Eodhd/Fundamentals_test.rb: Cover the newly wrapped entry types and collections.
25
+ - - Eodhd::Fundamentals::Financials::Statement: Replaced by the three per-statement classes.
26
+ - ~ Eodhd/VERSION: /0.18.1/0.19.0/
27
+
3
28
  ## [0.18.1] - 2026-07-19, urlencode helper naming consistency
4
29
  - /Thoran::String::UrlEncode#url_encode/Thoran::String::Urlencode#urlencode/ (url_encode kept as an alias).
5
30
  - /Thoran::Hash::XWwwFormUrlEncode#x_www_form_url_encode/Thoran::Hash::XWwwFormUrlencode#x_www_form_urlencode/ (x_www_form_url_encode kept as an alias).
@@ -0,0 +1,21 @@
1
+ # Eodhd/Fundamentals/Earnings/AnnualEntry.rb
2
+ # Eodhd::Fundamentals::Earnings::AnnualEntry
3
+
4
+ class Eodhd
5
+ class Fundamentals
6
+ class Earnings
7
+ class AnnualEntry
8
+ attr_reader\
9
+ :date,
10
+ :eps_actual
11
+
12
+ private
13
+
14
+ def initialize(data)
15
+ @date = data['date']
16
+ @eps_actual = data['epsActual']
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,33 @@
1
+ # Eodhd/Fundamentals/Earnings/HistoryEntry.rb
2
+ # Eodhd::Fundamentals::Earnings::HistoryEntry
3
+
4
+ class Eodhd
5
+ class Fundamentals
6
+ class Earnings
7
+ class HistoryEntry
8
+ attr_reader\
9
+ :report_date,
10
+ :date,
11
+ :before_after_market,
12
+ :currency,
13
+ :eps_actual,
14
+ :eps_estimate,
15
+ :eps_difference,
16
+ :surprise_percent
17
+
18
+ private
19
+
20
+ def initialize(data)
21
+ @report_date = data['reportDate']
22
+ @date = data['date']
23
+ @before_after_market = data['beforeAfterMarket']
24
+ @currency = data['currency']
25
+ @eps_actual = data['epsActual']
26
+ @eps_estimate = data['epsEstimate']
27
+ @eps_difference = data['epsDifference']
28
+ @surprise_percent = data['surprisePercent']
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,65 @@
1
+ # Eodhd/Fundamentals/Earnings/TrendEntry.rb
2
+ # Eodhd::Fundamentals::Earnings::TrendEntry
3
+
4
+ class Eodhd
5
+ class Fundamentals
6
+ class Earnings
7
+ class TrendEntry
8
+ attr_reader\
9
+ :date,
10
+ :period,
11
+ :growth,
12
+ :earnings_estimate_avg,
13
+ :earnings_estimate_low,
14
+ :earnings_estimate_high,
15
+ :earnings_estimate_year_ago_eps,
16
+ :earnings_estimate_number_of_analysts,
17
+ :earnings_estimate_growth,
18
+ :revenue_estimate_avg,
19
+ :revenue_estimate_low,
20
+ :revenue_estimate_high,
21
+ :revenue_estimate_year_ago_eps,
22
+ :revenue_estimate_number_of_analysts,
23
+ :revenue_estimate_growth,
24
+ :eps_trend_current,
25
+ :eps_trend_7_days_ago,
26
+ :eps_trend_30_days_ago,
27
+ :eps_trend_60_days_ago,
28
+ :eps_trend_90_days_ago,
29
+ :eps_revisions_up_last_7_days,
30
+ :eps_revisions_up_last_30_days,
31
+ :eps_revisions_down_last_7_days,
32
+ :eps_revisions_down_last_30_days
33
+
34
+ private
35
+
36
+ def initialize(data)
37
+ @date = data['date']
38
+ @period = data['period']
39
+ @growth = data['growth']
40
+ @earnings_estimate_avg = data['earningsEstimateAvg']
41
+ @earnings_estimate_low = data['earningsEstimateLow']
42
+ @earnings_estimate_high = data['earningsEstimateHigh']
43
+ @earnings_estimate_year_ago_eps = data['earningsEstimateYearAgoEps']
44
+ @earnings_estimate_number_of_analysts = data['earningsEstimateNumberOfAnalysts']
45
+ @earnings_estimate_growth = data['earningsEstimateGrowth']
46
+ @revenue_estimate_avg = data['revenueEstimateAvg']
47
+ @revenue_estimate_low = data['revenueEstimateLow']
48
+ @revenue_estimate_high = data['revenueEstimateHigh']
49
+ @revenue_estimate_year_ago_eps = data['revenueEstimateYearAgoEps']
50
+ @revenue_estimate_number_of_analysts = data['revenueEstimateNumberOfAnalysts']
51
+ @revenue_estimate_growth = data['revenueEstimateGrowth']
52
+ @eps_trend_current = data['epsTrendCurrent']
53
+ @eps_trend_7_days_ago = data['epsTrend7daysAgo']
54
+ @eps_trend_30_days_ago = data['epsTrend30daysAgo']
55
+ @eps_trend_60_days_ago = data['epsTrend60daysAgo']
56
+ @eps_trend_90_days_ago = data['epsTrend90daysAgo']
57
+ @eps_revisions_up_last_7_days = data['epsRevisionsUpLast7days']
58
+ @eps_revisions_up_last_30_days = data['epsRevisionsUpLast30days']
59
+ @eps_revisions_down_last_7_days = data['epsRevisionsDownLast7days']
60
+ @eps_revisions_down_last_30_days = data['epsRevisionsDownLast30days']
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -1,6 +1,10 @@
1
1
  # Eodhd/Fundamentals/Earnings.rb
2
2
  # Eodhd::Fundamentals::Earnings
3
3
 
4
+ require_relative './Earnings/AnnualEntry'
5
+ require_relative './Earnings/HistoryEntry'
6
+ require_relative './Earnings/TrendEntry'
7
+
4
8
  class Eodhd
5
9
  class Fundamentals
6
10
  class Earnings
@@ -12,9 +16,14 @@ class Eodhd
12
16
  private
13
17
 
14
18
  def initialize(data)
15
- @history = data['History']
16
- @trend = data['Trend']
17
- @annual = data['Annual']
19
+ @annual = wrap(data['Annual'], AnnualEntry)
20
+ @history = wrap(data['History'], HistoryEntry)
21
+ @trend = wrap(data['Trend'], TrendEntry)
22
+ end
23
+
24
+ def wrap(entries, entry_class)
25
+ return [] unless entries
26
+ entries.values.map{|entry| entry_class.new(entry)}.sort_by(&:date)
18
27
  end
19
28
  end
20
29
  end
@@ -0,0 +1,147 @@
1
+ # Eodhd/Fundamentals/Financials/BalanceSheet/Entry.rb
2
+ # Eodhd::Fundamentals::Financials::BalanceSheet::Entry
3
+
4
+ class Eodhd
5
+ class Fundamentals
6
+ class Financials
7
+ class BalanceSheet
8
+ class Entry
9
+ attr_reader\
10
+ :date,
11
+ :filing_date,
12
+ :currency_symbol,
13
+ :total_assets,
14
+ :intangible_assets,
15
+ :earning_assets,
16
+ :other_current_assets,
17
+ :total_liabilities,
18
+ :total_stockholder_equity,
19
+ :deferred_long_term_liabilities,
20
+ :other_current_liabilities,
21
+ :common_stock,
22
+ :capital_stock,
23
+ :retained_earnings,
24
+ :other_liabilities,
25
+ :goodwill,
26
+ :other_assets,
27
+ :cash,
28
+ :cash_and_equivalents,
29
+ :total_current_liabilities,
30
+ :current_deferred_revenue,
31
+ :net_debt,
32
+ :short_term_debt,
33
+ :short_long_term_debt,
34
+ :short_long_term_debt_total,
35
+ :other_stockholder_equity,
36
+ :property_plant_equipment,
37
+ :total_current_assets,
38
+ :long_term_investments,
39
+ :net_tangible_assets,
40
+ :short_term_investments,
41
+ :net_receivables,
42
+ :long_term_debt,
43
+ :inventory,
44
+ :accounts_payable,
45
+ :total_permanent_equity,
46
+ :noncontrolling_interest_in_consolidated_entity,
47
+ :temporary_equity_redeemable_noncontrolling_interests,
48
+ :accumulated_other_comprehensive_income,
49
+ :additional_paid_in_capital,
50
+ :common_stock_total_equity,
51
+ :preferred_stock_total_equity,
52
+ :retained_earnings_total_equity,
53
+ :treasury_stock,
54
+ :accumulated_amortization,
55
+ :non_current_assets_other,
56
+ :deferred_long_term_asset_charges,
57
+ :non_current_assets_total,
58
+ :capital_lease_obligations,
59
+ :long_term_debt_total,
60
+ :non_current_liabilities_other,
61
+ :non_current_liabilities_total,
62
+ :negative_goodwill,
63
+ :warrants,
64
+ :preferred_stock_redeemable,
65
+ :capital_surplus,
66
+ :liabilities_and_stockholders_equity,
67
+ :cash_and_short_term_investments,
68
+ :property_plant_and_equipment_gross,
69
+ :property_plant_and_equipment_net,
70
+ :accumulated_depreciation,
71
+ :net_working_capital,
72
+ :net_invested_capital,
73
+ :common_stock_shares_outstanding
74
+
75
+ private
76
+
77
+ def initialize(data)
78
+ @date = data['date']
79
+ @filing_date = data['filing_date']
80
+ @currency_symbol = data['currency_symbol']
81
+ @total_assets = data['totalAssets']
82
+ @intangible_assets = data['intangibleAssets']
83
+ @earning_assets = data['earningAssets']
84
+ @other_current_assets = data['otherCurrentAssets']
85
+ @total_liabilities = data['totalLiab']
86
+ @total_stockholder_equity = data['totalStockholderEquity']
87
+ @deferred_long_term_liabilities = data['deferredLongTermLiab']
88
+ @other_current_liabilities = data['otherCurrentLiab']
89
+ @common_stock = data['commonStock']
90
+ @capital_stock = data['capitalStock']
91
+ @retained_earnings = data['retainedEarnings']
92
+ @other_liabilities = data['otherLiab']
93
+ @goodwill = data['goodWill']
94
+ @other_assets = data['otherAssets']
95
+ @cash = data['cash']
96
+ @cash_and_equivalents = data['cashAndEquivalents']
97
+ @total_current_liabilities = data['totalCurrentLiabilities']
98
+ @current_deferred_revenue = data['currentDeferredRevenue']
99
+ @net_debt = data['netDebt']
100
+ @short_term_debt = data['shortTermDebt']
101
+ @short_long_term_debt = data['shortLongTermDebt']
102
+ @short_long_term_debt_total = data['shortLongTermDebtTotal']
103
+ @other_stockholder_equity = data['otherStockholderEquity']
104
+ @property_plant_equipment = data['propertyPlantEquipment']
105
+ @total_current_assets = data['totalCurrentAssets']
106
+ @long_term_investments = data['longTermInvestments']
107
+ @net_tangible_assets = data['netTangibleAssets']
108
+ @short_term_investments = data['shortTermInvestments']
109
+ @net_receivables = data['netReceivables']
110
+ @long_term_debt = data['longTermDebt']
111
+ @inventory = data['inventory']
112
+ @accounts_payable = data['accountsPayable']
113
+ @total_permanent_equity = data['totalPermanentEquity']
114
+ @noncontrolling_interest_in_consolidated_entity = data['noncontrollingInterestInConsolidatedEntity']
115
+ @temporary_equity_redeemable_noncontrolling_interests = data['temporaryEquityRedeemableNoncontrollingInterests']
116
+ @accumulated_other_comprehensive_income = data['accumulatedOtherComprehensiveIncome']
117
+ @additional_paid_in_capital = data['additionalPaidInCapital']
118
+ @common_stock_total_equity = data['commonStockTotalEquity']
119
+ @preferred_stock_total_equity = data['preferredStockTotalEquity']
120
+ @retained_earnings_total_equity = data['retainedEarningsTotalEquity']
121
+ @treasury_stock = data['treasuryStock']
122
+ @accumulated_amortization = data['accumulatedAmortization']
123
+ @non_current_assets_other = data['nonCurrrentAssetsOther']
124
+ @deferred_long_term_asset_charges = data['deferredLongTermAssetCharges']
125
+ @non_current_assets_total = data['nonCurrentAssetsTotal']
126
+ @capital_lease_obligations = data['capitalLeaseObligations']
127
+ @long_term_debt_total = data['longTermDebtTotal']
128
+ @non_current_liabilities_other = data['nonCurrentLiabilitiesOther']
129
+ @non_current_liabilities_total = data['nonCurrentLiabilitiesTotal']
130
+ @negative_goodwill = data['negativeGoodwill']
131
+ @warrants = data['warrants']
132
+ @preferred_stock_redeemable = data['preferredStockRedeemable']
133
+ @capital_surplus = data['capitalSurpluse']
134
+ @liabilities_and_stockholders_equity = data['liabilitiesAndStockholdersEquity']
135
+ @cash_and_short_term_investments = data['cashAndShortTermInvestments']
136
+ @property_plant_and_equipment_gross = data['propertyPlantAndEquipmentGross']
137
+ @property_plant_and_equipment_net = data['propertyPlantAndEquipmentNet']
138
+ @accumulated_depreciation = data['accumulatedDepreciation']
139
+ @net_working_capital = data['netWorkingCapital']
140
+ @net_invested_capital = data['netInvestedCapital']
141
+ @common_stock_shares_outstanding = data['commonStockSharesOutstanding']
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,28 @@
1
+ # Eodhd/Fundamentals/Financials/BalanceSheet.rb
2
+ # Eodhd::Fundamentals::Financials::BalanceSheet
3
+
4
+ require_relative './BalanceSheet/Entry'
5
+
6
+ class Eodhd
7
+ class Fundamentals
8
+ class Financials
9
+ class BalanceSheet
10
+ attr_reader\
11
+ :quarterly,
12
+ :yearly
13
+
14
+ private
15
+
16
+ def initialize(data)
17
+ @yearly = wrap(data['yearly'])
18
+ @quarterly = wrap(data['quarterly'])
19
+ end
20
+
21
+ def wrap(entries)
22
+ return [] unless entries
23
+ entries.values.map{|entry| Entry.new(entry)}.sort_by(&:date)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,83 @@
1
+ # Eodhd/Fundamentals/Financials/CashFlow/Entry.rb
2
+ # Eodhd::Fundamentals::Financials::CashFlow::Entry
3
+
4
+ class Eodhd
5
+ class Fundamentals
6
+ class Financials
7
+ class CashFlow
8
+ class Entry
9
+ attr_reader\
10
+ :date,
11
+ :filing_date,
12
+ :currency_symbol,
13
+ :investments,
14
+ :change_to_liabilities,
15
+ :total_cashflows_from_investing_activities,
16
+ :net_borrowings,
17
+ :total_cash_from_financing_activities,
18
+ :change_to_operating_activities,
19
+ :net_income,
20
+ :change_in_cash,
21
+ :begin_period_cash_flow,
22
+ :end_period_cash_flow,
23
+ :total_cash_from_operating_activities,
24
+ :issuance_of_capital_stock,
25
+ :depreciation,
26
+ :other_cashflows_from_investing_activities,
27
+ :dividends_paid,
28
+ :change_to_inventory,
29
+ :change_to_account_receivables,
30
+ :sale_purchase_of_stock,
31
+ :other_cashflows_from_financing_activities,
32
+ :change_to_netincome,
33
+ :capital_expenditures,
34
+ :change_receivables,
35
+ :cash_flows_other_operating,
36
+ :exchange_rate_changes,
37
+ :cash_and_cash_equivalents_changes,
38
+ :change_in_working_capital,
39
+ :stock_based_compensation,
40
+ :other_non_cash_items,
41
+ :free_cash_flow
42
+
43
+ private
44
+
45
+ def initialize(data)
46
+ @date = data['date']
47
+ @filing_date = data['filing_date']
48
+ @currency_symbol = data['currency_symbol']
49
+ @investments = data['investments']
50
+ @change_to_liabilities = data['changeToLiabilities']
51
+ @total_cashflows_from_investing_activities = data['totalCashflowsFromInvestingActivities']
52
+ @net_borrowings = data['netBorrowings']
53
+ @total_cash_from_financing_activities = data['totalCashFromFinancingActivities']
54
+ @change_to_operating_activities = data['changeToOperatingActivities']
55
+ @net_income = data['netIncome']
56
+ @change_in_cash = data['changeInCash']
57
+ @begin_period_cash_flow = data['beginPeriodCashFlow']
58
+ @end_period_cash_flow = data['endPeriodCashFlow']
59
+ @total_cash_from_operating_activities = data['totalCashFromOperatingActivities']
60
+ @issuance_of_capital_stock = data['issuanceOfCapitalStock']
61
+ @depreciation = data['depreciation']
62
+ @other_cashflows_from_investing_activities = data['otherCashflowsFromInvestingActivities']
63
+ @dividends_paid = data['dividendsPaid']
64
+ @change_to_inventory = data['changeToInventory']
65
+ @change_to_account_receivables = data['changeToAccountReceivables']
66
+ @sale_purchase_of_stock = data['salePurchaseOfStock']
67
+ @other_cashflows_from_financing_activities = data['otherCashflowsFromFinancingActivities']
68
+ @change_to_netincome = data['changeToNetincome']
69
+ @capital_expenditures = data['capitalExpenditures']
70
+ @change_receivables = data['changeReceivables']
71
+ @cash_flows_other_operating = data['cashFlowsOtherOperating']
72
+ @exchange_rate_changes = data['exchangeRateChanges']
73
+ @cash_and_cash_equivalents_changes = data['cashAndCashEquivalentsChanges']
74
+ @change_in_working_capital = data['changeInWorkingCapital']
75
+ @stock_based_compensation = data['stockBasedCompensation']
76
+ @other_non_cash_items = data['otherNonCashItems']
77
+ @free_cash_flow = data['freeCashFlow']
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,28 @@
1
+ # Eodhd/Fundamentals/Financials/CashFlow.rb
2
+ # Eodhd::Fundamentals::Financials::CashFlow
3
+
4
+ require_relative './CashFlow/Entry'
5
+
6
+ class Eodhd
7
+ class Fundamentals
8
+ class Financials
9
+ class CashFlow
10
+ attr_reader\
11
+ :quarterly,
12
+ :yearly
13
+
14
+ private
15
+
16
+ def initialize(data)
17
+ @yearly = wrap(data['yearly'])
18
+ @quarterly = wrap(data['quarterly'])
19
+ end
20
+
21
+ def wrap(entries)
22
+ return [] unless entries
23
+ entries.values.map{|entry| Entry.new(entry)}.sort_by(&:date)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,87 @@
1
+ # Eodhd/Fundamentals/Financials/IncomeStatement/Entry.rb
2
+ # Eodhd::Fundamentals::Financials::IncomeStatement::Entry
3
+
4
+ class Eodhd
5
+ class Fundamentals
6
+ class Financials
7
+ class IncomeStatement
8
+ class Entry
9
+ attr_reader\
10
+ :date,
11
+ :filing_date,
12
+ :currency_symbol,
13
+ :research_development,
14
+ :effect_of_accounting_charges,
15
+ :income_before_tax,
16
+ :minority_interest,
17
+ :net_income,
18
+ :selling_general_administrative,
19
+ :selling_and_marketing_expenses,
20
+ :gross_profit,
21
+ :reconciled_depreciation,
22
+ :ebit,
23
+ :ebitda,
24
+ :depreciation_and_amortization,
25
+ :non_operating_income_net_other,
26
+ :operating_income,
27
+ :other_operating_expenses,
28
+ :interest_expense,
29
+ :tax_provision,
30
+ :interest_income,
31
+ :net_interest_income,
32
+ :extraordinary_items,
33
+ :non_recurring,
34
+ :other_items,
35
+ :income_tax_expense,
36
+ :total_revenue,
37
+ :total_operating_expenses,
38
+ :cost_of_revenue,
39
+ :total_other_income_expense_net,
40
+ :discontinued_operations,
41
+ :net_income_from_continuing_operations,
42
+ :net_income_applicable_to_common_shares,
43
+ :preferred_stock_and_other_adjustments
44
+
45
+ private
46
+
47
+ def initialize(data)
48
+ @date = data['date']
49
+ @filing_date = data['filing_date']
50
+ @currency_symbol = data['currency_symbol']
51
+ @research_development = data['researchDevelopment']
52
+ @effect_of_accounting_charges = data['effectOfAccountingCharges']
53
+ @income_before_tax = data['incomeBeforeTax']
54
+ @minority_interest = data['minorityInterest']
55
+ @net_income = data['netIncome']
56
+ @selling_general_administrative = data['sellingGeneralAdministrative']
57
+ @selling_and_marketing_expenses = data['sellingAndMarketingExpenses']
58
+ @gross_profit = data['grossProfit']
59
+ @reconciled_depreciation = data['reconciledDepreciation']
60
+ @ebit = data['ebit']
61
+ @ebitda = data['ebitda']
62
+ @depreciation_and_amortization = data['depreciationAndAmortization']
63
+ @non_operating_income_net_other = data['nonOperatingIncomeNetOther']
64
+ @operating_income = data['operatingIncome']
65
+ @other_operating_expenses = data['otherOperatingExpenses']
66
+ @interest_expense = data['interestExpense']
67
+ @tax_provision = data['taxProvision']
68
+ @interest_income = data['interestIncome']
69
+ @net_interest_income = data['netInterestIncome']
70
+ @extraordinary_items = data['extraordinaryItems']
71
+ @non_recurring = data['nonRecurring']
72
+ @other_items = data['otherItems']
73
+ @income_tax_expense = data['incomeTaxExpense']
74
+ @total_revenue = data['totalRevenue']
75
+ @total_operating_expenses = data['totalOperatingExpenses']
76
+ @cost_of_revenue = data['costOfRevenue']
77
+ @total_other_income_expense_net = data['totalOtherIncomeExpenseNet']
78
+ @discontinued_operations = data['discontinuedOperations']
79
+ @net_income_from_continuing_operations = data['netIncomeFromContinuingOps']
80
+ @net_income_applicable_to_common_shares = data['netIncomeApplicableToCommonShares']
81
+ @preferred_stock_and_other_adjustments = data['preferredStockAndOtherAdjustments']
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,28 @@
1
+ # Eodhd/Fundamentals/Financials/IncomeStatement.rb
2
+ # Eodhd::Fundamentals::Financials::IncomeStatement
3
+
4
+ require_relative './IncomeStatement/Entry'
5
+
6
+ class Eodhd
7
+ class Fundamentals
8
+ class Financials
9
+ class IncomeStatement
10
+ attr_reader\
11
+ :quarterly,
12
+ :yearly
13
+
14
+ private
15
+
16
+ def initialize(data)
17
+ @yearly = wrap(data['yearly'])
18
+ @quarterly = wrap(data['quarterly'])
19
+ end
20
+
21
+ def wrap(entries)
22
+ return [] unless entries
23
+ entries.values.map{|entry| Entry.new(entry)}.sort_by(&:date)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -1,7 +1,9 @@
1
1
  # Eodhd/Fundamentals/Financials.rb
2
2
  # Eodhd::Fundamentals::Financials
3
3
 
4
- require_relative './Financials/Statement'
4
+ require_relative './Financials/BalanceSheet'
5
+ require_relative './Financials/CashFlow'
6
+ require_relative './Financials/IncomeStatement'
5
7
 
6
8
  class Eodhd
7
9
  class Fundamentals
@@ -14,9 +16,9 @@ class Eodhd
14
16
  private
15
17
 
16
18
  def initialize(data)
17
- @income_statement = Statement.new(data['Income_Statement']) if data['Income_Statement']
18
- @balance_sheet = Statement.new(data['Balance_Sheet']) if data['Balance_Sheet']
19
- @cash_flow = Statement.new(data['Cash_Flow']) if data['Cash_Flow']
19
+ @income_statement = IncomeStatement.new(data['Income_Statement']) if data['Income_Statement']
20
+ @balance_sheet = BalanceSheet.new(data['Balance_Sheet']) if data['Balance_Sheet']
21
+ @cash_flow = CashFlow.new(data['Cash_Flow']) if data['Cash_Flow']
20
22
  end
21
23
  end
22
24
  end
@@ -0,0 +1,31 @@
1
+ # Eodhd/Fundamentals/Holders/Fund.rb
2
+ # Eodhd::Fundamentals::Holders::Fund
3
+
4
+ class Eodhd
5
+ class Fundamentals
6
+ class Holders
7
+ class Fund
8
+ attr_reader\
9
+ :name,
10
+ :date,
11
+ :total_shares,
12
+ :total_assets,
13
+ :current_shares,
14
+ :change,
15
+ :change_percent
16
+
17
+ private
18
+
19
+ def initialize(data)
20
+ @name = data['name']
21
+ @date = data['date']
22
+ @total_shares = data['totalShares']
23
+ @total_assets = data['totalAssets']
24
+ @current_shares = data['currentShares']
25
+ @change = data['change']
26
+ @change_percent = data['change_p']
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ # Eodhd/Fundamentals/Holders/Institution.rb
2
+ # Eodhd::Fundamentals::Holders::Institution
3
+
4
+ class Eodhd
5
+ class Fundamentals
6
+ class Holders
7
+ class Institution
8
+ attr_reader\
9
+ :name,
10
+ :date,
11
+ :total_shares,
12
+ :total_assets,
13
+ :current_shares,
14
+ :change,
15
+ :change_percent
16
+
17
+ private
18
+
19
+ def initialize(data)
20
+ @name = data['name']
21
+ @date = data['date']
22
+ @total_shares = data['totalShares']
23
+ @total_assets = data['totalAssets']
24
+ @current_shares = data['currentShares']
25
+ @change = data['change']
26
+ @change_percent = data['change_p']
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -1,6 +1,9 @@
1
1
  # Eodhd/Fundamentals/Holders.rb
2
2
  # Eodhd::Fundamentals::Holders
3
3
 
4
+ require_relative './Holders/Institution'
5
+ require_relative './Holders/Fund'
6
+
4
7
  class Eodhd
5
8
  class Fundamentals
6
9
  class Holders
@@ -11,8 +14,13 @@ class Eodhd
11
14
  private
12
15
 
13
16
  def initialize(data)
14
- @institutions = data['Institutions']
15
- @funds = data['Funds']
17
+ @institutions = wrap(data['Institutions'], Institution)
18
+ @funds = wrap(data['Funds'], Fund)
19
+ end
20
+
21
+ def wrap(entries, entry_class)
22
+ return [] unless entries
23
+ entries.values.map{|entry| entry_class.new(entry)}
16
24
  end
17
25
  end
18
26
  end
@@ -0,0 +1,35 @@
1
+ # Eodhd/Fundamentals/InsiderTransaction.rb
2
+ # Eodhd::Fundamentals::InsiderTransaction
3
+
4
+ class Eodhd
5
+ class Fundamentals
6
+ class InsiderTransaction
7
+ attr_reader\
8
+ :date,
9
+ :owner_cik,
10
+ :owner_name,
11
+ :transaction_date,
12
+ :transaction_code,
13
+ :transaction_amount,
14
+ :transaction_price,
15
+ :transaction_acquired_disposed,
16
+ :post_transaction_amount,
17
+ :sec_link
18
+
19
+ private
20
+
21
+ def initialize(data)
22
+ @date = data['date']
23
+ @owner_cik = data['ownerCik']
24
+ @owner_name = data['ownerName']
25
+ @transaction_date = data['transactionDate']
26
+ @transaction_code = data['transactionCode']
27
+ @transaction_amount = data['transactionAmount']
28
+ @transaction_price = data['transactionPrice']
29
+ @transaction_acquired_disposed = data['transactionAcquiredDisposed']
30
+ @post_transaction_amount = data['postTransactionAmount']
31
+ @sec_link = data['secLink']
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,25 @@
1
+ # Eodhd/Fundamentals/OutstandingShares/Entry.rb
2
+ # Eodhd::Fundamentals::OutstandingShares::Entry
3
+
4
+ class Eodhd
5
+ class Fundamentals
6
+ class OutstandingShares
7
+ class Entry
8
+ attr_reader\
9
+ :date,
10
+ :date_formatted,
11
+ :shares_mln,
12
+ :shares
13
+
14
+ private
15
+
16
+ def initialize(data)
17
+ @date = data['date']
18
+ @date_formatted = data['dateFormatted']
19
+ @shares_mln = data['sharesMln']
20
+ @shares = data['shares']
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,26 @@
1
+ # Eodhd/Fundamentals/OutstandingShares.rb
2
+ # Eodhd::Fundamentals::OutstandingShares
3
+
4
+ require_relative './OutstandingShares/Entry'
5
+
6
+ class Eodhd
7
+ class Fundamentals
8
+ class OutstandingShares
9
+ attr_reader\
10
+ :annual,
11
+ :quarterly
12
+
13
+ private
14
+
15
+ def initialize(data)
16
+ @annual = wrap(data['annual'])
17
+ @quarterly = wrap(data['quarterly'])
18
+ end
19
+
20
+ def wrap(entries)
21
+ return [] unless entries
22
+ entries.values.map{|entry| Entry.new(entry)}.sort_by(&:date)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -8,6 +8,8 @@ require_relative './Fundamentals/Financials'
8
8
  require_relative './Fundamentals/General'
9
9
  require_relative './Fundamentals/Highlights'
10
10
  require_relative './Fundamentals/Holders'
11
+ require_relative './Fundamentals/InsiderTransaction'
12
+ require_relative './Fundamentals/OutstandingShares'
11
13
  require_relative './Fundamentals/SharesStats'
12
14
  require_relative './Fundamentals/SplitsDividends'
13
15
  require_relative './Fundamentals/Technicals'
@@ -75,11 +77,16 @@ class Eodhd
75
77
  @splits_dividends = SplitsDividends.new(splits_dividends) if splits_dividends
76
78
  @analyst_ratings = AnalystRatings.new(analyst_ratings) if analyst_ratings
77
79
  @holders = Holders.new(holders) if holders
78
- @insider_transactions = insider_transactions
80
+ @insider_transactions = wrap_insider_transactions(insider_transactions)
79
81
  @esg_scores = ESGScores.new(esg_scores) if esg_scores
80
- @outstanding_shares = outstanding_shares
82
+ @outstanding_shares = OutstandingShares.new(outstanding_shares) if outstanding_shares
81
83
  @earnings = Earnings.new(earnings) if earnings
82
84
  @financials = Financials.new(financials) if financials
83
85
  end
86
+
87
+ def wrap_insider_transactions(entries)
88
+ return [] unless entries
89
+ entries.values.map{|entry| InsiderTransaction.new(entry)}.sort_by(&:date)
90
+ end
84
91
  end
85
92
  end
data/lib/Eodhd/VERSION.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class Eodhd
2
- VERSION = '0.18.1'
2
+ VERSION = '0.19.0'
3
3
  end
@@ -47,18 +47,40 @@ describe Eodhd::Fundamentals do
47
47
  end
48
48
  end
49
49
 
50
- it "returns Financials with income_statement, balance_sheet, and cash_flow" do
50
+ it "returns Financials with typed income_statement, balance_sheet, and cash_flow" do
51
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)
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
55
  end
56
56
  end
57
57
 
58
- it "returns quarterly and yearly data as hashes on financial statements" do
58
+ it "returns quarterly and yearly as sorted arrays of typed entries" do
59
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)
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
62
84
  end
63
85
  end
64
86
 
@@ -68,6 +90,44 @@ describe Eodhd::Fundamentals do
68
90
  end
69
91
  end
70
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
+
71
131
  it "returns SharesStats as an Eodhd::Fundamentals::SharesStats" do
72
132
  VCR.use_cassette('fundamentals_aapl') do
73
133
  _(fd.shares_stats).must_be_kind_of(Eodhd::Fundamentals::SharesStats)
@@ -75,4 +135,29 @@ describe Eodhd::Fundamentals do
75
135
  end
76
136
  end
77
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
78
163
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eodhd.rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.18.1
4
+ version: 0.19.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - thoran
@@ -157,11 +157,24 @@ files:
157
157
  - lib/Eodhd/Fundamentals/AnalystRatings.rb
158
158
  - lib/Eodhd/Fundamentals/ESGScores.rb
159
159
  - lib/Eodhd/Fundamentals/Earnings.rb
160
+ - lib/Eodhd/Fundamentals/Earnings/AnnualEntry.rb
161
+ - lib/Eodhd/Fundamentals/Earnings/HistoryEntry.rb
162
+ - lib/Eodhd/Fundamentals/Earnings/TrendEntry.rb
160
163
  - lib/Eodhd/Fundamentals/Financials.rb
161
- - lib/Eodhd/Fundamentals/Financials/Statement.rb
164
+ - lib/Eodhd/Fundamentals/Financials/BalanceSheet.rb
165
+ - lib/Eodhd/Fundamentals/Financials/BalanceSheet/Entry.rb
166
+ - lib/Eodhd/Fundamentals/Financials/CashFlow.rb
167
+ - lib/Eodhd/Fundamentals/Financials/CashFlow/Entry.rb
168
+ - lib/Eodhd/Fundamentals/Financials/IncomeStatement.rb
169
+ - lib/Eodhd/Fundamentals/Financials/IncomeStatement/Entry.rb
162
170
  - lib/Eodhd/Fundamentals/General.rb
163
171
  - lib/Eodhd/Fundamentals/Highlights.rb
164
172
  - lib/Eodhd/Fundamentals/Holders.rb
173
+ - lib/Eodhd/Fundamentals/Holders/Fund.rb
174
+ - lib/Eodhd/Fundamentals/Holders/Institution.rb
175
+ - lib/Eodhd/Fundamentals/InsiderTransaction.rb
176
+ - lib/Eodhd/Fundamentals/OutstandingShares.rb
177
+ - lib/Eodhd/Fundamentals/OutstandingShares/Entry.rb
165
178
  - lib/Eodhd/Fundamentals/SharesStats.rb
166
179
  - lib/Eodhd/Fundamentals/SplitsDividends.rb
167
180
  - lib/Eodhd/Fundamentals/Technicals.rb
@@ -198,7 +211,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
198
211
  - !ruby/object:Gem::Version
199
212
  version: '0'
200
213
  requirements: []
201
- rubygems_version: 4.0.16
214
+ rubygems_version: 4.0.18
202
215
  specification_version: 4
203
216
  summary: Access the eodhd.com API with Ruby.
204
217
  test_files: []
@@ -1,21 +0,0 @@
1
- # Eodhd/Fundamentals/Financials/Statement.rb
2
- # Eodhd::Fundamentals::Financials::Statement
3
-
4
- class Eodhd
5
- class Fundamentals
6
- class Financials
7
- class Statement
8
- attr_reader\
9
- :quarterly,
10
- :yearly
11
-
12
- private
13
-
14
- def initialize(data)
15
- @quarterly = data['quarterly']
16
- @yearly = data['yearly']
17
- end
18
- end
19
- end
20
- end
21
- end