# Live market ticker

Stream tickers, candles, and a live order book with no authentication, using the shared realtime contract.

Smallest path into the SDK. Build a live ticker on Polyester devnet with public market data only. No keys, wallets, or sessions. By the end you will know the realtime contract every stream shares.

About ten minutes.

> **No credentials needed**
>
> Every service in this tutorial is public. An unauthenticated `PolyesterClient` can call all of it.

1. Create a public client

   Install the SDK and create a client against the devnet environment. With no `auth` option, the client can still read all public market data.

   ```ts
   // ticker.ts
   import { PolyesterClient, POLYESTER_DEVNET_ENVIRONMENT } from "@polyester/sdk";

   const client = new PolyesterClient({ environment: POLYESTER_DEVNET_ENVIRONMENT });

   await client.catalog.ensureReady();
   const SYMBOL = "BTC-USDT";
   const symbolId = client.catalog.market.requireSymbolIdByPairSymbol(SYMBOL);
   ```

   Trading and market-data streams use the stable numeric `symbolId`. Resolve it from the pair symbol through the [catalog](https://testnet.polyester.com/docs/sdk/typescript/reference/catalog).

2. Stream the market overview

   The market overview is one row per market with last price and 24h stats. Its stream is snapshot-then-stream: it fetches the full set first, then merges live updates and emits the merged array. It also refetches automatically on reconnect, so you always render a consistent table.

   ```ts
   const overviewUnsub = client.marketOverview.subscribe({
   	onEvent: (markets) => {
   		const top = markets.slice(0, 5);
   		for (const m of top) {
   			const symbol = client.catalog.market.requirePairSymbolBySymbolId(m.symbolId);
   			console.log(symbol, m.lastPrice);
   		}
   	},
   	onError: (ctx) => console.error("overview error", ctx.error),
   });
   ```

   Every stream method follows the same shape: pass an `onEvent` handler (plus optional `onOpen`, `onClose`, and `onError`), and you get back an idempotent unsubscribe function.

3. Add a live candle feed

   Subscribe to one-minute candles for your symbol. Handlers receive fully parsed objects with decimal strings, the same shapes the request methods return.

   ```ts
   const candleUnsub = client.candles.subscribe({
   	symbolId,
   	timeframe: "1m",
   	onEvent: (candle) => console.log("candle close", candle.close),
   	onError: (ctx) => console.error("candle error", ctx.error),
   });
   ```

   You can seed history first with `client.candles.list({ symbolId, timeframe: "1m", limit: 60 })`, then let the stream keep it current.

4. Render a live order book

   `createSubscription` maintains a local order book: initial snapshot, sequence-checked deltas, and refetch after an observed sequence gap or reconnect. Your handler sees a complete book relative to the last applied snapshot or delta. Any `depth` in `[1, 500]` works. A connected feed that goes silent will not fire `onError` or refetch; if you need continuity, watch the last `onEvent` and resync with `orderbook.get()`. See [Order book](https://testnet.polyester.com/docs/sdk/typescript/reference/order-book).

   ```ts
   const book = client.orderbook.createSubscription({
   	symbolId,
   	depth: 10,
   	onEvent: (b) => {
   		const bid = b.bids[0];
   		const ask = b.asks[0];
   		if (bid && ask) console.log(`bid ${bid.price}  ask ${ask.price}`);
   	},
   	onError: (ctx) => console.error("book error", ctx.error),
   });

   // Re-aggregate into coarser price buckets without reconnecting:
   book.setBucket("10");
   ```

5. Run it and shut down

   Under the hood, one shared WebSocket client multiplexes all three streams, so this costs a single connection. Clean up on exit:

   ```ts
   process.on("SIGINT", () => {
   	overviewUnsub();
   	candleUnsub();
   	book.unsubscribe();
   	client.realtime.disconnect();
   	process.exit(0);
   });
   ```

   ```bash
   bun run ticker.ts
   ```

   You should see the top markets, then a stream of candle closes and top-of-book updates.

> **This runs on a server too**
>
> This script is a long-lived process, so it streams fine from Node, Bun, or a server, not just a browser. Subscriptions are only blocked inside a framework's SSR render pass, where you should fetch a snapshot during render and subscribe after the page hydrates. See [Streaming](https://testnet.polyester.com/docs/sdk/typescript/guides/streaming).

## Where to go next

- [Market data guide](https://testnet.polyester.com/docs/sdk/typescript/guides/market-data) for every public read and stream.
- [Streaming guide](https://testnet.polyester.com/docs/sdk/typescript/guides/streaming) for the realtime model in depth.
- [Build a trading bot](https://testnet.polyester.com/docs/sdk/typescript/tutorials/trading-bot) to act on this data.
