Metadata-Version: 2.4
Name: sory
Version: 5.3.2
Summary: Smart order routing and execution for crypto
Author-email: Manuel de Cara <manu.de.cara@gmail.com>
License: MIT License
        
        Copyright (c) 2024 Manuel de Cara
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
Project-URL: Documentation, https://github.com/manudc-scope/sory/tree/main/docs
Project-URL: Source, https://github.com/manudc-scope/sory
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: ccxt>=4.5.69
Requires-Dist: cryptography>=45.0.3
Requires-Dist: loguru>=0.7.3
Requires-Dist: pydantic>=2.11.5
Requires-Dist: python-dotenv>=1.1.1
Provides-Extra: betterstack
Requires-Dist: logtail-python>=0.3.3; extra == "betterstack"
Dynamic: license-file

# SORY

**A smart order router for crypto, in a Python package.**

One order book across every venue you trade, then execute against the best **all-in** price — fees
included. One config to get a consolidated book, one call to route an order.

```bash
pip install sory
```

---

## The whole integration

```python
import asyncio
from decimal import Decimal

from sory import SoryClient

config = {
    "licence_key": "...",
    "symbol": "BTC/USDT",
    "exchanges": ["binance", "okx", "bybit"],
    "fees_bps": "fees.toml",
    "fee_offset": {"binance": "taker", "okx": "taker", "bybit": "taker"},
}


async def main() -> None:
    async with SoryClient(config) as sory:
        # A consolidated, fee-adjusted book across all three venues.
        book = sory.book()
        print(book.best_bid.price, book.best_ask.price, book.best_ask.venue)

        # One call. SORY splits it across venues on best all-in price.
        order = await sory.place(side="buy", qty=Decimal("2"), order_type="market")
        print(order.filled, order.achieved_price, order.plan.allocations)


asyncio.run(main())
```

That is the integration. No adapters to write, no per-venue special cases, no WebSocket plumbing.

## What it does

Two things, well:

**Market data** — one consolidated order book across any number of venues, with your fees applied
where you ask, venue health tracked, VWAP depth and the trade tape on request.

**Execution** — a market order split across venues on best all-in price, or a limit order resting on
the venue you name, with a full account of what filled where and why.

It is deliberately not an OEMS. No balances, no positions, no PnL, no trade database. SORY plugs
into whatever already owns those — which is why it takes about ten minutes to drop into an existing
system.

## What people use it for

| | |
|---|---|
| **Best execution** | Sweep the consolidated book instead of guessing which venue is cheapest. |
| **Arbitrage and basis** | One book, every venue, fee-adjusted — the spread you see is the spread you get. |
| **Hedging** | Fill on one venue, hedge across the others in a single call. |
| **Market making** | Quote passively, hedge the fill in one call. |
| **Unwinds and liquidations** | Size against real aggregate depth, and see the remainder you could not fill. |
| **Execution algos** | TWAP, VWAP, POV — build the schedule, let SORY handle each slice. |
| **Research and monitoring** | Consolidated depth and the trade tape, as a normal Python stream. |

## Why fee-aware routing matters

Routing on quoted prices is routing on the wrong number:

```
venue A:  ask 100.00, your taker fee 20 bps  ->  all-in 100.200
venue B:  ask 100.05, your taker fee  1 bp   ->  all-in 100.060   <- actually cheaper
```

Venue A looks better and costs more. SORY compares all-in prices everywhere, using **your own**
fee tier from a config file — never a venue's published rate, which is usually the entry-level
tier and not what you pay.

## What you get

| | |
|---|---|
| **Consolidated book** | Any number of venues merged into one, fee-adjusted, best price first. |
| **Venue health** | `Online` / `Stale` / `Offline`. A silent feed is treated as a fault, not a quiet market — and never routed to. |
| **Fee-inclusive routing** | Splits on best all-in price, and reports every venue it considered, excluded, and why. |
| **One config** | One symbol per client. Two symbols is two clients, one line each. |
| **Full reconciliation** | `requested == filled + unfilled`, always, with a reason. Remainders are never silently dropped. |
| **VWAP depth** | The price to fill 1, 5, 10 units — and the limit price needed to achieve it. |
| **Unified liquidity** | Pool `BTC/USD`, `BTC/USDC` and `BTC/USDT` into one book. |
| **Trade tape** | Every venue, streamed in parallel with the book. |
| **`Decimal` throughout** | No float rounding anywhere near a price, size or fee. |
| **Dry run** | One flag on `place()`: routes, validates and builds every venue order, then stops before sending. |
| **Open orders** | Ask the venues what is still resting — the whole recovery story after a restart. |

## Venues

Binance, OKX, Bybit, Coinbase, Kraken, Bitget, KuCoin, Gate, HTX, Crypto.com, Bullish, Bitstamp,
Bitfinex, Hyperliquid and Deribit, among others — the [full list](docs/venues.mdx) is generated from
the registry, so it is never out of date.

Venue ids and symbols follow a single convention across all of them — `BTC/USDT` for spot,
`BTC/USDT:USDT` for a perp — so putting a venue on a card is one string. Omit `exchanges` entirely
and SORY uses every venue that lists the symbol. Need one that is not listed?
[Ask for it](mailto:manu.de.cara@gmail.com) — new venues land on almost every release.

## Try it

[playground.sory.pro](https://playground.sory.pro) — build a config and run it against live order
books, in your browser.

## Documentation

[introduction](docs/introduction.mdx) ·
[configuration](docs/configurations.mdx) ·
[market data](docs/market-data.mdx) ·
[routing](docs/routing.mdx) ·
[execution](docs/order-execution.mdx) ·
[fees](docs/fees.mdx) ·
[market making](docs/market-making.mdx) ·
[errors](docs/errors.mdx) ·
[venues](docs/venues.mdx) ·
[licensing](docs/licensing.mdx)

## Licence

SORY is commercial software, unlocked with a licence key — see
[licensing](docs/licensing.mdx). The source is MIT; see [LICENSE](LICENSE).
