Python SDK — taifoon_clob
taifoon_clob (client.py + models.py). Vendor it from the orderbook repo at scripts/sdk/taifoon_clob/, or once the PyPI release lands pip install taifoon-clob. No third-party deps — standard library only.Quickstart
from taifoon_clob import TaifoonClient
c = TaifoonClient(attribution="my-bot") # base_url defaults to https://api.taifoon.dev
bars = c.get_ohlc("BTC", "15s") # market data (no auth)
ack = c.add_order("BTC", "buy", 0.01) # place a market order
c.close_position("BTC") # reduce-only close (Kraken idiom)Construction: TaifoonClient(base_url="https://api.taifoon.dev", attribution="sdk-paper", session=None, timeout=15). attribution tags your orders/fills (your "account" on the shared book); session scopes reads/trades to a warp-replay session (for backtests).
ApiError(error, body, status) — branch with isinstance(r, ApiError).Coming from Kraken?
Every Kraken method maps to a Taifoon SDK method and a CLOB endpoint:
Kraken SDK Taifoon SDK Endpoint
─────────────────────────────────────────────────────────────────
OHLC → get_ohlc() → GET /tape/v1/candles/:m/:tf
AssetPairs → markets() → GET /book/v1/markets
Ticker → ticker() → GET /tape/v1/ticker/:m (+ /mark)
Depth → depth() → GET /book/v1/depth/:m
Time → clock() → GET /tape/v1/clock
AddOrder → add_order() → POST /book/v1/orders
CancelOrder → cancel_order() → DEL /book/v1/orders/:id
(close = reduceOnly)→ close_position() → POST /book/v1/orders {reduce_only}
OpenPositions → open_positions() → GET /book/v1/positions
TradesHistory → fills() → GET /book/v1/fills
- Taifoon-only -------------------------------------------------
add_stop() → POST /book/v1/stops
add_option() → POST /book/v1/options
mint_session() ... → POST /tape/v1/sessions (+ replay)Market data (Kraken "public" — no attribution)
get_ohlc(pair, interval="1m", since=None, to=None, limit=None) — ≈ Kraken OHLC
OHLCV candles, oldest-first. interval accepts both Kraken int-minutes (1 · 5 · 15 · 60 · 240 · 1440) and tf strings (15s · 1m · 5m · 15m · 1h · 4h · 1d) — so Kraken code is drop-in; 15s is the sub-minute extension. since/to are unix seconds (omit for the latest window). Returns list[Candle(t, o, h, l, c, v)].
bars = c.get_ohlc("BTC", "15s", since=1780300000, to=1780900000)
print(bars[-1].t, bars[-1].c) # latest bar-open, close
c.get_ohlc("BTC", 1) # Kraken int-minutes also work
c.get_ohlc("NQ", "1m") # futures toomarkets() / asset_pairs() / get_asset_pairs() — ≈ Kraken AssetPairs
The tradeable registry. Returns list[Market(market_id, asset, source, status, t_open)].
for m in c.markets():
print(m.market_id, m.status) # BTC-PERP open, NQ-PERP open, ...ticker(pair) / get_ticker(pair) — ≈ Kraken Ticker
Top-of-book + mark. Returns Ticker(bid_px, ask_px, bid_qty, ask_qty, mark) with a .mid property.
t = c.ticker("BTC")
print(t.bid_px, t.ask_px, t.mid)depth(pair) / get_order_book(pair, count=None) — ≈ Kraken Depth
L2 book: {"bids": [[px, qty], ...], "asks": [...]}. get_order_book(count=N) truncates each side to the top-N levels (matching Kraken's count).
d = c.depth("BTC-PERP")
print(d["bids"][0], d["asks"][0])
top = c.get_order_book("BTC", count=5) # Kraken-name + countfunding(pair), stats(pair), and clock() / get_system_status() / get_server_time() (≈ Kraken Time) round out the read surface.
get_ohlc, get_asset_pairs / get_assets, get_ticker, get_order_book, get_recent_trades (≈ TradesHistory → our fills), get_system_status / get_server_time.Trading (Kraken "private" — carries attribution)
add_order(pair, side, qty, price=None, tif="gtc", reduce_only=False) — ≈ Kraken AddOrder
Omit price for a market order. side ∈ buy · sell; tif ∈ gtc · ioc · fok · post. Returns OrderAck(order_id, mode, .ok).
ack = c.add_order("BTC", "buy", 0.01) # market buy
ack = c.add_order("BTC", "sell", 0.01, price=75000, tif="post") # resting limit
if ack.ok: print(ack.order_id)cancel_order(order_id) — ≈ Kraken CancelOrder
c.cancel_order(ack.order_id)
close_position(pair, qty=None) — the Kraken close idiom
Closes (or reduces) an open position by placing a reduce_only MARKET order on the opposite side — exactly how you close on Kraken futures. Reads open_positions() to size it; pass qty for a partial close.
c.add_order("BTC", "buy", 0.5) # long 0.5
c.close_position("BTC") # reduce_only sell 0.5 (flat)
c.close_position("BTC", qty=0.2) # partialClosing orders & futures options
add_stop(pair, side, trigger_price, qty, reduce_only=True) / cancel_stop(id)
A stop-loss / take-profit trigger order. reduce_only=True (default) makes it a protective exit that can only shrink a position.
# protect a long: stop-sell if price drops to 74000
c.add_stop("BTC", "sell", trigger_price=74000, qty=0.5)add_option(pair, side, qty, opt_type="AUTO", strike=0, expiry="")
Buy/sell a futures option. opt_type AUTO (infers from side) · CALL · PUT; strike=0 = ATM; expiry="" = NEAREST.
c.add_option("NQ", "buy", 1) # nearest ATM call
c.add_option("NQ", "buy", 1, opt_type="PUT", strike=21000, expiry="2026-06-20")Positions & fills
open_positions() — ≈ Kraken OpenPositions · fills(pair=None, since=None) — ≈ TradesHistory
for p in c.open_positions():
print(p.market, p.side, p.qty, p.unrealized_pnl)
for f in c.fills("BTC", since=1780900000):
print(f.t, f.side, f.qty, f.price)Replay & backtest (Taifoon-only — beyond Kraken)
Drive a strategy over historical candles in the warp partition (never touches the live book):
sid = c.mint_session("BTC", frm=1780300000, to=1780386400, speed_x=1000)
c.start_replay(sid, "BTC", 1780300000, 1780386400,
cubicle_url="http://localhost:5055/decide",
cubicle_algo="skydweller_v2")
c.replay_status(sid)
c.session_fills(sid) # synth fills the strategy produced
c.receipt(sid) # 3-actor causality receipt (causality_ok)End-to-end example
Candles → decide → order → close, entirely through the SDK (scripts/sdk/examples/skydweller_session.py):
from taifoon_clob import TaifoonClient
c = TaifoonClient(attribution="my-bot")
bars = c.get_ohlc("BTC", "1m", since=t0, to=t1)
for b in bars:
fire = my_strategy(b) # your decide()
if fire:
c.add_order("BTC", fire.side, 0.01)
c.close_position("BTC")
print([(f.side, f.price) for f in c.fills("BTC")])