# Catalog & precision

Spot/Zipper catalogs, decimal strings, and scaled-integer inputs.

Every market has tick size, step size, and minimums. The SDK loads **spot** and **Zipper** catalogs so decimal inputs can be converted to wire integers safely.

## Wait for ready

Order and trigger **write** paths auto-await catalog hydration when `hydrate_catalogs=True` (default). You can still call this explicitly before reads that need symbol ids/scales:

```python
await client.wait_for_catalogs()
```

Hydration is fail-closed. `wait_for_catalogs` raises when a fetch fails. Empty catalogs can still break a write with `PolyesterValidationError`. See [Catalog](https://testnet.polyester.com/docs/sdk/python/reference/catalog).

## Decimal inputs

Use **decimal strings** (or `Price` / `Quantity`) for human-facing `qty` / `price`. **Do not pass floats**, binary floating point is not a financial representation. Strict decimal form is digits with an optional fractional part (`65000` / `65000.5`); bare trailing dots (`65000.`) are rejected. Leading/trailing whitespace is trimmed before validation.

Excess precision relative to the catalog should error; values are not silently rounded. Unscaled decimal quantities need a symbol (or an already-scaled `Quantity`) so the SDK can resolve catalog scale. Catalog lookups return `None` for unknown or unhydrated symbols; they never invent scale 8. Write paths raise `PolyesterValidationError` instead of guessing.

```python
await client.orders.create(
    symbol="BTC-USDT",
    side="buy",
    order_type="limit",
    tif="gtc",
    qty="0.01",
    price="64250.5",
    post_only=True,
)
```

> **post\_only is limit GTC only**
>
> `post_only=True` on market / IOC / FOK raises `PolyesterValidationError` before send.

## Protocol scale ceiling

Quantity and ledger formatters, parsers, and catalog hydration reject scales above `MAX_PROTOCOL_SCALE` (**36**). That ceiling is an SDK safety bound against pathological padding — it is **not** the ledger canonical scale. Ledger balances and `amount_e18` remain fixed at scale **18**. Trading quantity scales come from the spot catalog and are typically well below 36.

## Scaled integers (bots)

Stay in integer space when your strategy already works in wire units:

```python
from polyester import Price, Quantity

await client.orders.create(
    symbol="BTC-USDT",
    side="buy",
    order_type="limit",
    tif="gtc",
    qty=Quantity.from_scaled(1_000_000, scale=8),
    price=Price.from_ticks(100_000_000),  # protocol 1e6 ticks
    post_only=True,
)
```

Protocol **price ticks** use fixed 1e6 scale; that is not the same as market tick-size alignment (the server still validates tick size).

Also see [Scaled integers](https://testnet.polyester.com/docs/developer-docs/connectrpc/scaled-integers) and [Public IDs](https://testnet.polyester.com/docs/developer-docs/shared-concepts/public-ids).
