Skip to content
🌐Network: Mainnetâ–ŧ

Developer Quick Start - Python ​

Build your first o2 trade using the official Python SDK.

Prerequisites ​

  • Python 3.10–3.13 (3.14+ not yet supported due to dependency constraints)
  • pip install o2-sdk

AI Tools ​

Use AI assistants to help build and run your trading bot. See the Skills (gives AI agents the o2 integration workflow and patterns) and the MCP Server (trade via natural language).

1. Set Up Your Project ​

bash
mkdir o2-quickstart && cd o2-quickstart
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

pip install o2-sdk

Create your trading script:

bash
touch main.py

2. Get Test Funds ​

â„šī¸

Faucet is not available on mainnet. Deposit funds from your Fuel wallet to your trade account contract via the web-interface or via the Deposit flow.

3. Complete Trading Flow ​

Create main.py. The SDK handles network configuration, signing, encoding, and nonce management automatically.

Select your network (the SDK has built-in endpoints for each):

Network SelectionMainnet
from o2_sdk import Network
network = Network.TESTNET  # https://api.o2.app
python
import asyncio
from o2_sdk import Network, O2Client, OrderSide, OrderType

# Configuration
PRIVATE_KEY = "0xYOUR_PRIVATE_KEY"  # Use env vars in production!


async def main():
    # 1. Initialize client
    client = O2Client(network=Network.TESTNET)

    # 2. Load wallet
    # Use load_wallet() for an existing key, or generate_wallet() for a new one
    wallet = client.load_wallet(PRIVATE_KEY)
    print(f"Owner address: {wallet.b256_address}")

    # 3. Set up trading account
    # Idempotent: creates account, mints test tokens (testnet/devnet),
    # and whitelists — safe to call on every startup
    account = await client.setup_account(wallet)
    print(f"Trade account: {account.trade_account_id}")

    # Wait for faucet funds to settle
    await asyncio.sleep(5)

    # 4. Fetch markets
    markets = await client.get_markets()
    market = markets[0]
    pair = market.pair
    print(f"Trading on: {pair}")

    # 5. Check balances
    balances = await client.get_balances(account.trade_account_id)
    for symbol, bal in balances.items():
        print(f"{symbol}: {bal.trading_account_balance}")

    # 6. Create session
    # Delegates trading authority to an ephemeral keypair.
    # The session is stored on the client and used implicitly by trading methods.
    # o2 sponsors gas for all session-based actions.
    session = await client.create_session(
        owner=wallet,
        markets=[pair],
        expiry_days=30,
    )
    print(f"Session created, expires: {session.session_expiry}")

    # 7. Place an order
    # Prices and quantities are human-readable — the SDK auto-scales them.
    # SettleBalance is auto-prepended by default (settle_first=True).
    # Use a low price to avoid immediate fill; notional must be >= ~5 USDC.
    result = await client.create_order(
        market=pair,
        side=OrderSide.BUY,
        price="1",
        quantity="5",
        order_type=OrderType.SPOT,
    )
    print(f"Order tx: {result.tx_id}")

    if result.success and result.orders:
        order = result.orders[0]
        print(f"Order ID: {order.order_id}")

        # 8. Check open orders
        await asyncio.sleep(3)
        open_orders = await client.get_orders(
            account.trade_account_id,
            pair,
            is_open=True,
        )
        print(f"Open orders: {len(open_orders)}")

        # 9. Cancel order
        if open_orders:
            await client.cancel_order(
                order_id=open_orders[0].order_id,
                market=pair,
            )
            print("Order cancelled")

    # 10. Check final balance
    final_balances = await client.get_balances(account.trade_account_id)
    for symbol, bal in final_balances.items():
        print(f"{symbol}: {bal.trading_account_balance}")

    await client.close()
    print("Done!")


if __name__ == "__main__":
    asyncio.run(main())

Run the script:

bash
python main.py

4. Batch Orders ​

Submit up to 5 actions per request using the fluent builder.

Create a new session scoped to the batch market, refresh the nonce, then submit:

python
from o2_sdk import OrderSide, OrderType

await client.create_session(owner=wallet, markets=["fFUEL/fUSDC"], expiry_days=30)
await client.refresh_nonce()

batch = (
    client.actions_for("fFUEL/fUSDC")
    .settle_balance()
    .create_order(OrderSide.BUY, "0.1", "50")
    .create_order(OrderSide.BUY, "1", "5")
    .create_order(OrderSide.SELL, "2", "5", OrderType.POST_ONLY)
    .build()
)

result = await client.batch_actions([batch], collect_orders=True)
print(f"Batch tx: {result.tx_id}")
if result.orders:
    for order in result.orders:
        print(f"{order.side} order: {order.order_id}")

WARNING

create_order automatically prepends a SettleBalance call (controlled by settle_first, default True). When using batch_actions, add .settle_balance() explicitly if needed. The total action count (including settle) must not exceed 5.

5. Deposit & Withdraw ​

The easiest way to deposit and withdraw funds is through the o2 trading UI. The UI supports deposits from and withdrawals to EVM chains (Base, Ethereum) and Fuel wallets, and handles all bridging, wrapping, and unwrapping automatically.

Programmatic deposits & withdrawals coming soon

Fully integrated deposit and withdrawal support via the o2-sdk is currently in development.

In the meanwhile, if you want to go ahead, you can refer to the Fast Bridge docs and implement the deposit and withdrawal flow directly. For contract addresses and asset IDs, see the Network Identifiers page.

Key Concepts ​

ConceptDescription
Trading AccountOn-chain contract holding your balances and order state
SessionEphemeral keypair authorized to trade. Enables fast trading without wallet popups
NonceCounter for replay protection. Auto-managed by the SDK
Gas Sponsorshipo2 pays gas fees for all session-based actions
setup_account()Idempotent — creates account, funds via faucet, whitelists. Safe on every startup
SettleBalanceMoves filled order proceeds into your available balance. Auto-prepended by create_order

Nonce management

The SDK auto-manages nonces. If you encounter errors after a failed transaction, call refresh_nonce() to re-sync:

python
await client.refresh_nonce(session)

SDK Reference ​

For the full API reference, advanced patterns (market making, WebSocket streams, external signers), and more examples, see the SDK documentation on GitHub.