DpExchange.Robinhood.Feed (DpExchangeRobinhood v0.1.1)

Copy Markdown View Source

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

Which symbols are actually arriving. Observed, never intended.

Replaces the polled set.

Functions

child_spec(opts)

@spec child_spec(keyword()) :: Supervisor.child_spec()

coverage(feed)

@spec coverage(pid() | atom()) :: %{required(String.t()) => :internal_poll}

Which symbols are actually arriving. Observed, never intended.

start_link(opts)

@spec start_link(keyword()) :: GenServer.on_start()

update_symbols(feed, symbols)

@spec update_symbols(pid() | atom(), [String.t()]) :: :ok

Replaces the polled set.