Bourse.CoinbaseCandlePagination (bourse v0.7.0)

Copy Markdown View Source

Coinbase Exchange candle-window mechanics.

Coinbase's Exchange API accepts granularities 60, 300, 900, 3600, 21600, and 86400 seconds. Its candle endpoint returns newest-first rows and documents a 300-candle maximum. Because start and end are inclusive, Bourse requests at most 299 intervals per page, then merges non-overlapping pages back into Coinbase's newest-first wire order.

Unified callers use ETH/USD; the authored dash symbol pattern routes it to Coinbase's ETH-USD product id. Native product ids remain available on the generated raw endpoint functions.

Live observation on 2026-08-11 established that the current forming bucket appears once it contains a trade. Intervals without ticks are omitted, as the provider documentation states; callers must not assume a dense time series.

Summary

Functions

Merges paged raw responses, deduplicating and retaining the requested chronological range.

Builds inclusive, non-overlapping request pages when limit exceeds 300.

Types

metadata()

@type metadata() :: %{
  start_ms: non_neg_integer(),
  end_ms: non_neg_integer(),
  limit: pos_integer()
}

page()

@type page() :: %{
  params: map(),
  start_ms: non_neg_integer(),
  end_ms: non_neg_integer()
}

Functions

merge_responses!(responses, map)

@spec merge_responses!([map()], metadata()) :: map()

Merges paged raw responses, deduplicating and retaining the requested chronological range.

pagination(params, timeframes, now_ms)

@spec pagination(map(), map(), non_neg_integer()) ::
  {:single, map()} | {:paginate, [page()], metadata()}

Builds inclusive, non-overlapping request pages when limit exceeds 300.

Single-page requests come back as {:single, params} with the window pair completed: Coinbase ignores BOTH start and end whenever either one is missing and silently answers with the most recent page, so a half-open window must never reach the wire.