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

# Streams & Account

> Read your perpetuals account, follow fills and market data, and keep a local order book with the Go SDK.

This page builds a program that reads your account over HTTP, then follows a market's order book, its trades and your own fills over the WebSocket, printing the top of the book as it changes. It picks up from the [Quickstart](/latest/perps/go-sdk/quickstart).

## Read the Account

The account reads are methods on the client. Each takes a market, or `perps.MarketAll` for all of them:

```go theme={null}
balances, err := client.Balances(ctx, perps.MarketAll)
if err != nil {
	return err
}
fmt.Printf("balance %s USDT, available %s\n",
	balances.TotalBalance, balances.AvailableBalance)

positions, err := client.Positions(ctx, perps.MarketAll)
if err != nil {
	return err
}
for _, p := range positions {
	fmt.Printf("position %s: %s, unrealized PnL %s\n",
		p.Market, p.Quantity, p.UnrealizedPnL)
}
```

The fields are those of [Get Account Balances](/latest/perps/rest-api/get-account-balances) and [Get Account Positions](/latest/perps/rest-api/get-account-positions). Amounts are strings, as on the wire, so no precision is lost.

`Deposits`, `Withdrawals` and `Fundings` return one `perps.Page` at a time. Pass `Next` back as the cursor until it comes back empty; `CompletedOrders` takes it in its query:

```go theme={null}
deposits := 0
for cursor := ""; ; {
	page, err := client.Deposits(ctx, cursor)
	if err != nil {
		return err
	}
	deposits += len(page.Items)
	if cursor = page.Next; cursor == "" {
		break
	}
}
```

`OpenOrders` follows the cursor for you and returns every open order.

## Subscribe to Streams

`perps.WithSubscriptions` adds streams beyond the [Order Creation Stream](/latest/perps/websocket-api/order-creation-stream) when the connection opens; `conn.Subscribe` and `conn.Unsubscribe` change the set later. The set survives reconnects.

```go theme={null}
conn, err := client.Connect(ctx, "BTC-USDT", perps.WithSubscriptions(
	perps.SubscriptionTrades,
	perps.SubscriptionPublicTrades,
	perps.SubscriptionPublicOrderBook,
))
if err != nil {
	return err
}
defer conn.Close()
```

## Handle Events

Everything the connection receives arrives as a typed event on `conn.Events()`. The channel applies backpressure instead of dropping events, so it must be read: a consumer that stops reading stalls the connection.

```go theme={null}
for event := range conn.Events() {
	switch e := event.(type) {
	case perps.PublicTrades:
		for _, t := range e.Trades {
			fmt.Printf("trade: %s %s at %s\n", t.OrderType, t.Quantity, t.Price)
		}
	case perps.Trades:
		for _, t := range e.Trades {
			fmt.Printf("your fill %s: %s %s at %s\n",
				t.Market, t.OrderType, t.Quantity, t.Price)
		}
	}
}
```

`perps.OrderBookDelta` is handled [below](#keep-an-order-book). `perps.OrderFilled` and `perps.OrderRejected` are your orders filling or being refused after the command that placed them returned. `perps.Connected` and `perps.Disconnected` report the socket coming and going. `perps.Unknown` is a message this version of the SDK has no type for.

## Keep an Order Book

A local book starts from a snapshot and applies each delta after it, as the [Order Book](/latest/perps/guides/order-book) guide describes. Deltas carry no sequence number, so take a new snapshot after every reconnect. `perps.Connected` arrives for the first socket and for each reconnect.

A snapshot is a request on the connection. It is asked for off the event loop, which has to keep reading events while it waits:

```go theme={null}
bids, asks := map[string]string{}, map[string]string{} // quantity by price
snapshots := make(chan *perps.OrderBookSnapshot, 1)
```

```go theme={null}
switch event.(type) {
case perps.Connected:
	go func() {
		snapshot, err := conn.EmitPublicOrderBook(ctx, "BTC-USDT")
		if err != nil {
			fmt.Fprintln(os.Stderr, "order book snapshot:", err)
			return
		}
		select {
		case snapshots <- snapshot:
		case <-ctx.Done():
		}
	}()
}
```

Deltas keep arriving while the snapshot is on its way. Hold them back, and once the snapshot has arrived replay those not older than its `Ts`, dropping any older delta that is still queued; discard a snapshot that was requested before a later reconnect. The example has that bookkeeping. Snapshot levels (`snapshot.Orders`) and delta levels are applied the same way: each replaces the level at its price, and a quantity of `0` removes it.

```go theme={null}
switch e := event.(type) {
case perps.OrderBookDelta:
	for _, l := range e.Orders {
		side := asks
		if l.OrderType == perps.OrderTypeBuy {
			side = bids
		}
		if q, _ := strconv.ParseFloat(l.Quantity, 64); q == 0 {
			delete(side, l.Price)
		} else {
			side[l.Price] = l.Quantity
		}
	}
}
```

## After a Reconnect

`perps.SessionBackfill` reports how the [session](/latest/websocket-session) was recovered, on the first connection and after each reconnect. When the session could not be resumed, or a market's backfill expired, rebuild your order state over HTTP:

```go theme={null}
switch e := event.(type) {
case perps.SessionBackfill:
	if !e.Resumed || len(e.ExpiredMarkets) > 0 {
		orders, err := client.OpenOrders(ctx, perps.MarketAll)
		if err != nil {
			return err
		}
		fmt.Printf("rebuilt: %d open orders\n", len(orders))
	}
}
```

## Run the Example

The complete program is [`examples/perps-streams-and-account`](https://github.com/rails-xyz/exchange-go-sdk/tree/main/examples/perps-streams-and-account) in the SDK repository. Run it for as long as you want to watch:

```bash theme={null}
RAILS_API_KEY=<key> RAILS_API_SECRET=<secret> go run ./examples/perps-streams-and-account -for 30s
```

```text theme={null}
balance 1499.0156133 USDT, available 1499.0156133
3 deposits
rebuilt: 0 open orders
book BTC-USDT: 83986.86 / 84294.24
book BTC-USDT: 84119.74 / 84161.82
```

The first `rebuilt` line is the fresh session reporting that nothing was resumed.

## Related

* [Account Information](/latest/perps/guides/account-info) and [Order Book](/latest/perps/guides/order-book)
* [Account Trades Stream](/latest/perps/websocket-api/account-trades-stream), [Public Trades Stream](/latest/perps/websocket-api/public-trades-stream) and [Order Book Stream](/latest/perps/websocket-api/order-book-stream)
* [WebSocket Session](/latest/websocket-session)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.