Class: TradingviewScreener::ScreenData::FieldContract
- Inherits:
-
Object
- Object
- TradingviewScreener::ScreenData::FieldContract
- Defined in:
- lib/tradingview_screener/screen_data.rb
Overview
Field names used in filter and sort expressions are validated against the
scanner's server-side schema. Projection-only aliases such as ticker-view
are intentionally excluded because TradingView does not publish them in
/metainfo even though /scan accepts them as columns.
Constant Summary collapse
- METAINFO_URL =
"https://scanner.tradingview.com/%<market>s/metainfo"- MARKET_RE =
/\A[a-z0-9_-]+\z/i- PROJECTION_ALIASES =
Set.new(%w[ticker-view sector.tr AnalystRating AnalystRating.tr]).freeze
Class Method Summary collapse
Instance Method Summary collapse
-
#initialize(market_fields) ⇒ FieldContract
constructor
A new instance of FieldContract.
- #validate!(field, projection: false) ⇒ Object
Constructor Details
#initialize(market_fields) ⇒ FieldContract
Returns a new instance of FieldContract.
124 125 126 |
# File 'lib/tradingview_screener/screen_data.rb', line 124 def initialize(market_fields) @market_fields = market_fields.transform_keys(&:to_s).transform_values { |fields| Set.new(fields.map(&:to_s)) } end |
Class Method Details
.fetch(markets:, client:) ⇒ Object
100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/tradingview_screener/screen_data.rb', line 100 def self.fetch(markets:, client:) market_fields = Array(markets).map(&:to_s).uniq.to_h do |market| unless market.match?(MARKET_RE) raise FieldContractError, "invalid scanner market for metainfo: #{market.inspect}" end body = client.get(format(METAINFO_URL, market: market)) [market, parse_fields(body, market)] end new(market_fields) end |
.parse_fields(body, market) ⇒ Object
112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/tradingview_screener/screen_data.rb', line 112 def self.parse_fields(body, market) data = JSON.parse(body) fields = data["fields"] unless fields.is_a?(Array) raise FieldContractError, "invalid #{market} metainfo: fields must be an array" end fields.filter_map { |field| field["n"] if field.is_a?(Hash) }.to_set rescue JSON::ParserError => e raise FieldContractError, "invalid #{market} metainfo JSON: #{e.}" end |
Instance Method Details
#validate!(field, projection: false) ⇒ Object
128 129 130 131 132 133 134 135 136 |
# File 'lib/tradingview_screener/screen_data.rb', line 128 def validate!(field, projection: false) return field if projection && PROJECTION_ALIASES.include?(field.to_s) missing_markets = @market_fields.filter_map { |market, fields| market unless fields.include?(field.to_s) } return field if missing_markets.empty? raise FieldContractError, "scanner field #{field.inspect} is absent from metainfo for: #{missing_markets.join(', ')}" end |