Programmatic Trading with Reservoir

This guide outlines how to use Reservoir for market making across the NFT ecosystem

You can use this process to get market data, place bids and asks, and buy and sell tokens, programmatically across Reservoir, OpenSea, LooksRare, X2Y2, and more. There are some limitations depending on which orderbook you wish to interact with, which we detail below.

Reservoir Overview

Reservoir aggregates all NFT liquidity data, normalizes it, and abstracts the execution process across exchanges so traders can create and execute aggregated liquidity as if using a single orderbook and exchange. We do not have all liquidity from across the ecosystem, but are working to integrate more of the market all the time. For programmatic trading, the two primary Reservoir products of interest are

  1. Data APIs - get real-time and historical market data (including sales, listings, bids, and metadata) in order to build the best programmatic trading models
  2. Reservoir SDK - create and execute orders across all major NFT marketplaces easily using the Reservoir SDK

Additional information:
Website: https://reservoir.tools/
Docs: https://docs.reservoir.tools/docs
API Reference: https://docs.reservoir.tools/reference/overview

Data

Reservoir has an extremely comprehensive set of real-time and historical data for NFT collections, sales, and liquidity. You can see some of that data in use here: https://dune.com/reservoir0x/nft-marketplace-overview This data is particularly useful for creating models of NFT prices, and building robust market making strategies. All this data and more is available using our Data APIs. If you need more comprehensive data access, feel free to reach out.

Data we have:

  • All historical sales
    maker, taker, mp, price (Eth and USD), fees

  • Most historical listings

  • Maker, price (Eth and USD), expiration, final state (executed expired)

  • Token and collection metadata

  • Token attributes: i.e. token #123 has ‘blue hair’

  • Collection attributes: i.e. total supply, holders, etc.

  • Real time floor price data including TWAPs

  • Some, but not all current bids

Reservoir SDK

Reservoir SDK allows you to interact with major NFT marketplaces easily. In order to showcase this SDK we walk you through an example of market making activity below.
Feel free to check out the full example code here.

Installing and Configuring the Reservoir Client

> yarn add @reservoir0x/reservoir-kit-client

ReservoirKit client also requires ethers to be installed, make sure that's added to your package.json if it isn't already.

> yarn add ethers

To configure the client we first need to create a global instance of it:

import { createClient } from "@reservoir0x/reservoir-kit-client"

const client =  createClient({
  apiBase: "https://api.reservoir.tools",
  apiKey: "YOUR_API_KEY",
  source: "YOUR.SOURCE"
});

export default client

More details about the Reservoir Client are available here.

Bidding and Listing on Different Marketplaces

We are going to assume here that you have the price that you want to bid or list a token already computed. Where data can be useful for this calculation, see the Data APIs for real time data.

Bidding

In order to bid you must first set the bid order params. For a collection bid, you simply set the collection as follows:

Collection Bid Example

let bidPrice = x; //example bid price  
let expirationTime = dayjs().add(20, "minutes").unix().toString(); 
let bidOrder = {
  collection: contract,
  orderKind: "seaport",
  orderbook: "reservoir",
  automatedRoyalties: true,
  excludeFlaggedTokens: true,
  weiPrice: ethers.utils.parseEther(bidPrice).toString(),
  expirationTime,
};

To make a token bid, In order to bid on a single token, you pass token: tokenId into the params in addition to the collection contract.

Token Bid Example

let bidPrice = x; //example bid price  
let expirationTime = dayjs().add(20, "minutes").unix().toString();
let bidOrder = {
  collection: contract,
  token: tokenId,
  orderKind: "seaport",
  orderbook: "reservoir",
  automatedRoyalties: true,
  excludeFlaggedTokens: true,
  weiPrice: ethers.utils.parseEther(bidPrice).toString(),
  expirationTime,
};

You can also place trait and arbitrary token set bids, depending on the orderbook you choose.

Here orderKind and orderbook set the marketplace you wish to interact with:

MarketplaceorderKindorderbookMarketplace FeeAvailable Features
OpenSeaseaportopensea2.5%Collection, token bids
LooksRarelooks-rarelooks-rare2%Collection, token bids
X2Y2x2y2x2y20.5%Collection, token bids
Reservoirseaportreservoir0%Collection, trait, token arbitrary token set bids

Then, you can simply use the the Reservoir SDK for bidding:

await reservoirClient.actions
  .placeBid({
    signer: signer,
    onProgress: () => {},
    bids: [bidOrder],
  })

The place bid function takes an array of bid objects that match the params passed to the execute bid api

Listing

In order to list you must first set the listing params:

Example System Set-up

let listPrice = x //example list price 
let expirationTime = dayjs().add(20, "minutes").unix().toString();
 
let listOrder = {
  token: `${contract}:${token}`,
  orderKind: "seaport",
  orderbook: "reservoir",
  weiPrice: ethers.utils.parseEther(listPrice).toString(),
  expirationTime: listingTime,
};

await reservoirClient.actions
  .listToken({
    signer: signer,
    onProgress: () => {},
    listings: [listOrder],
  })

One could set up a programmatic trading system in a number of ways. But one simple set up is as follows:

  • Design a trading strategy using Reservoir’s APIs to get all the data needed to set buys and sells or bids and asks appropriately
  • Use Reservoir’s abstracted SDK for creating orders
  • For on-chain actions use Ethers.js and connect to an OpenZeppelin defender relayer and Reservoir SDK takes care of everything that needs to happen behind the scenes (including approvals, making safety checks, etc.)
  • Deploy a node server to execute a cron job, loop the job over a collections list and executes a market making strategy above