DpExchange.Robinhood.Fake (DpExchangeRobinhood v0.2.3)

Copy Markdown View Source

An in-process Robinhood, for a consumer's tier-1 tests and for the conformance suite.

It is not a mock. A real implementation of DpExchange.Core.Venue answering from memory, running the same conformance suite as the real adapter.

What it models that is specific to this venue

  • Credentials are required for market data, because the real venue signs every call and has no anonymous endpoint. Without them: {:refused, :missing_credentials}.
  • Coverage is :internal_poll, not :stream — the one place a consumer can see that this venue has no socket, and it shows up as what is arriving, never as how.
  • No candles, no order book, no volume. The venue serves none, so neither does this.

Failure injection and anonymous mode

Every function below that has a real success path (not an unconditional Venue.not_supported()) checks DpExchange.Core.FakeInjection.next_outcome/1 or /2 first — a queued or always-set outcome from FakeInjection.queue_failures/2,3 or fail_always/2,3 short-circuits the fake's normal logic and is returned as-is. authenticated/1 also checks FakeInjection.credentials_bypassed?/1 before its normal {:refused, :missing_credentials} path. Neither changes anything for a test that never calls FakeInjection — see that module for the full contract.

subscribe/2, unsubscribe/2 and update_symbols/2 are NOT wired: each takes a list of symbols in one call, and "this one symbol in the batch fails, the rest succeed" is a case whole-call injection cannot express — see FakeInjection's own moduledoc.

Summary

Functions

coverage/1, split by kind. Same single-key shape as the real venue, and for the same reason: get_top_of_book/2 above is this fake's only source of subscription data and it produces exclusively Types.TopOfBook, so :top_of_book is the only kind there is to report — see DpExchange.Robinhood.coverage_by_kind/1 for why the family requires this callback even where a venue has nothing to split.

Functions

coverage_by_kind(opts \\ [])

@spec coverage_by_kind(keyword()) :: %{
  required(DpExchange.Core.Capabilities.data_kind()) => %{
    required(DpExchange.Core.Venue.symbol()) => DpExchange.Core.Venue.route()
  }
}

coverage/1, split by kind. Same single-key shape as the real venue, and for the same reason: get_top_of_book/2 above is this fake's only source of subscription data and it produces exclusively Types.TopOfBook, so :top_of_book is the only kind there is to report — see DpExchange.Robinhood.coverage_by_kind/1 for why the family requires this callback even where a venue has nothing to split.