Quick Start
===========

This guide walks you through the five steps needed to place your first trade
on the O2 Exchange using the Python SDK.

.. seealso::

   For background on how the O2 Exchange works, see the
   `O2 Exchange documentation <https://docs.o2.app>`_.

Step 1: Initialize the client
-----------------------------

.. code-block:: python

   from o2_sdk import O2Client, Network

   client = O2Client(network=Network.TESTNET)

The client connects to the O2 testnet by default. Pass ``Network.MAINNET``
for production trading. You can also provide a custom
:class:`~o2_sdk.config.NetworkConfig` for private deployments.

Step 2: Create a wallet
-----------------------

.. code-block:: python

   # Fuel-native wallet
   owner = client.generate_wallet()
   print(owner.b256_address)  # 0x-prefixed, 66-character hex

   # — or load an existing private key —
   owner = client.load_wallet("0xabcd...1234")

The SDK supports both Fuel-native wallets and EVM-compatible wallets:

.. code-block:: python

   # EVM wallet (Ethereum-style address, zero-padded for Fuel)
   evm_owner = client.generate_evm_wallet()
   print(evm_owner.evm_address)    # 0x-prefixed, 42-character hex
   print(evm_owner.b256_address)   # zero-padded to 32 bytes

Use Fuel-native wallets for broad interop with other Fuel ecosystem apps.
Use EVM wallets when you want to reuse existing EVM accounts and simplify
bridging from EVM chains. O2 owner identity is always B256; for EVM wallets,
that B256 value is the EVM address zero-left-padded to 32 bytes.

.. warning::

   Never hard-code private keys in source code. Use environment variables or
   a secrets manager for production deployments.

Step 3: Set up a trading account
---------------------------------

.. code-block:: python

   account = await client.setup_account(owner)
   print(account.trade_account_id)

:meth:`~o2_sdk.client.O2Client.setup_account` is **idempotent** — it is safe
to call on every bot startup. It performs the following steps automatically:

1. Checks whether an account already exists for the wallet address.
2. Creates a new trading account if needed.
3. Mints test tokens via the faucet (testnet/devnet only).
4. Whitelists the account for trading.

Step 4: Create a trading session
--------------------------------

.. code-block:: python

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

A **session** delegates signing authority from your owner wallet to a
temporary session key. This allows the SDK to sign trade actions without
needing the owner key for every request. Sessions are scoped to specific
markets and expire after the specified number of days.

The returned session is stored as the client's active session. Trading
methods use it automatically unless you pass ``session=...`` explicitly.

.. note::

   Session creation uses ``personalSign`` (Fuel prefix + SHA-256 for
   Fuel-native wallets, or Ethereum prefix + keccak-256 for EVM wallets).
   Session *actions* use ``rawSign`` (plain SHA-256). The SDK handles this
   distinction automatically.

Step 5: Place an order
-----------------------

.. code-block:: python

   from o2_sdk import OrderSide, OrderType

   result = await client.create_order(
       market="fFUEL/fUSDC",
       side=OrderSide.BUY,
       price=0.02,
       quantity=100.0,
       order_type=OrderType.SPOT,
   )

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

Prices and quantities accept human-readable values (``"0.02"``, ``100.0``)
or explicit on-chain integers via :class:`~o2_sdk.models.ChainInt`. The SDK
scales and validates inputs against the market's constraints automatically.

Cleanup
-------

Always close the client when you are done:

.. code-block:: python

   await client.close()

Or use the async context manager:

.. code-block:: python

   async with O2Client(network=Network.TESTNET) as client:
       # ... your trading logic ...
       pass  # close() is called automatically

Complete example
----------------

.. code-block:: python

   import asyncio
   from o2_sdk import O2Client, Network, OrderSide

   async def main():
       async with O2Client(network=Network.TESTNET) as client:
           # Wallet + account
           owner = client.generate_wallet()
           account = await client.setup_account(owner)

           # Session
           session = await client.create_session(
               owner=owner,
               markets=["fFUEL/fUSDC"],
           )

           # Place order
           result = await client.create_order(
               "fFUEL/fUSDC", OrderSide.BUY,
               price=0.02, quantity=100.0,
           )
           print(f"tx_id={result.tx_id}")

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

   asyncio.run(main())

Next steps
----------

- :doc:`guides/trading` — Order types, batch actions, cancel/replace patterns
- :doc:`guides/market_data` — Fetching depth, trades, candles, and ticker data
- :doc:`guides/websocket_streams` — Real-time data with ``async for``
- :doc:`guides/identifiers` — Fuel vs EVM wallet choice and owner ID mapping
- :doc:`api/client` — Full API reference for :class:`~o2_sdk.client.O2Client`
