> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sory.pro/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> From install to a routed order in five minutes.

<Steps>
  <Step title="Install" icon="download">
    ```bash theme={"dark"}
    pip install sory
    ```

    Python 3.11 or newer.
  </Step>

  <Step title="Set your licence key" icon="key">
    ```bash theme={"dark"}
    export SORY_LICENCE_KEY="..."
    ```

    Don't have one? [Request a key](mailto:manu.de.cara@gmail.com). See [Licensing](/licensing).
  </Step>

  <Step title="Write a fee schedule" icon="percent">
    SORY never guesses what you pay. Create `fees.toml` with your **negotiated** rates in basis points:

    ```toml fees.toml theme={"dark"}
    [binance]
    maker_bps = 1.0
    taker_bps = 4.0

    [okx]
    maker_bps = 2.0
    taker_bps = 5.0
    ```

    A missing entry is a startup error, never a silent zero. [More on fees](/fees).
  </Step>

  <Step title="Get a consolidated book" icon="layers">
    ```python theme={"dark"}
    import asyncio
    from sory import SoryClient

    config = {
        "market_data": {
            "exchanges": ["binance", "okx"],
            "symbols": ["BTC/USDT"],
            "aggregated": True,
        },
        "fees_bps": "fees.toml",
    }


    async def main():
        async with SoryClient(config=config) as sory:
            await asyncio.sleep(1)          # let the first books arrive

            book = sory.book("BTC/USDT")
            print(book.best_bid.price, book.best_ask.price, book.best_ask.venue)
            print(book.venues, book.excluded)


    asyncio.run(main())
    ```

    Prices are **all-in**: your fees are already applied. `excluded` names any venue that is not contributing, and why.
  </Step>

  <Step title="Route an order" icon="split">
    Add credentials for the venues you want to trade:

    ```bash theme={"dark"}
    export SORY_BINANCE_API_KEY="..." SORY_BINANCE_API_SECRET="..."
    ```

    Then place. SORY splits the order across venues on best all-in price:

    ```python theme={"dark"}
    from decimal import Decimal

    order = await sory.place(
        symbol="BTC/USDT",
        side="buy",
        qty=Decimal("2"),
        type="market",
        max_slippage_bps=15,
    )

    print(order.filled, order.achieved_price)
    for a in order.plan.allocations:
        print(a.venue, a.amount, a.expected_price)
    ```

    <Warning>
      Every order needs a price bound: a `price` for limit orders, `max_slippage_bps` for market orders. SORY will not sweep to arbitrary depth, and will not invent a bound for you.
    </Warning>
  </Step>

  <Step title="Try it without sending anything" icon="shield-check">
    Set `dry_run` and the whole path runs — routing, capability checks, rounding — without an order leaving the process:

    ```python theme={"dark"}
    config = {"market_data": {...}, "fees_bps": "fees.toml", "dry_run": True}
    ```

    Or just plan, and send nothing at all:

    ```python theme={"dark"}
    plan = sory.simulate(symbol="BTC/USDT", side="buy",
                         qty=Decimal("2"), max_slippage_bps=15)

    print(plan.expected_price, plan.allocations, plan.excluded)
    ```
  </Step>
</Steps>

## Next

<Columns cols={3}>
  <Card title="Configuration" icon="sliders" href="/configurations">
    Every option, one table.
  </Card>

  <Card title="Routing" icon="split" href="/routing">
    How allocation works.
  </Card>

  <Card title="Venues" icon="building-2" href="/venues">
    What's supported.
  </Card>
</Columns>
