Velocity ProtocolDevelopers
Market Makers

Indicative Quotes

Indicative quotes let market makers signal liquidity offchain without committing onchain orders. A maker publishes bid/ask prices and sizes to Velocity's WebSocket endpoint, where they feed:

  • UI display: takers see available liquidity before placing orders
  • Aggregator routing: Jupiter and other aggregators factor indicative liquidity into routing decisions
  • Price discovery: helps establish fair prices in thin markets

When to use indicative quotes:

  • Showing liquidity without paying transaction fees for onchain orders
  • Market making in lower-volume markets where onchain orders may sit unfilled
  • Attracting taker flow with prices tighter than the resting book
  • Running a JIT-only strategy while staying visible in the orderbook

Important: indicative quotes are not firm commitments. They signal intent and carry no obligation to fill at the published prices. When a taker actually places an order, the fill happens through the normal JIT auction or DLOB flow.

Setup

Endpoint is provisional. wss://dlob.velocity.exchange/quotes/ws below follows Velocity's <sub>.velocity.exchange hosted-endpoint convention but hasn't been confirmed as the final production URL. Check with the team before hardcoding it.

Construct the IndicativeQuotesSender with the WebSocket endpoint and a signing keypair, then connect:

import { IndicativeQuotesSender } from "@velocity-exchange/sdk";

import {
  IndicativeQuotesSender,
  PRICE_PRECISION,
  BASE_PRECISION,
  BN,
  convertToNumber,
  loadKeypair,
} from "@velocity-exchange/sdk";

// Constructor takes the WebSocket endpoint and the signing keypair (for auth)
const keypair = loadKeypair("<KEYPAIR_PATH>");
const quoter = new IndicativeQuotesSender(
  "wss://dlob.velocity.exchange/quotes/ws",
  keypair
);
// Connects to WebSocket, authenticates via challenge-response with the keypair
await quoter.connect();

Publishing quotes

Call setQuote to publish or update the indicative quote for a market. The WebSocket server broadcasts it to all subscribers: UI, aggregators, and anything else listening.

quoter.setQuote({
  bidPrice: new BN(bid * PRICE_PRECISION.toNumber()),
  askPrice: new BN(ask * PRICE_PRECISION.toNumber()),
  bidBaseAssetAmount: new BN(bidSize * BASE_PRECISION.toNumber()),
  askBaseAssetAmount: new BN(askSize * BASE_PRECISION.toNumber()),
  marketIndex,
  isOracleOffset: false,
});

Complete example: publish quotes that track oracle

This example publishes indicative quotes at a fixed spread around the oracle price, updating every second:

import {
  IndicativeQuotesSender,
  PRICE_PRECISION,
  BASE_PRECISION,
  BN,
  convertToNumber,
  loadKeypair,
} from "@velocity-exchange/sdk";

const marketIndex = 0; // SOL-PERP
const spread = 0.25;   // $0.25 on each side
const quoteSize = 10;  // 10 SOL per side

const keypair = loadKeypair("<KEYPAIR_PATH>");
const quoter = new IndicativeQuotesSender("wss://dlob.velocity.exchange/quotes/ws", keypair);
await quoter.connect();

// Update quotes periodically
setInterval(() => {
  const oracle = velocityClient.getOracleDataForPerpMarket(marketIndex);
  const oraclePrice = convertToNumber(oracle.price, PRICE_PRECISION);

  const bidPrice = oraclePrice - spread;
  const askPrice = oraclePrice + spread;

  quoter.setQuote({
    bidPrice: new BN(Math.round(bidPrice * PRICE_PRECISION.toNumber())),
    askPrice: new BN(Math.round(askPrice * PRICE_PRECISION.toNumber())),
    bidBaseAssetAmount: new BN(Math.round(quoteSize * BASE_PRECISION.toNumber())),
    askBaseAssetAmount: new BN(Math.round(quoteSize * BASE_PRECISION.toNumber())),
    marketIndex,
    isOracleOffset: false,
  });

  console.log(`Published indicative: bid $${bidPrice.toFixed(2)} / ask $${askPrice.toFixed(2)} (${quoteSize} SOL each side)`);
}, 1_000);

Using oracle offsets

With isOracleOffset: true, the bidPrice and askPrice are interpreted as offsets from the oracle price rather than absolute prices. This is analogous to oracle offset orders, and the quote floats with the oracle automatically.

const spreadOffset = 0.25; // $0.25 from oracle

quoter.setQuote({
  bidPrice: new BN(Math.round(-spreadOffset * PRICE_PRECISION.toNumber())), // oracle - $0.25
  askPrice: new BN(Math.round(spreadOffset * PRICE_PRECISION.toNumber())),  // oracle + $0.25
  bidBaseAssetAmount: new BN(Math.round(10 * BASE_PRECISION.toNumber())),
  askBaseAssetAmount: new BN(Math.round(10 * BASE_PRECISION.toNumber())),
  marketIndex: 0,
  isOracleOffset: true,
});

Stopping quotes

To stop publishing quotes for a specific market, send a quote with any field set to null. The sender detects incomplete quotes and deletes the stored quote for that market:

// Stop quoting market 0; setting any required field to null triggers deletion
quoter.setQuote({
  bidPrice: null,
  askPrice: null,
  bidBaseAssetAmount: null,
  askBaseAssetAmount: null,
  marketIndex: 0,
});

How indicative quotes appear in the orderbook

Indicative quotes show up in the L2 orderbook on requests carrying includeIndicative=true. They're merged with DLOB and vAMM liquidity at each price level, giving takers a fuller picture of available depth.

Gotchas

  • Indicative ≠ committed: aggregators and UIs display indicative quotes as available liquidity, but there's no onchain enforcement. Quotes that get published but not honored leave takers with slippage and degrade the maker's standing with routing algorithms.
  • WebSocket reconnection: if the WebSocket connection drops, the indicative quotes disappear from the orderbook. Implement auto-reconnect and re-publish quotes on reconnection.
  • Oracle offset mode simplifies maintenance: with isOracleOffset: true, an oracle move needs no republish. Only update when changing spread or size. This mirrors oracle offset orders for onchain quoting.
  • Rate limiting: the DLOB WebSocket server may throttle rapid setQuote updates. Publishing every second is sufficient for most use cases.
  • Null fields to clear: sending null for price/size fields removes the quote. This matters for graceful shutdown: clear indicative quotes before stopping the bot to avoid showing phantom liquidity.