Skip to content

Coinbase: API keys required for public market data (symbols() raises, subscribe() signs unconditionally) #1114

@mercurise-project

Description

@mercurise-project

Version: 2.4.1 (code unchanged on current master)

The Coinbase adapter requires key_id/key_secret even for public market data, although Coinbase made Advanced Trade market data public in 2024. Two places enforce this:

  1. Coinbase.symbols() (coinbase.py#L77-L82) raises unconditionally without credentials:
if 'coinbase' not in config or 'key_id' not in config['coinbase'] or 'key_secret' not in config['coinbase']:
    raise ValueError('You must provide key_id and key_secret in config to retrieve symbols from Coinbase.')
  1. subscribe() (coinbase.py#L173-L185) calls get_private_parameters(self.config, ...) unconditionally, which reads config["coinbase"]["key_secret"] and signs every subscription — so subscribing without keys fails even though the channels don't need a signature.

What Coinbase actually requires now

  • REST: GET https://api.coinbase.com/api/v3/brokerage/market/products is the public, unauthenticated twin of the authed /api/v3/brokerage/products the adapter currently uses for the symbol map. Verify with:

    curl -s 'https://api.coinbase.com/api/v3/brokerage/market/products' | head -c 300
    

    It returns the full product list with the same shape (products, product_id, base_currency_id, quote_currency_id, quote_increment), so _parse_symbol_data works as-is.

  • WebSocket: wss://advanced-trade-ws.coinbase.com accepts unsigned subscriptions to the public market data channels (market_trades, level2, heartbeats). An unsigned message of the shape the adapter already builds:

    {"type": "subscribe", "product_ids": ["BTC-USD"], "channel": "market_trades"}

    is accepted and streams trades (verified live).

Docs: https://docs.cdp.coinbase.com/advanced-trade/docs/ws-overview (public market data does not require authentication).

Suggested fix

  • Point the symbol-map REST call at /market/products (no headers needed) and drop the credential check in symbols().
  • In subscribe(), only merge in get_private_parameters(...) when credentials are actually configured, so authenticated use keeps working but TRADES/L2_BOOK run with zero config.

I have a working subclass doing exactly this and can open a PR if that's welcome.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions