Skip to content

Commit

Permalink
update orderbook docs
Browse files Browse the repository at this point in the history
  • Loading branch information
wphan committed Dec 20, 2023
1 parent 3365ddd commit 89f5fba
Show file tree
Hide file tree
Showing 3 changed files with 195 additions and 48 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Make sure latest ruby version is installed:
brew update
brew install ruby
```
(mac users will need to make sure their [`PATH` is set properly](https://mac.install.guide/ruby/13.html) to not use the default system ruby)

Update gem (no `sudo`, if it fails running it again seems to work...):
```
Expand Down
33 changes: 31 additions & 2 deletions source/includes/_historicaldata.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Historical Data

Snapshots are collected by parsing on-chain transaction logs. For convience the below are parsed logs collected, stored as a CSV, and stored off-chain (~99% of records).
Snapshots are collected by parsing on-chain transaction logs. For convience the below are parsed logs collected, stored as a CSV, and stored off-chain (~99% of records).

Please share any transaction signatures or time ranges you believe might be missing in Drift Protocol Discord.

Expand Down Expand Up @@ -30,12 +30,41 @@ devnet: `https://drift-historical-data.s3.us-east-1.amazonaws.com/program/dRifty
| marketSymbol | market name | SOL-PERP |
| year | | 2023 |
| month | | 4 |
| day | utc time | 25 |
| day | utc time | 25 |
| candleResolution | | 1M |


## Examples

Get historical trades on `SOL-PERP` for August 5, 2023:
```
https://drift-historical-data.s3.eu-west-1.amazonaws.com/program/dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH/market/SOL-PERP/trades/2023/8/5
```

## Records Columns

Below are definitions of the columns in each record type.

### trades

| variable | description | example |
| --- | --- | --- |
| accountKey | user sub account public key (not authority) | |

### market-trades

### funding-rates

### funding-payments

### deposits

### liquidations

### candles

### settle-pnl-records


```python
import requests
Expand Down
209 changes: 163 additions & 46 deletions source/index.html.md
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,7 @@ order_params = OrderParams(
await drift_client.place_perp_order(order_params)
```

Oracle market orders enable a user to define their auction params as an offset (or relative to) the oracle price.
Oracle market orders enable a user to define their auction params as an offset (or relative to) the oracle price.

## Canceling Order

Expand Down Expand Up @@ -1078,75 +1078,115 @@ Leverage is the total liability value (borrows plus total perp position) divided

# Orderbook (Blockchain)

## Slot Subscription
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.

### `UserMap`

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

```typescript
import {Connection} from "@solana/web3.js";
import {SlotSubscriber} from "@drift-labs/sdk";
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 slotSubscriber = new SlotSubscriber(connection);
const connection = new Connection("https://api.mainnet-beta.solana.com");

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

slotSubscriber.eventEmitter.on('newSlot', async (slot) => {
console.log('new slot', slot);
});
```
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,
};

| Parameter | Description | Optional | Default |
| ----------- | ----------- | -------- | ------- |
| connection | Connection object specifying solana rpc url | No | |
const userMap = new UserMap({
driftClient,
connection,
subscriptionConfig,
skipInitialLoad: false, // skips initial load of user accounts
includeIdle: false, // filters out idle users
});

await userMap.subscribe();
```

The slot subscriber subscribes to the latest slot and updates the slot value every time a new slot is received. The state of the orderbook is dependent on the slot value, so to build the orderbook you must keep track of the slot value.
### `OrderSubscriber`

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

```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");
import {Connection} from "@solana/web3.js";
import {DriftClient, OrderSubscriber, Wallet, loadKeypair} from "@drift-labs/sdk";

const keyPairFile = '~/.config/solana/my-keypair.json';
const wallet = new Wallet(loadKeypair(privateKeyFile))
const connection = new Connection("https://api.mainnet-beta.solana.com");

const driftClient = new DriftClient({
connection,
wallet,
env: 'mainnet-beta',
});
const keyPairFile = '~/.config/solana/my-keypair.json';
const wallet = new Wallet(loadKeypair(privateKeyFile))

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

const includeIdleUsers = false;
const userMap = new UserMap(driftClient, {type: 'websocket'}, false);
await userMap.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
};

| Parameter | Description | Optional | Default |
| ----------- | ----------- | -------- | ------- |
| driftClient | DriftClient object | No | |
| accountSubscription | Whether to use websocket or polling to subscribe to users | No | |
| includeIdle | Whether to include idle users. An idle user has had no orders, perp position or borrow for 7 days | Yes | |
const orderSubscriber = new OrderSubscriber({
driftClient,
subscriptionConfig,
});

Orders are stored on user accounts. To reconstruct the orderbook, you must keep track of the user accounts that have orders.
The user map subscribes to user account updates.
await orderSubscriber.subscribe();
```

## Orderbook Subscription

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

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

// on-chain subscription to users
const userMap = new UserMap(driftClient, {type: 'websocket'}, false);
await userMap.subscribe();

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

Expand Down Expand Up @@ -1196,6 +1236,83 @@ const l3 = dlobSubscriber.getL3({

The L3 orderbook contains every maker order on drift dlob, including the address for the user that placed the order.

# Orderbook (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).

## Polling

The mainnet-beta http endpoint is: `https://dlob.drift.trade/`

### Specifying a market

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` and `Get /l3`

Returns an L2/L3 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

Example: 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

## Websocket

The mainnet-beta websocket endpoint is: `wss://dlob.drift.trade/ws`

The websocket server currently only sends L2 orderbook data, roughly every 1s. Ensure you have reconnect logc in place in case the connection is terminated by the server.

```typescript
import WebSocket from 'ws';

const ws = new WebSocket('wss://dlob.drift.trade/ws');
ws.on('open', async () => {
ws.send(JSON.stringify({ type: 'subscribe', marketType: 'perp', channel: 'orderbook', market: 'SOL-PERP' }));
});

ws.on('message', (data: WebSocket.Data) => {
try {
const message = JSON.parse(data.toString());
console.log(`Received data from channel: ${JSON.stringify(message.channel)}`);
// book and trades data is in message.data
} catch (e) {
console.error('Invalid message:', data);
}
});

wsConn.on('close', () => {
console.log('Connection closed');
// if you did not close the connection yourself, you should reconnect here
});

```



# Events

## Event Subscription
Expand Down

0 comments on commit 89f5fba

Please sign in to comment.