Kraken SDK
Complete reference for ctx.kraken — programmatic spot and margin trading on Kraken from worker code.
Kraken REST + WebSocket v2
This SDK wraps the Kraken REST API with optional WebSocket v2 acceleration. WS-first methods fall back to REST automatically; REST-only methods always work.
Setup
- Add a Kraken trading block to your workspace canvas.
- Open the inspector → API Keys → pick a key (Settings → API Keys → Kraken to add new).
- Connect the block to your Worker block via an edge.
ctx.krakenis now available.
def tick(ctx):
t = ctx.kraken.get_ticker("XBTUSD")
ctx.log.info(f"BTC: {t}")If no Kraken block is connected:
RuntimeError: No trading block connected. Connect a Kraken block to this worker.Pairs
Kraken uses its own pair codes — sometimes the same as the common ticker, sometimes prefixed with X/Z (asset class). Examples:
| Common | Kraken pair |
|---|---|
| BTC/USD | XBTUSD |
| ETH/USD | ETHUSD |
| BTC/EUR | XBTEUR |
| SOL/USD | SOLUSD |
| Margin BTC/USD | XBT/USD |
Use get_asset_pairs to discover the canonical pair name for any market, plus its tick size, lot size, and trading status.
USD vs ZUSD
Kraken's "Z" prefix marks fiat assets (ZUSD, ZEUR). For account-level methods (get_trade_balance, get_ledgers) you typically pass ZUSD; for trading you use plain USD-suffix pair codes.
Market Data
get_ticker
Latest ticker for a pair.
ctx.kraken.get_ticker(pair: str = "XBTUSD") -> dictReturns: {"XXBTZUSD": {"a": [ask, w_lot, lot], "b": [bid, w_lot, lot], "c": [last_price, last_lot], "v": [vol_today, vol_24h], "p": [vwap_today, vwap_24h], "t": [trades_today, trades_24h], "l": [low_today, low_24h], "h": [high_today, high_24h], "o": open_today}}
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.kraken.get_orderbook(pair: str = "XBTUSD") -> dictget_ohlc
OHLCV candles.
ctx.kraken.get_ohlc(pair: str = "XBTUSD", interval: int = 1) -> dictinterval (minutes) | Description |
|---|---|
1, 5, 15, 30 | Intra-day |
60, 240 | Hourly / 4h |
1440 | Daily |
10080, 21600 | Weekly / 15-day |
get_recent_trades
Recent public trades for a pair.
ctx.kraken.get_recent_trades(pair: str = "XBTUSD", since: int = None) -> dictget_spread
Recent bid/ask spreads — useful for liquidity profiling.
ctx.kraken.get_spread(pair: str = "XBTUSD", since: int = None) -> dictget_asset_pairs
Tradable pair info: pair_decimals, lot_decimals, tick_size, ordermin, costmin, status.
ctx.kraken.get_asset_pairs(pair: str = None) -> dictAdapter caches this after first call — pair metadata rarely changes.
get_trades
Get recent trades from the WebSocket stream (PRO/MAX only).
ctx.kraken.get_trades(pair: str = "BTC/USD") -> dictget_system_status
Kraken-wide trading status.
ctx.kraken.get_system_status() -> dict
# Returns: {"status": "online" | "maintenance" | "cancel_only" | "post_only", "timestamp": ...}def tick(ctx):
s = ctx.kraken.get_system_status()
if s.get("status") != "online":
ctx.log.warn(f"Kraken {s.get('status')} — pausing")
return
# ... tradeAccount & Wallet
get_balance
Account balance per currency.
ctx.kraken.get_balance() -> dict
# {"ZUSD": "1234.56", "XXBT": "0.5", ...}WebSocket cache
PRO/MAX: cached from private WS at 0ms.
get_trade_balance
Margin info: equity, P&L, margin, free margin, margin level.
ctx.kraken.get_trade_balance(asset: str = "ZUSD") -> dictReturns: {"eb", "tb", "m", "n", "c", "v", "e", "mf", "ml"} (equity balance, trade balance, margin, unrealized P&L, cost basis, valuation, equity, free margin, margin level).
get_positions
Open margin positions.
ctx.kraken.get_positions() -> dictWebSocket cache
PRO/MAX: cached at 0ms.
get_ledgers
Account ledger — every deposit, withdrawal, trade, fee, transfer, settlement.
ctx.kraken.get_ledgers(
asset: str = None,
ledger_type: str = "all", # "all" | "deposit" | "withdrawal" | "trade" | "margin"
start: int = None,
end: int = None,
) -> dictOrders
place_order
Place an order. Supports market, limit, stop-loss, take-profit, and stop-loss-limit.
ctx.kraken.place_order(
pair: str,
side: str, # "buy" | "sell"
volume: float,
ordertype: str = "market", # "market" | "limit" | "stop-loss" | "take-profit" | "stop-loss-limit" | …
price: float = None,
leverage: float = None, # None = spot; 2-5 for margin
reduce_only: bool = False,
time_in_force: str = None, # "GTC" | "IOC" | "GTD"
post_only: bool = False,
cl_ord_id: str = None,
) -> dict# Spot market buy
r = ctx.kraken.place_order("XBTUSD", "buy", 0.001, "market")
# 3x margin long
r = ctx.kraken.place_order("XBTUSD", "buy", 0.01, "limit",
price=65000, leverage=3)WS-accelerated
In Server mode, orders route through Kraken's V2 WebSocket for ~10× faster acks than REST.
edit_order
Modify an unfilled order (volume / price). Keeps queue priority on the original timestamp.
ctx.kraken.edit_order(
order_id: str,
pair: str,
volume: float = None,
price: float = None,
post_only: bool = None,
) -> dictcancel_order
Cancel a single order by txid.
ctx.kraken.cancel_order(order_id: str) -> dictcancel_all_orders
Cancel ALL open orders (account-wide). Kill switch.
ctx.kraken.cancel_all_orders() -> dictbatch_add
Place up to 15 orders atomically.
ctx.kraken.batch_add(orders: list, pair: str, validate: bool = False) -> dictctx.kraken.batch_add(
pair="XBTUSD",
orders=[
{"ordertype": "limit", "type": "buy", "volume": "0.001", "price": "60000"},
{"ordertype": "limit", "type": "buy", "volume": "0.001", "price": "59000"},
{"ordertype": "limit", "type": "buy", "volume": "0.001", "price": "58000"},
],
)batch_cancel
Cancel multiple orders by txid.
ctx.kraken.batch_cancel(order_ids: list) -> dictget_orders
Active (open) orders.
ctx.kraken.get_orders() -> dictWebSocket cache
PRO/MAX: cached at 0ms.
query_orders
Detail of one or more specific orders by txid.
ctx.kraken.query_orders(txids, trades: bool = False) -> dictdetail = ctx.kraken.query_orders("OQCLML-BW3P3-BUCMWZ", trades=True)get_closed_orders
Closed (filled / cancelled / expired) orders.
ctx.kraken.get_closed_orders() -> dictget_trades_history
Trade fills with fees (the actual transactions, not just orders).
ctx.kraken.get_trades_history(
trade_type: str = "all", # "all" | "any position" | "closed position" | "closing position" | "no position"
start: int = None,
end: int = None,
) -> dictCommon Patterns
Error handling
def tick(ctx):
try:
balance = ctx.kraken.get_balance()
except Exception as e:
ctx.log.error(f"Kraken unreachable: {e}")
returnKrakenAPIError (extends ExchangeAPIError) wraps the array of strings Kraken returns in error[]. Network failures raise httpx.HTTPStatusError.
Cloud-Run proxy
PRO+ workers route Kraken traffic through a Cloud Run proxy with rotating exit IPs. Transparent — no code changes.
WebSocket-first
Almost every method has a WebSocket fast-path on PRO+:
| Method | WS path | REST fallback |
|---|---|---|
get_ticker, get_orderbook, get_trades | public stream cache | yes |
get_balance, get_positions, get_orders | private stream cache | yes |
place_order, cancel_order, edit_order | WS v2 add/cancel/amend | yes |
cancel_all_orders, batch_add, batch_cancel | WS v2 batch ops | yes (Phase 5) |
The adapter probes _ws_client per call — when WS is connected and authenticated, it routes through; otherwise REST.
System-status guard
Kraken regularly enters cancel_only or post_only modes during volatility. Always check before placing market orders:
def tick(ctx):
if ctx.kraken.get_system_status().get("status") != "online":
return
# safe to tradeRecipes
DCA on hourly close (with status guard)
def setup(ctx):
ctx.state.set("last_buy_ts", 0)
def tick(ctx):
import time
now = int(time.time())
if now - ctx.state.get("last_buy_ts", 0) < 3600:
return
if ctx.kraken.get_system_status().get("status") != "online":
ctx.log.warn("Kraken not online, deferring buy")
return
px = float(ctx.kraken.get_ticker("XBTUSD")["XXBTZUSD"]["c"][0])
qty = round(50 / px, 5) # $50 worth
r = ctx.kraken.place_order("XBTUSD", "buy", qty, "market")
ctx.state.set("last_buy_ts", now)
ctx.log.info(f"DCA: {qty} BTC @ {px} → {r}")Layered grid with batch placement
def setup(ctx):
# Always cancel any leftovers from a previous run
ctx.kraken.cancel_all_orders()
px = float(ctx.kraken.get_ticker("XBTUSD")["XXBTZUSD"]["c"][0])
step = px * 0.005
orders = []
for i in range(1, 6):
orders.append({
"ordertype": "limit", "type": "buy",
"volume": "0.001",
"price": str(round(px - i * step, 1)),
})
orders.append({
"ordertype": "limit", "type": "sell",
"volume": "0.001",
"price": str(round(px + i * step, 1)),
})
ctx.kraken.batch_add(orders, pair="XBTUSD")
ctx.state.set("grid_centre", px)
ctx.log.info(f"Grid placed around ${px:.0f}")Spread-aware market making
def tick(ctx):
spreads = ctx.kraken.get_spread("XBTUSD")["XXBTZUSD"]
if not spreads:
return
bid, ask, _ = spreads[-1] # last record: [bid, ask, ts]
spread_bps = (float(ask) - float(bid)) / float(bid) * 10000
if spread_bps > 5:
ctx.log.info(f"Spread {spread_bps:.1f} bps > target — quoting inside")
# ... place limit orders inside the spread
else:
ctx.log.info(f"Spread tight ({spread_bps:.1f} bps) — staying out")Reference
| Kraken endpoint | SDK method |
|---|---|
GET /0/public/Ticker | get_ticker |
GET /0/public/Depth | get_orderbook |
GET /0/public/OHLC | get_ohlc |
GET /0/public/Trades | get_recent_trades |
GET /0/public/Spread | get_spread |
GET /0/public/AssetPairs | get_asset_pairs |
GET /0/public/SystemStatus | get_system_status |
POST /0/private/Balance | get_balance |
POST /0/private/TradeBalance | get_trade_balance |
POST /0/private/OpenPositions | get_positions |
POST /0/private/Ledgers | get_ledgers |
POST /0/private/AddOrder | place_order |
POST /0/private/EditOrder | edit_order |
POST /0/private/CancelOrder | cancel_order |
POST /0/private/CancelAll | cancel_all_orders |
POST /0/private/AddOrderBatch | batch_add |
POST /0/private/CancelOrderBatch | batch_cancel |
POST /0/private/OpenOrders | get_orders |
POST /0/private/QueryOrders | query_orders |
POST /0/private/ClosedOrders | get_closed_orders |
POST /0/private/TradesHistory | get_trades_history |