Skip to content

Commit

Permalink
restructure websocket docs
Browse files Browse the repository at this point in the history
  • Loading branch information
wphan committed Dec 20, 2023
1 parent 9140291 commit ff330ff
Show file tree
Hide file tree
Showing 3 changed files with 224 additions and 250 deletions.
159 changes: 159 additions & 0 deletions source/includes/_orderbook_blockchain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
# Orderbook (Blockchain)

The drift orderbook is a collection of all open orders on the Drift protocol. There is no single source of truth for the orderbook. The most up to date view of the orderbook is one where you track user orders and maintain the orderbook structure yourself. This section shows how to do that with the various SDKs.

## Dlob Source

This is the main source of orders for maintaing the orderbook.

## Dlob Source - `UserMap`

`UserMap` stores a complete map of all user accounts (idle users are commonly filtered ou).

```typescript
import {Connection} from "@solana/web3.js";
import {DriftClient, UserMap, Wallet, loadKeypair} from "@drift-labs/sdk";

const connection = new Connection("https://api.mainnet-beta.solana.com");

const keyPairFile = '~/.config/solana/my-keypair.json';
const wallet = new Wallet(loadKeypair(privateKeyFile))

const driftClient = new DriftClient({
connection,
wallet,
env: 'mainnet-beta',
});
await driftClient.subscribe();

// polling keep users updated with periodic calls to getProgramAccounts
// websocket keep users updated via programSubscribe
const subscriptionConfig:
| {
type: 'polling';
frequency: number;
commitment?: Commitment;
} | {
type: 'websocket';
resubTimeoutMs?: number;
commitment?: Commitment;
} = {
type: 'websocket',
resubTimeoutMs: 30_000,
commitment: stateCommitment,
};

const userMap = new UserMap({
driftClient,
connection,
subscriptionConfig,
skipInitialLoad: false, // skips initial load of user accounts
includeIdle: false, // filters out idle users
});

await userMap.subscribe();
```

## Dlob Source - `OrderSubscriber`

`OrderSubscriber` is a more efficient version of `UserMap`, only tracking user accounts that have orders.

```typescript
import {Connection} from "@solana/web3.js";
import {DriftClient, OrderSubscriber, Wallet, loadKeypair} from "@drift-labs/sdk";

const connection = new Connection("https://api.mainnet-beta.solana.com");

const keyPairFile = '~/.config/solana/my-keypair.json';
const wallet = new Wallet(loadKeypair(privateKeyFile))

const driftClient = new DriftClient({
connection,
wallet,
env: 'mainnet-beta',
});
await driftClient.subscribe();

const subscriptionConfig:
| {
type: 'polling',
frequency: ORDERBOOK_UPDATE_INTERVAL,
commitment: stateCommitment,
}
| {
type: 'websocket',
commitment: stateCommitment,
resyncIntervalMs: WS_FALLBACK_FETCH_INTERVAL,
} = {
type: 'websocket',
commitment: stateCommitment,
resyncIntervalMs: WS_FALLBACK_FETCH_INTERVAL, // periodically resyncs the orders in case of missed websocket messages
};

const orderSubscriber = new OrderSubscriber({
driftClient,
subscriptionConfig,
});

await orderSubscriber.subscribe();
```

## Orderbook Subscription

With a `DlobSource` you can then subscribe to the orderbook.

```typescript
import {DLOBSubscriber} from "@drift-labs/sdk";

const dlobSubscriber = new DLOBSubscriber({
driftClient,
dlobSource: orderSubscriber, // or UserMap
slotSource: orderSubscriber, // or UserMap
updateFrequency: 1000,
});

await dlobSubscriber.subscribe();
```

| Parameter | Description | Optional | Default |
| ----------- | ----------- | -------- | ------- |
| driftClient | DriftClient object | No | |
| dlobSource | Where to build the orderbook from. Can subscribe to user accounts on-chain using UserMap or request DLOB from api using DLOBApiClient | No | |
| slotSource | Where to get slot from | No | |
| updateFrequency | How often to rebuild the orderbook from the dlobSource in milliseconds | No | |

## Get L2 Orderbook

```typescript
const l2 = dlobSubscriber.getL2({
marketName: 'SOL-PERP',
depth: 50,
});
```

| Parameter | Description | Optional | Default |
| ----------- | ----------- | -------- | ------- |
| marketName | The market name of the orderbook to get. If not set, marketIndex and marketType must be set | Yes | |
| marketIndex | The market index of the orderbook to get. If not set, marketName must be set | Yes | |
| marketType | The market type of the orderbook to get. If not set, marketName must be set | Yes | |
| depth | The depth of the orderbook to get | Yes | 10 |
| includeVamm | Whether to include vAMM | Yes | false |
| fallbackL2Generators | L2OrderbookGenerators for fallback liquidity e.g. vAmm, openbook, phoenix. Unnecessary if includeVamm is true | Yes | |

The L2 orderbook is an aggregate of drift dlob orders and, optionally, fallback liquidity.

## Get L3 Orderbook

```typescript
const l3 = dlobSubscriber.getL3({
marketName: 'SOL-PERP',
});
```

| Parameter | Description | Optional | Default |
| ----------- | ----------- | -------- | ------- |
| marketName | The market name of the orderbook to get. If not set, marketIndex and marketType must be set | Yes | |
| marketIndex | The market index of the orderbook to get. If not set, marketName must be set | Yes | |
| marketType | The market type of the orderbook to get. If not set, marketName must be set | Yes | |

The L3 orderbook contains every maker order on drift dlob, including the address for the user that placed the order.
Original file line number Diff line number Diff line change
@@ -1,12 +1,58 @@
# Websocket API
# Orderbook/Trades (DLOB Server)

Drift runs a [`dlob-server`](https://github.com/drift-labs/dlob-server) to reduce the RPC load on UI users and traders. You can access this server (or run your own!) instead of [maintaing an order book from the blockchain](#orderbook-blockchain).


mainnet-beta: [https://dlob.drift.trade/](https://dlob.drift.trade/)
devnet: [https://master.dlob.drift.trade/](https://master.dlob.drift.trade/)

All endpoints follow the same query parameter scheme to specify a market:

| Parameter | Description | Optional | Default |
| ----------- | ----------- | -------- | ------- |
| marketName | The market name of the orderbook to get. If not set, marketIndex and marketType must be set | Yes | |
| marketIndex | The market index of the orderbook to get. If not set, marketName must be set | Yes | |
| marketType | The market type of the orderbook to get. If not set, marketName must be set | Yes | |

## `GET /l2`
## `GET /l3`


Returns an L2 (aggregate price levels) or L3 (individual orders) orderbook for the specificed market.

| Parameter | Description | Optional | Default | L2 only |
| ------------- | ------------------------------------------------ | -------- | ---------- | ------- |
| depth | Number of records to return per side | Yes | all orders | Yes |
| includeVamm | `true` to include vAMM liquidity in the response | Yes | `false` | Yes |
| includeOracle | `true` to include oracle data with the response | Yes | `false` | No |

Example: [https://dlob.drift.trade/l2?marketName=JTO-PERP&depth=10&includeOracle=true&includeVamm=true](https://dlob.drift.trade/l2?marketName=JTO-PERP&depth=10&includeOracle=true&includeVamm=true)

Example: [https://dlob.drift.trade/l3?marketName=JTO-PERP&includeOracle=true](https://dlob.drift.trade/l3?marketName=JTO-PERP&includeOracle=true)

## `GET /topMakers`

Returns the top makers (currently returns an exhaustive list) for a given market (useful for `place_and_take` orders).

| Parameter | Description | Optional | Default |
| ---------------- | ------------------------------------------------ | -------- | ---------- |
| side | Side to return makers for (`bid` or `ask`) | No | |
| limit | Limit number of makers to return | Yes | all |
| includeUserStats | `true` to include full UserStats | Yes | `false` |

Example: [https://dlob.drift.trade/topMakers?marketName=JTO-PERP&side=bid&limit=5](https://dlob.drift.trade/topMakers?marketName=JTO-PERP&side=bid&limit=5)

## Websocket

The mainnet-beta websocket endpoint is: [wss://dlob.drift.trade/ws](wss://dlob.drift.trade/ws)

Drift currently offers websocket streaming for two data streams: orderbooks and trades. The data streams are constructed from blockhain data. More data sources and user specific feeds will be added as this functionality is expanded.

mainnet-beta: `wss://dlob.drift.trade/ws`
mainnet-beta: [wss://dlob.drift.trade/ws](wss://dlob.drift.trade/ws)

devnet: `wss://master.dlob.drift.trade/ws`
devnet: [wss://master.dlob.drift.trade/ws](wss://master.dlob.drift.trade/ws)

## Subscribing
## Websocket - Subscribing

Clients must send subscribe messages over the websocket connection in order to start receiving messages.

Expand Down Expand Up @@ -43,12 +89,12 @@ ws.on('open', async () => {
console.log('Connected to the server');

// Subscribe to orderbook data
ws.send(JSON.stringify({ type: 'subscribe', marketType: 'perp', channel: 'orderbook', market: 'SOL-PERP' }));
ws.send(JSON.stringify({ type: 'subscribe', marketType: 'perp', channel: 'orderbook', market: 'SOL-PERP' }));
ws.send(JSON.stringify({ type: 'subscribe', marketType: 'spot', channel: 'orderbook', market: 'SOL' }));


// Subscribe to trades data
ws.send(JSON.stringify({ type: 'subscribe', marketType: 'perp', channel: 'trades', market: 'SOL-PERP' }));
ws.send(JSON.stringify({ type: 'subscribe', marketType: 'perp', channel: 'trades', market: 'SOL-PERP' }));
});

ws.on('message', (data: WebSocket.Data) => {
Expand All @@ -63,7 +109,7 @@ ws.on('message', (data: WebSocket.Data) => {

```

```python
```python
import json
import websocket
import ssl
Expand Down Expand Up @@ -131,13 +177,22 @@ Trades feed subscribe messages take a similar form to orderbook data, just chang
}
`

## Unsubscribing
## Websocket - Unsubscribing

To unsubscribe to a channel, send a subscribe-like message, with the message type set to `unsubscribe`. Unsubscribe requests to channels not previously subscribed to will have no impact.

## Liveness measure
`
{
type: 'unsubscribe',
marketType: 'perp',
channel: 'orderbook',
market: 'SOL-PERP'
}
`

## Websocket - Liveness measure

To alleviate backpressure on websocket servers, drift websockets stop sending messages to clients that have more than 50 messages unproccessed in their buffer, until the buffer is cleared and the messages are processed. We recommend listening for heartbeat messages from the server to determine if your client is still receiving messages.
To alleviate backpressure on websocket servers, drift websockets stop sending messages to clients that have more than 50 messages unproccessed in their buffer, until the buffer is cleared and the messages are processed. We recommend listening for heartbeat messages from the server to determine if your client is still receiving messages.

Heartbeat messages are sent every 5 seconds and take the following form:
`
Expand All @@ -148,6 +203,3 @@ Heartbeat messages are sent every 5 seconds and take the following form:

No ping messages are sent from the websocket server. Unsolicited ping messages are allowed and will receive pongs back.

## Feedback

For any feedback on websockets, please reach out on discord under the channel research-and-dev-chat
Loading

0 comments on commit ff330ff

Please sign in to comment.