TaifoonTAIFOON
Taifoon · Docs
SDK

Python SDK — taifoon_clob

A Kraken-parity client for the Taifoon CLOB: candles, markets, trades, closing, futures-options, and the replay/backtest surface. Stdlib-only (no dependencies). If you've used python-kraken-sdk, every method has a 1:1 equivalent.
Note
The SDK is the module 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).

Note
Errors are returned, not raised. A non-2xx response yields an 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 too

markets() / 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 + count

funding(pair), stats(pair), and clock() / get_system_status() / get_server_time() (≈ Kraken Time) round out the read surface.

Note
Kraken-exact aliases. Every python-kraken-sdk Spot Market method name is present as an alias so Kraken code is drop-in: 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) # partial

Closing 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")])
Note
Per-endpoint request/response/error detail lives under API → Orders / Positions / Tape / Stops / Options. The TypeScript SDK mirrors this surface; see SDKs → TypeScript.