This venue's feed — a REST poll, and nothing outside this module needs to know that.
Why a venue with no socket still has a feed
Robinhood Crypto exposes no streaming API. Under the shape this replaces, that fact travelled upward: the collection layer kept a poll set and decided which venues were exempt from it, and an operations page described Robinhood's pairs in terms of a socket it does not have and has never claimed — sending a reader hunting a streaming fault that cannot exist.
Behind a feed, the poll is an implementation detail. This module delivers the same
Core.Types.Quote to the same subscriber as a WebSocket venue, so no consumer branches
on transport, and coverage/1 can report what the venue actually reports about itself:
these symbols are arriving.
Per symbol, because there is no bulk endpoint
best_bid_ask carries no 24-hour statistics and the venue publishes no bulk-stats
endpoint, so Core.PollingFeed runs each symbol on its own schedule — spread across the
interval rather than swept in a burst. With 86 pairs, a burst would put 86 signed
requests into one instant of a budget this venue has already proven sensitive to.
acquire, not check
A moduledoc worth carrying from the adapter this replaces. When rate limiting was first
switched on for this venue — it had never been enabled at all — Robinhood went from
87 of 87 symbols delivering to 8 of 87 in a single cycle. Not the venue throttling:
our own limiter refusing calls the venue was perfectly happy to serve, because check/3
answers "is there capacity right now" and a poll that finds none simply skips the symbol.
acquire/3 waits for capacity instead. A slower cycle rather than a missing price.
Summary
Functions
@spec child_spec(keyword()) :: Supervisor.child_spec()
Which symbols are actually arriving. Observed, never intended.
@spec start_link(keyword()) :: GenServer.on_start()
Replaces the polled set.