brapi-ruby-sdk 0.1.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.
Files changed (38) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +30 -0
  3. data/LICENSE +201 -0
  4. data/README.md +221 -0
  5. data/lib/brapi/client.rb +102 -0
  6. data/lib/brapi/configuration.rb +20 -0
  7. data/lib/brapi/errors.rb +40 -0
  8. data/lib/brapi/model.rb +110 -0
  9. data/lib/brapi/models/available_list_response.rb +10 -0
  10. data/lib/brapi/models/balance_sheet_entry.rb +34 -0
  11. data/lib/brapi/models/financial_data_entry.rb +30 -0
  12. data/lib/brapi/models/quote.rb +60 -0
  13. data/lib/brapi/models/quote_list_item.rb +17 -0
  14. data/lib/brapi/models/quote_list_response.rb +16 -0
  15. data/lib/brapi/models/quote_retrieve_response.rb +11 -0
  16. data/lib/brapi/models/v2/crypto.rb +25 -0
  17. data/lib/brapi/models/v2/crypto_list_available_response.rb +11 -0
  18. data/lib/brapi/models/v2/crypto_retrieve_response.rb +13 -0
  19. data/lib/brapi/models/v2/currency.rb +21 -0
  20. data/lib/brapi/models/v2/currency_list_available_response.rb +11 -0
  21. data/lib/brapi/models/v2/currency_retrieve_response.rb +13 -0
  22. data/lib/brapi/models/v2/inflation_entry.rb +13 -0
  23. data/lib/brapi/models/v2/inflation_list_available_response.rb +11 -0
  24. data/lib/brapi/models/v2/inflation_retrieve_response.rb +13 -0
  25. data/lib/brapi/models/v2/prime_rate_entry.rb +13 -0
  26. data/lib/brapi/models/v2/prime_rate_list_available_response.rb +11 -0
  27. data/lib/brapi/models/v2/prime_rate_retrieve_response.rb +13 -0
  28. data/lib/brapi/resource.rb +39 -0
  29. data/lib/brapi/resources/available.rb +13 -0
  30. data/lib/brapi/resources/quote.rb +22 -0
  31. data/lib/brapi/resources/v2/crypto.rb +21 -0
  32. data/lib/brapi/resources/v2/currency.rb +21 -0
  33. data/lib/brapi/resources/v2/inflation.rb +21 -0
  34. data/lib/brapi/resources/v2/prime_rate.rb +21 -0
  35. data/lib/brapi/resources/v2.rb +29 -0
  36. data/lib/brapi/version.rb +5 -0
  37. data/lib/brapi.rb +80 -0
  38. metadata +110 -0
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "time"
4
+
5
+ module Brapi
6
+ class Model
7
+ class << self
8
+ def attribute(name, type: nil, json_key: nil)
9
+ attr_reader name
10
+
11
+ attribute_specs[name] = { type: type, json_key: json_key&.to_s || camelize(name.to_s) }
12
+ end
13
+
14
+ def attribute_specs
15
+ @attribute_specs ||= begin
16
+ parent = superclass.respond_to?(:attribute_specs) ? superclass.attribute_specs : {}
17
+ parent.dup
18
+ end
19
+ end
20
+
21
+ def from_h(value)
22
+ return nil if value.nil?
23
+ return value if value.is_a?(self)
24
+
25
+ new(value)
26
+ end
27
+
28
+ def camelize(snake)
29
+ head, *rest = snake.split("_")
30
+ ([head] + rest.map(&:capitalize)).join
31
+ end
32
+ end
33
+
34
+ def initialize(hash = {})
35
+ hash ||= {}
36
+ hash = hash.transform_keys(&:to_s) if hash.respond_to?(:transform_keys)
37
+ @raw = hash
38
+ self.class.attribute_specs.each do |name, spec|
39
+ value = hash[spec[:json_key]]
40
+ value = hash[name.to_s] if value.nil?
41
+ instance_variable_set("@#{name}", coerce(value, spec[:type]))
42
+ end
43
+ end
44
+
45
+ def to_h
46
+ self.class.attribute_specs.each_with_object({}) do |(name, _), h|
47
+ value = public_send(name)
48
+ h[name] = serialize(value)
49
+ end
50
+ end
51
+
52
+ def [](name)
53
+ public_send(name) if respond_to?(name)
54
+ end
55
+
56
+ def ==(other)
57
+ other.is_a?(self.class) && other.to_h == to_h
58
+ end
59
+ alias eql? ==
60
+
61
+ def hash
62
+ to_h.hash
63
+ end
64
+
65
+ attr_reader :raw
66
+
67
+ private
68
+
69
+ def coerce(value, type)
70
+ return nil if value.nil?
71
+
72
+ case type
73
+ when :string then value.to_s
74
+ when :integer then Integer(value)
75
+ when :float then Float(value)
76
+ when :boolean then !!value
77
+ when :time then parse_time(value)
78
+ when :date then parse_date(value)
79
+ when Array then Array(value).map { |v| coerce(v, type.first) }
80
+ when Class then type.respond_to?(:from_h) ? type.from_h(value) : value
81
+ else value
82
+ end
83
+ end
84
+
85
+ def serialize(value)
86
+ case value
87
+ when Brapi::Model then value.to_h
88
+ when Array then value.map { |v| serialize(v) }
89
+ when Time then value.iso8601
90
+ else value
91
+ end
92
+ end
93
+
94
+ def parse_time(value)
95
+ return value if value.is_a?(Time)
96
+
97
+ Time.parse(value.to_s)
98
+ rescue ArgumentError, TypeError
99
+ nil
100
+ end
101
+
102
+ def parse_date(value)
103
+ return value if value.is_a?(Date)
104
+
105
+ Date.parse(value.to_s)
106
+ rescue ArgumentError, TypeError
107
+ nil
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brapi
4
+ module Models
5
+ class AvailableListResponse < Brapi::Model
6
+ attribute :indexes
7
+ attribute :stocks
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brapi
4
+ module Models
5
+ class BalanceSheetEntry < Brapi::Model
6
+ attribute :end_date, type: :string
7
+ attribute :cash
8
+ attribute :short_term_investments
9
+ attribute :net_receivables
10
+ attribute :inventory
11
+ attribute :other_current_assets
12
+ attribute :total_current_assets
13
+ attribute :long_term_investments
14
+ attribute :property_plant_equipment
15
+ attribute :goodwill
16
+ attribute :intangible_assets
17
+ attribute :other_assets
18
+ attribute :total_assets
19
+ attribute :accounts_payable
20
+ attribute :short_long_term_debt
21
+ attribute :other_current_liabilities
22
+ attribute :total_current_liabilities
23
+ attribute :long_term_debt
24
+ attribute :other_liabilities
25
+ attribute :total_liabilities
26
+ attribute :common_stock
27
+ attribute :retained_earnings
28
+ attribute :treasury_stock
29
+ attribute :other_stockholder_equity
30
+ attribute :total_stockholder_equity
31
+ attribute :net_tangible_assets
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brapi
4
+ module Models
5
+ class FinancialDataEntry < Brapi::Model
6
+ attribute :end_date, type: :string
7
+ attribute :total_revenue
8
+ attribute :revenue_per_share
9
+ attribute :gross_profits
10
+ attribute :ebitda
11
+ attribute :operating_cashflow
12
+ attribute :free_cashflow
13
+ attribute :total_cash
14
+ attribute :total_cash_per_share
15
+ attribute :total_debt
16
+ attribute :debt_to_equity
17
+ attribute :current_ratio
18
+ attribute :quick_ratio
19
+ attribute :return_on_assets
20
+ attribute :return_on_equity
21
+ attribute :gross_margins
22
+ attribute :ebitda_margins
23
+ attribute :operating_margins
24
+ attribute :profit_margins
25
+ attribute :earnings_growth
26
+ attribute :revenue_growth
27
+ attribute :financial_currency
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brapi
4
+ module Models
5
+ class Quote < Brapi::Model
6
+ attribute :symbol, type: :string
7
+ attribute :short_name, type: :string
8
+ attribute :long_name, type: :string
9
+ attribute :currency, type: :string
10
+ attribute :regular_market_price, type: :float
11
+ attribute :regular_market_day_high, type: :float
12
+ attribute :regular_market_day_low, type: :float
13
+ attribute :regular_market_day_range, type: :string
14
+ attribute :regular_market_change, type: :float
15
+ attribute :regular_market_change_percent, type: :float
16
+ attribute :regular_market_time, type: :time
17
+ attribute :market_cap, type: :integer
18
+ attribute :regular_market_volume, type: :integer
19
+ attribute :regular_market_previous_close, type: :float
20
+ attribute :regular_market_open, type: :float
21
+ attribute :average_daily_volume3_month, type: :integer, json_key: "averageDailyVolume3Month"
22
+ attribute :average_daily_volume10_day, type: :integer, json_key: "averageDailyVolume10Day"
23
+ attribute :fifty_two_week_low_change, type: :float
24
+ attribute :fifty_two_week_low_change_percent, type: :float
25
+ attribute :fifty_two_week_range, type: :string
26
+ attribute :fifty_two_week_high_change, type: :float
27
+ attribute :fifty_two_week_high_change_percent, type: :float
28
+ attribute :fifty_two_week_low, type: :float
29
+ attribute :fifty_two_week_high, type: :float
30
+ attribute :two_hundred_day_average, type: :float
31
+ attribute :two_hundred_day_average_change, type: :float
32
+ attribute :two_hundred_day_average_change_percent, type: :float
33
+ attribute :price_earnings, type: :float
34
+ attribute :earnings_per_share, type: :float
35
+ attribute :logourl, type: :string
36
+
37
+ # Module-only fields — exposed as raw hashes/arrays in v0.1.0.
38
+ # Dedicated typed models will land in subsequent minor versions.
39
+ attribute :summary_profile
40
+ attribute :balance_sheet_history, type: [Brapi::Models::BalanceSheetEntry]
41
+ attribute :balance_sheet_history_quarterly, type: [Brapi::Models::BalanceSheetEntry]
42
+ attribute :default_key_statistics
43
+ attribute :default_key_statistics_history
44
+ attribute :default_key_statistics_history_quarterly
45
+ attribute :income_statement_history
46
+ attribute :income_statement_history_quarterly
47
+ attribute :financial_data, type: Brapi::Models::FinancialDataEntry
48
+ attribute :financial_data_history, type: [Brapi::Models::FinancialDataEntry]
49
+ attribute :financial_data_history_quarterly, type: [Brapi::Models::FinancialDataEntry]
50
+ attribute :value_added_history
51
+ attribute :value_added_history_quarterly
52
+ attribute :cashflow_history
53
+ attribute :cashflow_history_quarterly
54
+
55
+ # Historical price data when `range`/`interval` are passed.
56
+ attribute :historical_data_price
57
+ attribute :dividends_data
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brapi
4
+ module Models
5
+ class QuoteListItem < Brapi::Model
6
+ attribute :stock, type: :string
7
+ attribute :name, type: :string
8
+ attribute :close, type: :float
9
+ attribute :change, type: :float
10
+ attribute :volume, type: :integer
11
+ attribute :market_cap, type: :integer
12
+ attribute :logo, type: :string
13
+ attribute :sector, type: :string
14
+ attribute :type, type: :string
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brapi
4
+ module Models
5
+ class QuoteListResponse < Brapi::Model
6
+ attribute :indexes
7
+ attribute :stocks, type: [Brapi::Models::QuoteListItem]
8
+ attribute :available_sectors
9
+ attribute :available_stock_types
10
+ attribute :current_page, type: :integer
11
+ attribute :total_pages, type: :integer
12
+ attribute :item_count, type: :integer
13
+ attribute :has_next_page, type: :boolean
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brapi
4
+ module Models
5
+ class QuoteRetrieveResponse < Brapi::Model
6
+ attribute :results, type: [Brapi::Models::Quote]
7
+ attribute :requested_at, type: :time
8
+ attribute :took, type: :integer
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brapi
4
+ module Models
5
+ module V2
6
+ class Crypto < Brapi::Model
7
+ attribute :currency, type: :string
8
+ attribute :currency_rate_from_usd, type: :float
9
+ attribute :coin_name, type: :string
10
+ attribute :coin, type: :string
11
+ attribute :regular_market_change, type: :float
12
+ attribute :regular_market_change_percent, type: :float
13
+ attribute :regular_market_time, type: :time
14
+ attribute :regular_market_price, type: :float
15
+ attribute :regular_market_day_low, type: :float
16
+ attribute :regular_market_day_high, type: :float
17
+ attribute :regular_market_day_range, type: :string
18
+ attribute :regular_market_volume, type: :float
19
+ attribute :market_cap, type: :float
20
+ attribute :coin_image_url, type: :string
21
+ attribute :historical_data_price
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brapi
4
+ module Models
5
+ module V2
6
+ class CryptoListAvailableResponse < Brapi::Model
7
+ attribute :coins
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brapi
4
+ module Models
5
+ module V2
6
+ class CryptoRetrieveResponse < Brapi::Model
7
+ attribute :coins, type: [Brapi::Models::V2::Crypto]
8
+ attribute :requested_at, type: :time
9
+ attribute :took, type: :string
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brapi
4
+ module Models
5
+ module V2
6
+ class Currency < Brapi::Model
7
+ attribute :from_currency, type: :string
8
+ attribute :to_currency, type: :string
9
+ attribute :name, type: :string
10
+ attribute :high, type: :string
11
+ attribute :low, type: :string
12
+ attribute :bid_variation, type: :string
13
+ attribute :percentage_change, type: :string
14
+ attribute :bid_price, type: :string
15
+ attribute :ask_price, type: :string
16
+ attribute :updated_at_timestamp, type: :string
17
+ attribute :updated_at_date, type: :string
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brapi
4
+ module Models
5
+ module V2
6
+ class CurrencyListAvailableResponse < Brapi::Model
7
+ attribute :currencies
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brapi
4
+ module Models
5
+ module V2
6
+ class CurrencyRetrieveResponse < Brapi::Model
7
+ attribute :currency, type: [Brapi::Models::V2::Currency]
8
+ attribute :requested_at, type: :time
9
+ attribute :took, type: :string
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brapi
4
+ module Models
5
+ module V2
6
+ class InflationEntry < Brapi::Model
7
+ attribute :date, type: :string
8
+ attribute :value, type: :string
9
+ attribute :epoch_date, type: :integer
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brapi
4
+ module Models
5
+ module V2
6
+ class InflationListAvailableResponse < Brapi::Model
7
+ attribute :countries
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brapi
4
+ module Models
5
+ module V2
6
+ class InflationRetrieveResponse < Brapi::Model
7
+ attribute :inflation, type: [Brapi::Models::V2::InflationEntry]
8
+ attribute :requested_at, type: :time
9
+ attribute :took, type: :string
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brapi
4
+ module Models
5
+ module V2
6
+ class PrimeRateEntry < Brapi::Model
7
+ attribute :date, type: :string
8
+ attribute :value, type: :string
9
+ attribute :epoch_date, type: :integer
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brapi
4
+ module Models
5
+ module V2
6
+ class PrimeRateListAvailableResponse < Brapi::Model
7
+ attribute :countries
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brapi
4
+ module Models
5
+ module V2
6
+ class PrimeRateRetrieveResponse < Brapi::Model
7
+ attribute :prime_rate, type: [Brapi::Models::V2::PrimeRateEntry]
8
+ attribute :requested_at, type: :time
9
+ attribute :took, type: :string
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brapi
4
+ class Resource
5
+ attr_reader :client
6
+
7
+ def initialize(client)
8
+ @client = client
9
+ end
10
+
11
+ private
12
+
13
+ def get(path, params: {})
14
+ client.request(:get, path, params: camelize_keys(params))
15
+ end
16
+
17
+ def camelize_keys(params)
18
+ return params if params.nil? || params.empty?
19
+
20
+ params.each_with_object({}) do |(key, value), out|
21
+ out[camelize(key.to_s)] = format_value(value)
22
+ end
23
+ end
24
+
25
+ def camelize(snake)
26
+ head, *rest = snake.split("_")
27
+ ([head] + rest.map(&:capitalize)).join
28
+ end
29
+
30
+ def format_value(value)
31
+ case value
32
+ when Array then value.join(",")
33
+ when true then "true"
34
+ when false then "false"
35
+ else value
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brapi
4
+ module Resources
5
+ class Available < Brapi::Resource
6
+ # GET /api/available
7
+ def list(**params)
8
+ raw = get("/api/available", params: params)
9
+ Brapi::Models::AvailableListResponse.from_h(raw)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cgi"
4
+
5
+ module Brapi
6
+ module Resources
7
+ class Quote < Brapi::Resource
8
+ # GET /api/quote/{tickers}
9
+ def retrieve(tickers, **params)
10
+ tickers_str = Array(tickers).join(",")
11
+ raw = get("/api/quote/#{CGI.escape(tickers_str)}", params: params)
12
+ Brapi::Models::QuoteRetrieveResponse.from_h(raw)
13
+ end
14
+
15
+ # GET /api/quote/list
16
+ def list(**params)
17
+ raw = get("/api/quote/list", params: params)
18
+ Brapi::Models::QuoteListResponse.from_h(raw)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brapi
4
+ module Resources
5
+ class V2
6
+ class Crypto < Brapi::Resource
7
+ # GET /api/v2/crypto
8
+ def retrieve(**params)
9
+ raw = get("/api/v2/crypto", params: params)
10
+ Brapi::Models::V2::CryptoRetrieveResponse.from_h(raw)
11
+ end
12
+
13
+ # GET /api/v2/crypto/available
14
+ def list_available(**params)
15
+ raw = get("/api/v2/crypto/available", params: params)
16
+ Brapi::Models::V2::CryptoListAvailableResponse.from_h(raw)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brapi
4
+ module Resources
5
+ class V2
6
+ class Currency < Brapi::Resource
7
+ # GET /api/v2/currency
8
+ def retrieve(**params)
9
+ raw = get("/api/v2/currency", params: params)
10
+ Brapi::Models::V2::CurrencyRetrieveResponse.from_h(raw)
11
+ end
12
+
13
+ # GET /api/v2/currency/available
14
+ def list_available(**params)
15
+ raw = get("/api/v2/currency/available", params: params)
16
+ Brapi::Models::V2::CurrencyListAvailableResponse.from_h(raw)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brapi
4
+ module Resources
5
+ class V2
6
+ class Inflation < Brapi::Resource
7
+ # GET /api/v2/inflation
8
+ def retrieve(**params)
9
+ raw = get("/api/v2/inflation", params: params)
10
+ Brapi::Models::V2::InflationRetrieveResponse.from_h(raw)
11
+ end
12
+
13
+ # GET /api/v2/inflation/available
14
+ def list_available
15
+ raw = get("/api/v2/inflation/available")
16
+ Brapi::Models::V2::InflationListAvailableResponse.from_h(raw)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brapi
4
+ module Resources
5
+ class V2
6
+ class PrimeRate < Brapi::Resource
7
+ # GET /api/v2/prime-rate
8
+ def retrieve(**params)
9
+ raw = get("/api/v2/prime-rate", params: params)
10
+ Brapi::Models::V2::PrimeRateRetrieveResponse.from_h(raw)
11
+ end
12
+
13
+ # GET /api/v2/prime-rate/available
14
+ def list_available
15
+ raw = get("/api/v2/prime-rate/available")
16
+ Brapi::Models::V2::PrimeRateListAvailableResponse.from_h(raw)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brapi
4
+ module Resources
5
+ class V2
6
+ attr_reader :client
7
+
8
+ def initialize(client)
9
+ @client = client
10
+ end
11
+
12
+ def crypto
13
+ @crypto ||= Brapi::Resources::V2::Crypto.new(client)
14
+ end
15
+
16
+ def currency
17
+ @currency ||= Brapi::Resources::V2::Currency.new(client)
18
+ end
19
+
20
+ def inflation
21
+ @inflation ||= Brapi::Resources::V2::Inflation.new(client)
22
+ end
23
+
24
+ def prime_rate
25
+ @prime_rate ||= Brapi::Resources::V2::PrimeRate.new(client)
26
+ end
27
+ end
28
+ end
29
+ end