Coinbase SDK
Complete reference for ctx.coinbase — programmatic trading on Coinbase Advanced Trade from worker code.
Coinbase Advanced Trade API
This SDK wraps the Coinbase Advanced Trade v3 API. Live and (optionally) sandbox environments supported. Coinbase International (CFM) futures methods are surfaced when enabled on your account.
Setup
- Add a Coinbase trading block to your workspace canvas.
- Open the inspector → API Keys → pick a key (Settings → API Keys → Coinbase to add new). Coinbase requires
api_key(CDP key name) +api_secret(PEM-formatted EC private key). - Connect the block to your Worker block via an edge.
- The worker runs in Server mode (Coinbase blocks browser CORS for signed requests).
ctx.coinbaseis now available.
def tick(ctx):
t = ctx.coinbase.get_ticker("BTC-USD")
ctx.log.info(f"BTC-USD: {t.get('price')}")If no Coinbase block is connected:
RuntimeError: No trading block connected. Connect a Coinbase block to this worker.Products & Modes
Coinbase calls instruments products, identified by BASE-QUOTE strings:
| Product type | Pattern | Examples |
|---|---|---|
| Spot | {COIN}-{COIN} | BTC-USD, ETH-USDC, SOL-USDT |
| Futures (CFM) | {COIN}-{EXPIRY} | BTC-29NOV24-CDE |
| Perpetual (INTX) | {COIN}-PERP-INTX | BTC-PERP-INTX |
Account modes (api_mode on key):
| Mode | Notes |
|---|---|
live | Real funds |
sandbox | is_sandbox=true flag on key — Coinbase's Exchange sandbox |
Coinbase has portfolios — sub-accounts that segregate balances and risk. Default portfolio is automatic; for advanced setups use get_portfolios to discover them.
Market Data
get_ticker
Latest ticker for a product.
ctx.coinbase.get_ticker(product_id: str = "BTC-USD") -> dictReturns: {"product_id", "price", "volume_24h", "low_24h", "high_24h", "approximate_quote_24h_volume", ...}
WebSocket cache
PRO/MAX plans return cached ticker data at 0ms latency from the live WS stream — no REST call.
get_orderbook
Order book depth.
ctx.coinbase.get_orderbook(product_id: str = "BTC-USD", limit: int = 50) -> dictReturns: {"pricebook": {"product_id", "bids": [{"price", "size"}], "asks": [{"price", "size"}], "time"}}
ob = ctx.coinbase.get_orderbook("BTC-USD", limit=50)
best_bid = float(ob["pricebook"]["bids"][0]["price"])
best_ask = float(ob["pricebook"]["asks"][0]["price"])
spread_bps = (best_ask - best_bid) / best_bid * 10000get_best_bid_ask
Top-of-book for one or many products in one call.
ctx.coinbase.get_best_bid_ask(product_ids: list = None) -> dicttop = ctx.coinbase.get_best_bid_ask(["BTC-USD", "ETH-USD", "SOL-USD"])get_market_trades
Recent public trades.
ctx.coinbase.get_market_trades(product_id: str, limit: int = 100) -> dictget_candles
Historical OHLCV.
ctx.coinbase.get_candles(
product_id: str,
granularity: str = "ONE_HOUR",
start: str = None,
end: str = None,
) -> dictgranularity | Values |
|---|---|
| Minutes | "ONE_MINUTE", "FIVE_MINUTE", "FIFTEEN_MINUTE", "THIRTY_MINUTE" |
| Hours | "ONE_HOUR", "TWO_HOUR", "SIX_HOUR" |
| Days | "ONE_DAY" |
candles = ctx.coinbase.get_candles("BTC-USD", granularity="ONE_HOUR")
closes = [float(c["close"]) for c in candles["candles"]]
sma = sum(closes[-20:]) / 20get_products
List all tradable products.
ctx.coinbase.get_products(product_type: str = None) -> dict
# product_type: "SPOT" | "FUTURE" | None (all)get_product
Detailed info for one product (price, status, base/quote, fees, increments).
ctx.coinbase.get_product(product_id: str) -> dictAccount & Portfolios
get_accounts
All your accounts (one per currency).
ctx.coinbase.get_accounts() -> dictReturns: {"accounts": [{"uuid", "currency", "available_balance": {"value", "currency"}, "hold": {"value", "currency"}, "type", "active", "ready", "default", ...}]}
get_portfolios
List portfolios (sub-accounts).
ctx.coinbase.get_portfolios(portfolio_type: str = None) -> dict
# portfolio_type: "DEFAULT" | "CONSUMER" | "INTX" | None (all)ports = ctx.coinbase.get_portfolios()
intx = next((p for p in ports["portfolios"] if p["type"] == "INTX"), None)get_transactions_summary
30-day fee tier, total volume, fees paid. Useful for figuring out which fee bracket you're in.
ctx.coinbase.get_transactions_summary() -> dicts = ctx.coinbase.get_transactions_summary()
ctx.log.info(f"Tier: {s['fee_tier']['pricing_tier']}, "
f"30d vol: ${s['total_volume']:.0f}, "
f"fees: ${s['total_fees']:.2f}")get_futures_balance_summary
Coinbase International (CFM) futures balance: total equity, available margin, position mode.
ctx.coinbase.get_futures_balance_summary() -> dictCFM only
Returns 404 if your account doesn't have CFM enabled. Check via get_portfolios() for an INTX portfolio.
Orders
place_order
Place a single order. Auto-builds the order_configuration based on order_type and side.
ctx.coinbase.place_order(
product_id: str,
side: str, # "BUY" | "SELL"
size: str, # for market BUY → quote size (USD); else → base size
order_type: str = "market", # "market" | "limit"
price: str = None, # required for limit
client_order_id: str = None, # auto UUID if omitted
) -> dict# Market buy $50 worth of BTC
r = ctx.coinbase.place_order("BTC-USD", "BUY", "50", "market")
# Limit sell 0.01 BTC @ $70000
r = ctx.coinbase.place_order(
product_id="BTC-USD", side="SELL", size="0.01",
order_type="limit", price="70000",
)Market BUY peculiarity
For a market BUY Coinbase expects a quote size (USD amount). For a market SELL or any limit order, it expects a base size (coin amount). The SDK passes size to the right field automatically.
preview_order
Preview an order without placing it. Returns expected totals, fees, slippage estimate, and validation errors. Use for sanity checks.
ctx.coinbase.preview_order(
product_id: str,
side: str,
size,
order_type: str = "market",
price: str = None,
) -> dictpreview = ctx.coinbase.preview_order("BTC-USD", "BUY", "50", "market")
if preview.get("errs"):
ctx.log.error(f"Validation: {preview['errs']}")
return
ctx.log.info(f"Will pay {preview['total_fees']} in fees, "
f"slippage est: {preview.get('best_price') or 'n/a'}")edit_order
Modify an unfilled limit order (size and/or price).
ctx.coinbase.edit_order(order_id: str, size: str = None, price: str = None) -> dictcancel_order
Cancel one or more orders.
ctx.coinbase.cancel_order(order_ids) -> dict
# order_ids: str | list[str]ctx.coinbase.cancel_order("abc-123-...") # single
ctx.coinbase.cancel_order(["a", "b", "c"]) # batchcancel_all_orders
Cancel ALL open orders, optionally filtered by product. Kill switch.
ctx.coinbase.cancel_all_orders(product_id: str = None) -> dict# Cancel everything across all products
ctx.coinbase.cancel_all_orders()
# Or scoped to one product
ctx.coinbase.cancel_all_orders("BTC-USD")close_position
Close a perpetual futures position immediately at market (CFM/INTX only).
ctx.coinbase.close_position(product_id: str, size: str = None) -> dictget_orders
List orders with optional filters.
ctx.coinbase.get_orders(product_id: str = None) -> dictWebSocket cache
PRO/MAX: cached from private WS at 0ms.
get_order_by_id
Status of a single order.
ctx.coinbase.get_order_by_id(order_id: str) -> dictget_fills
Trade fills (the actual transactions, with fees).
ctx.coinbase.get_fills(product_id: str = None, order_id: str = None) -> dictCommon Patterns
Sandbox during development
Set is_sandbox=true when adding the API key in Settings → API Keys → Coinbase. All worker calls auto-route to Coinbase Exchange's sandbox endpoint.
Error handling
def tick(ctx):
try:
accounts = ctx.coinbase.get_accounts()
except Exception as e:
ctx.log.error(f"Coinbase unreachable: {e}")
returnCoinbaseAPIError (extends ExchangeAPIError) is raised for API errors with code and msg. Network failures raise httpx.HTTPStatusError.
Cloud-Run proxy
PRO+ workers route Coinbase traffic through a Cloud Run proxy with rotating exit IPs. Transparent — no code changes.
WebSocket caching
PRO+ subscribes to public + private WS streams in the background. get_ticker and get_orders auto-prefer the cache when fresh.
Server-only
Coinbase Advanced Trade signing requires a PEM private key — not safe to expose to a browser. Workers must run in Server mode.
Recipes
Always-validate-before-trade pattern
def tick(ctx):
px = float(ctx.coinbase.get_ticker("BTC-USD")["price"])
target_quote = "100" # buy $100 worth
# 1. Preview first
preview = ctx.coinbase.preview_order("BTC-USD", "BUY", target_quote, "market")
if preview.get("errs"):
ctx.log.error(f"Skipping — preview errors: {preview['errs']}")
return
fees = float(preview.get("total_fees") or 0)
if fees > float(target_quote) * 0.005: # >0.5% fees
ctx.log.warn(f"Fees too high: ${fees:.2f}, skipping")
return
# 2. Now place for real
r = ctx.coinbase.place_order("BTC-USD", "BUY", target_quote, "market")
ctx.log.info(f"Bought $100 BTC @ ~${px}, order {r.get('order_id')}")Grid market making
def setup(ctx):
px = float(ctx.coinbase.get_ticker("BTC-USD")["price"])
step = px * 0.005 # 0.5% spacing
# Cancel any old grid first
ctx.coinbase.cancel_all_orders("BTC-USD")
for i in range(1, 6):
ctx.coinbase.place_order(
"BTC-USD", "BUY", "0.001", "limit",
price=str(round(px - i * step, 2)),
)
ctx.coinbase.place_order(
"BTC-USD", "SELL", "0.001", "limit",
price=str(round(px + i * step, 2)),
)
ctx.state.set("grid_price", px)
def tick(ctx):
px = float(ctx.coinbase.get_ticker("BTC-USD")["price"])
base = ctx.state.get("grid_price", px)
# Re-grid if price has moved >2% from grid centre
if abs(px - base) / base > 0.02:
ctx.log.info(f"Re-gridding around {px}")
setup(ctx)Spot momentum with VWAP-aware sizing
def tick(ctx):
candles = ctx.coinbase.get_candles("BTC-USD", granularity="ONE_HOUR")["candles"]
closes = [float(c["close"]) for c in candles[:24]]
sma_24 = sum(closes) / len(closes)
last = closes[0]
# Are we already long?
accs = ctx.coinbase.get_accounts()["accounts"]
btc = next((a for a in accs if a["currency"] == "BTC"), None)
has_pos = btc and float(btc["available_balance"]["value"]) >= 0.001
if last > sma_24 * 1.005 and not has_pos:
# Validate first, then trade
preview = ctx.coinbase.preview_order("BTC-USD", "BUY", "100", "market")
if not preview.get("errs"):
ctx.coinbase.place_order("BTC-USD", "BUY", "100", "market")
ctx.log.info(f"Long entry at {last}")
elif last < sma_24 * 0.995 and has_pos:
size = btc["available_balance"]["value"]
ctx.coinbase.place_order("BTC-USD", "SELL", size, "market")
ctx.log.info(f"Exit at {last}")Reference
| Coinbase endpoint | SDK method |
|---|---|
GET /api/v3/brokerage/products/{id}/ticker | get_ticker / get_market_trades |
GET /api/v3/brokerage/market/product_book | get_orderbook |
GET /api/v3/brokerage/best_bid_ask | get_best_bid_ask |
GET /api/v3/brokerage/products/{id}/candles | get_candles |
GET /api/v3/brokerage/products | get_products |
GET /api/v3/brokerage/products/{id} | get_product |
GET /api/v3/brokerage/accounts | get_accounts |
GET /api/v3/brokerage/portfolios | get_portfolios |
GET /api/v3/brokerage/transaction_summary | get_transactions_summary |
GET /api/v3/brokerage/cfm/balance_summary | get_futures_balance_summary |
POST /api/v3/brokerage/orders | place_order |
POST /api/v3/brokerage/orders/preview | preview_order |
POST /api/v3/brokerage/orders/edit | edit_order |
POST /api/v3/brokerage/orders/batch_cancel | cancel_order / cancel_all_orders |
POST /api/v3/brokerage/orders/close_position | close_position |
GET /api/v3/brokerage/orders/historical/batch | get_orders |
GET /api/v3/brokerage/orders/historical/{id} | get_order_by_id |
GET /api/v3/brokerage/orders/historical/fills | get_fills |