O2Client — High-level client

The O2Client class is the primary entry point for interacting with the O2 Exchange. It orchestrates wallet management, account lifecycle, session management, trading, market data retrieval, and WebSocket streaming.

See also

The O2 Exchange platform documentation at https://docs.o2.app covers the underlying REST and WebSocket APIs that this client wraps.

Construction and lifecycle

class o2_sdk.client.O2Client(network=Network.TESTNET, custom_config=None)[source]

High-level client for the O2 Exchange.

Parameters:
  • network (Network) – Which network to connect to.

  • custom_config (NetworkConfig | None) – Optional custom network configuration, overriding the built-in config for the selected network.

The client manages an HTTP session (via aiohttp) and an optional WebSocket connection for streaming. Always call close() when done, or use the async context manager:

async with O2Client(network=Network.TESTNET) as client:
    ...
api: O2Api

The low-level REST API client. Exposed for advanced use cases where you need direct access to individual API endpoints.

async O2Client.close()[source]

Close all HTTP and WebSocket connections.

Always call this method when you are done using the client.

Wallet management

These static methods create or load wallet objects. No network calls are required.

static O2Client.generate_wallet()[source]

Generate a new Fuel-native wallet with a random private key.

Returns:

A new wallet with private_key, public_key, and b256_address populated.

Return type:

Wallet

owner = O2Client.generate_wallet()
# or equivalently:
owner = client.generate_wallet()
static O2Client.generate_evm_wallet()[source]

Generate a new EVM-compatible wallet with a random private key.

The wallet derives both an Ethereum-style address (keccak-256) and a Fuel B256 address (the EVM address zero-padded to 32 bytes).

Returns:

A new wallet with private_key, public_key, evm_address, and b256_address populated.

Return type:

EvmWallet

evm_owner = client.generate_evm_wallet()
print(evm_owner.evm_address)   # 0x-prefixed, 42 chars
print(evm_owner.b256_address)  # 0x-prefixed, 66 chars (zero-padded)
static O2Client.load_wallet(private_key_hex)[source]

Load a Fuel-native wallet from an existing private key.

Parameters:

private_key_hex (str) – The private key as a hex string (with or without 0x prefix).

Returns:

The reconstructed wallet.

Return type:

Wallet

static O2Client.load_evm_wallet(private_key_hex)[source]

Load an EVM-compatible wallet from an existing private key.

Parameters:

private_key_hex (str) – The private key as a hex string (with or without 0x prefix).

Returns:

The reconstructed wallet.

Return type:

EvmWallet

Account lifecycle

async O2Client.setup_account(wallet)[source]

Set up a trading account idempotently.

This method performs the complete account setup flow:

  1. Check if a trading account already exists for the wallet address.

  2. Create a new account if needed (POST /v1/accounts).

  3. Mint test tokens via the faucet (testnet/devnet only; non-fatal if the faucet is on cooldown).

  4. Whitelist the account for trading (idempotent; non-fatal on error).

Safe to call on every bot startup.

Parameters:

wallet (Signer) – The owner wallet (Fuel or EVM).

Returns:

Account info including the trade_account_id.

Return type:

AccountInfo

account = await client.setup_account(owner)
print(account.trade_account_id)
print(account.exists)  # True

Session management

async O2Client.create_session(owner, markets, expiry_days=30)[source]

Create a new trading session.

A session delegates signing authority from the owner wallet to a temporary session key, scoped to specific market contracts. The session key is used to sign all subsequent trade actions.

Parameters:
  • owner (Signer) – The owner wallet or external signer.

  • markets (list[str | Market]) – List of market pairs/IDs or Market objects.

  • expiry_days (int) – Session expiry in days (default 30).

Returns:

Session info with the session key, account ID, and authorized contract IDs.

Return type:

SessionInfo

Raises:

O2Error – If the account does not exist (call setup_account() first).

session = await client.create_session(
    owner=owner,
    markets=["fFUEL/fUSDC"],
    expiry_days=7,
)
O2Client.session: :class:`~o2_sdk.models.SessionInfo` | None

The active session stored on the client.

O2Client.set_session(session)[source]

Set the active session used by trading methods when session= is not passed explicitly.

O2Client.clear_session()[source]

Clear the currently active session.

Trading

async O2Client.create_order(market, side, price, quantity, order_type=OrderType.SPOT, settle_first=True, collect_orders=True, session=None)[source]

Place an order with automatic encoding, signing, and nonce management.

Prices and quantities accept normalized numeric inputs (str, int, float, Decimal, or ChainInt) and are automatically converted to on-chain integers based on market precision. The SDK validates orders against on-chain constraints.

Parameters:
  • market (str | Market) – Market pair (e.g., "FUEL/USDC"), market_id, contract_id, or Market.

  • side (OrderSide) – The order side.

  • price (str | int | float | Decimal | ChainInt) – Price input in human units, or explicit raw chain integer via ChainInt.

  • quantity (str | int | float | Decimal | ChainInt) – Quantity input in human units, or explicit raw chain integer via ChainInt.

  • order_type (OrderType | LimitOrder | BoundedMarketOrder) – The order type. Use OrderType enum for simple types (SPOT, MARKET, FILL_OR_KILL, POST_ONLY), LimitOrder for limit orders, or BoundedMarketOrder for bounded market orders.

  • settle_first (bool) – If True (default), prepend a SettleBalance action to reclaim filled proceeds before placing the order.

  • collect_orders (bool) – If True (default), the response includes details of the created order.

  • session (SessionInfo | None) – Optional explicit session override. If omitted, the client’s active session is used.

Returns:

The action result including tx_id and optional orders.

Return type:

ActionsResponse

Order types:

from o2_sdk import OrderSide, OrderType, LimitOrder, BoundedMarketOrder

# Spot (default) — rests on the book
await client.create_order("fFUEL/fUSDC", OrderSide.BUY, 0.02, 100.0)

# PostOnly — rejected if it would match immediately
await client.create_order(
    "fFUEL/fUSDC", OrderSide.BUY, 0.02, 100.0,
    order_type=OrderType.POST_ONLY,
)

# BoundedMarket — market order with price bounds
await client.create_order(
    "fFUEL/fUSDC", OrderSide.BUY, 0.025, 100.0,
    order_type=BoundedMarketOrder(max_price=0.03, min_price=0.01),
)

# Limit — with expiry timestamp
import time
await client.create_order(
    "fFUEL/fUSDC", OrderSide.BUY, 0.02, 100.0,
    order_type=LimitOrder(price=0.025, timestamp=int(time.time())),
)
async O2Client.cancel_order(order_id, market=None, market_id=None, session=None)[source]

Cancel a specific order.

Either market (pair string) or market_id (hex ID) must be provided.

Parameters:
  • order_id (str) – The 0x-prefixed order ID to cancel.

  • market (str | None) – Market pair string (e.g., "FUEL/USDC").

  • market_id (str | None) – Market ID (hex string).

  • session (SessionInfo | None) – Optional explicit session override. If omitted, the client’s active session is used.

Returns:

The action result.

Return type:

ActionsResponse

Raises:

ValueError – If neither market nor market_id is provided.

async O2Client.cancel_all_orders(market, session=None)[source]

Cancel all open orders for a market.

Fetches up to 200 open orders and cancels them in batches of 5. Returns a list of ActionsResponse (one per batch), or an empty list if there are no open orders.

Parameters:
  • market (str | Market) – Market pair string or Market.

  • session (SessionInfo | None) – Optional explicit session override. If omitted, the client’s active session is used.

Returns:

A list of action results (one per batch of up to 5 cancellations), or an empty list if there are no open orders.

Return type:

list[ActionsResponse]

async O2Client.settle_balance(market, session=None)[source]

Settle filled order proceeds for a market.

After your orders are filled, the proceeds remain locked in the order book contract until you settle them back to your trading account. The create_order() method does this automatically when settle_first=True (the default).

Parameters:
  • market (str | Market) – Market pair string or Market.

  • session (SessionInfo | None) – Optional explicit session override. If omitted, the client’s active session is used.

Returns:

The action result.

Return type:

ActionsResponse

async O2Client.batch_actions(actions, collect_orders=False, session=None)[source]

Submit a batch of typed actions with automatic signing and nonce management.

Actions are submitted as typed market groups (MarketActions) or fluent request groups (MarketActionGroup). The O2 Exchange supports a maximum of 5 actions per request.

Parameters:
  • actions (Sequence[MarketActions | MarketActionGroup]) – A list of action groups.

  • collect_orders (bool) – If True, return created order details.

  • session (SessionInfo | None) – Optional explicit session override. If omitted, the client’s active session is used.

Returns:

The action result.

Return type:

ActionsResponse

Raises:

SessionExpired – If the session has expired.

from o2_sdk import (
    CancelOrderAction, CreateOrderAction, SettleBalanceAction,
    MarketActions, OrderSide, OrderType,
)

result = await client.batch_actions(
    actions=[MarketActions(
        market_id=market.market_id,
        actions=[
            SettleBalanceAction(to=session.trade_account_id),
            CancelOrderAction(order_id=Id("0xabc...")),
            CreateOrderAction(
                side=OrderSide.BUY,
                price="25000",
                quantity="100000000000",
                order_type=OrderType.SPOT,
            ),
        ],
    )],
    collect_orders=True,
)
O2Client.actions_for(market)[source]

Return a fluent MarketActionsBuilder for high-level action construction.

Parameters:

market (str | Market) – Market pair string, market identifier, or Market object.

Returns:

Builder for chained action creation.

Return type:

MarketActionsBuilder

Market data

async O2Client.get_markets()[source]

Get all available markets on the exchange.

Results are cached for the lifetime of the client.

Returns:

List of all market definitions.

Return type:

list[Market]

async O2Client.get_market(symbol_pair)[source]

Get a specific market by its pair symbol.

Parameters:

symbol_pair (str) – The trading pair (e.g., "FUEL/USDC" or "fFUEL/fUSDC").

Returns:

The market definition.

Return type:

Market

Raises:

O2Error – If the market is not found.

async O2Client.get_depth(market, precision=1)[source]

Get the current order book depth snapshot for a market.

Parameters:
  • market (str | Market) – Market pair string, market ID, or Market object.

  • precision (int) – Price aggregation precision (default 1, most precise).

Returns:

The depth snapshot with buys, sells, best_bid, and best_ask.

Return type:

DepthSnapshot

depth = await client.get_depth("fFUEL/fUSDC", precision=1)
if depth.best_bid:
    print(f"Best bid: {depth.best_bid.price}")
if depth.best_ask:
    print(f"Best ask: {depth.best_ask.price}")
async O2Client.get_trades(market, count=50)[source]

Get recent trades for a market.

Parameters:
  • market (str | Market) – Market pair string, market ID, or Market object.

  • count (int) – Number of trades to retrieve (default 50).

Returns:

List of recent trades, most recent first.

Return type:

list[Trade]

async O2Client.get_bars(market, resolution, from_ts, to_ts)[source]

Get OHLCV candlestick bars for a market.

Parameters:
  • market (str | Market) – Market pair string, market ID, or Market object.

  • resolution (str) – Candle resolution (e.g., "1m", "5m", "1h", "1d").

  • from_ts (int) – Start timestamp in milliseconds (not seconds).

  • to_ts (int) – End timestamp in milliseconds (not seconds).

Returns:

List of OHLCV bars.

Return type:

list[Bar]

import time
now_ms = int(time.time() * 1000)
bars = await client.get_bars(
    "fFUEL/fUSDC",
    resolution="1h",
    from_ts=now_ms - 86_400_000,  # last 24 hours
    to_ts=now_ms,
)
for bar in bars:
    print(f"{bar.time}: O={bar.open} H={bar.high} L={bar.low} C={bar.close} V={bar.volume}")
async O2Client.get_ticker(market)[source]

Get real-time ticker data for a market.

Parameters:

market (str) – Market pair string or market ID.

Returns:

Raw ticker data dict.

Return type:

dict

Account data

async O2Client.get_balances(account)[source]

Get balances for all known assets, keyed by asset symbol.

Iterates over all markets to discover assets, then queries the balance for each unique asset.

Parameters:

account (AccountInfo | str) – An AccountInfo object or a trade_account_id string.

Returns:

A dict mapping asset symbol to balance info.

Return type:

dict[str, Balance]

balances = await client.get_balances(account)
for symbol, bal in balances.items():
    print(f"{symbol}: available={bal.trading_account_balance}")
async O2Client.get_orders(market, account, is_open=None, count=20)[source]

Get orders for an account on a market.

Parameters:
  • market (str) – Market pair string.

  • account (AccountInfo | str) – An AccountInfo object or a trade_account_id string.

  • is_open (bool | None) – Filter by open/closed status. None returns all.

  • count (int) – Maximum number of orders to return (default 20).

Returns:

List of orders, most recent first.

Return type:

list[Order]

async O2Client.get_order(market, order_id)[source]

Get a specific order by its ID.

Parameters:
  • market (str) – Market pair string.

  • order_id (str) – The 0x-prefixed order ID.

Returns:

The order details.

Return type:

Order

WebSocket streaming

All streaming methods return async iterators that yield typed update objects. The underlying WebSocket connection is created lazily on first use and supports automatic reconnection with exponential backoff.

async O2Client.stream_depth(market, precision=1)[source]

Stream real-time order book depth updates.

The first message is a full snapshot; subsequent messages are incremental updates.

Parameters:
  • market (str) – Market pair string.

  • precision (int) – Price aggregation precision (default 1, most precise).

Returns:

An async iterator of depth updates.

Return type:

AsyncIterator[DepthUpdate]

async for update in client.stream_depth("fFUEL/fUSDC"):
    if update.is_snapshot:
        print(f"Snapshot: {len(update.changes.bids)} bids, {len(update.changes.asks)} asks")
    else:
        print(f"Update: best_bid={update.changes.best_bid}")
async O2Client.stream_orders(account)[source]

Stream real-time order updates for an account.

Parameters:

account (AccountInfo | str) – An AccountInfo object or a trade_account_id string.

Returns:

An async iterator of order updates.

Return type:

AsyncIterator[OrderUpdate]

async O2Client.stream_trades(market)[source]

Stream real-time trade updates for a market.

Parameters:

market (str) – Market pair string.

Returns:

An async iterator of trade updates.

Return type:

AsyncIterator[TradeUpdate]

async O2Client.stream_balances(account)[source]

Stream real-time balance updates for an account.

Parameters:

account (AccountInfo | str) – An AccountInfo object or a trade_account_id string.

Returns:

An async iterator of balance updates.

Return type:

AsyncIterator[BalanceUpdate]

async O2Client.stream_nonce(account)[source]

Stream real-time nonce updates for an account.

Useful for monitoring nonce changes caused by other sessions or external transactions.

Parameters:

account (AccountInfo | str) – An AccountInfo object or a trade_account_id string.

Returns:

An async iterator of nonce updates.

Return type:

AsyncIterator[NonceUpdate]

Withdrawals

async O2Client.withdraw(owner, asset, amount, to=None)[source]

Withdraw funds from the trading account to an external address.

This method signs the withdrawal with the owner key (using personalSign), not the session key.

Parameters:
  • owner (Signer) – The owner wallet or external signer.

  • asset (str) – Asset symbol (e.g., "USDC") or asset ID.

  • amount (float) – Human-readable amount to withdraw.

  • to (str | None) – Destination address. Defaults to the owner’s address.

Returns:

The withdrawal result.

Return type:

WithdrawResponse

result = await client.withdraw(owner=owner, asset="fUSDC", amount=10.0)
if result.success:
    print(f"Withdrawal tx: {result.tx_id}")

Nonce management

async O2Client.get_nonce(trade_account_id)[source]

Get the current nonce for a trading account.

Returns the cached value if available; otherwise fetches from the API.

Parameters:

trade_account_id (str) – The trading account contract ID.

Returns:

The current nonce.

Return type:

int

async O2Client.refresh_nonce(session)[source]

Re-fetch the nonce from the API and update the local cache.

Call this after catching an error from batch_actions() if you suspect the nonce is out of sync (the SDK does this automatically on error).

Parameters:

session (SessionInfo) – The session whose nonce to refresh.

Returns:

The refreshed nonce.

Return type:

int