Velocity ProtocolDevelopers
Velocity SDK

Markets, Oracles, and Positions

How it works

Velocity has two types of markets: perp markets, perpetual futures with funding rates, and spot markets, token deposits and borrows that serve as collateral. Each market has an onchain account storing configuration like oracle source, fees, funding rates, AMM parameters, and current open interest.

Market Indexes

Markets are identified by a numeric index starting from 0. Perp and spot markets are indexed separately, and the mapping from index to symbol is not fixed in the SDK: resolve it from the market accounts rather than hardcoding it.

Where to find market indexes:

  • State account: Query velocityClient.getStateAccount() for numberOfMarkets and numberOfSpotMarkets, the counts of perp and spot markets. This gives the index range (0 to count - 1) to enumerate; it does not contain the market configurations themselves
  • SDK methods: Use velocityClient.getPerpMarketAccounts() or velocityClient.getSpotMarketAccounts() to get all markets and inspect their indexes
  • Market account directly: Each market account has a marketIndex field to read
  • Symbol lookup: Most bots maintain their own mapping from symbol to market index, or query all markets and build the mapping at startup

Each market names an oracle that supplies its price. The supported OracleSource values are Pyth push, Pyth Lazer, Prelaunch for pre-listing markets, and QuoteAsset for the quote asset itself. Which one a given market uses is a per-market setting: read oracleSource off the market account.

Two families are gone. Switchboard is deprecated, with its OracleSource variants retained only as Deprecated* stubs. The Pyth pull variants (PythPull, Pyth1KPull, Pyth1MPull, PythStableCoinPull) are rejected onchain with InvalidOracle. A config ported from elsewhere that names either fails at the market rather than at the client.

The SDK reads oracle prices off the subscription cache, exposes their validity and staleness flags, and returns the value in PRICE_PRECISION (1e6) for quoting and risk math.

Perp markets track funding rates, open interest, and AMM liquidity pools. Spot markets track total deposits, borrows, and utilization rates. Trading goes through these market accounts: opening positions on perp markets, or borrowing and depositing in spot markets. Spot markets on Velocity are collateral and borrow-lend only: spot orders cannot be placed on the DLOB (see Orders).

SDK Usage

These are the most common read-path helpers behind bots, dashboards, and risk logic.

Market Accounts

Read a single spot market account by index (e.g., market config, oracle source, and utilization state).

const marketIndex = 0;
const spotMarket = velocityClient.getSpotMarketAccount(marketIndex);
console.log(spotMarket?.marketIndex);

Read a single perp market account by index (e.g., AMM params, funding state, and open interest).

const marketIndex = 0;
const perpMarket = velocityClient.getPerpMarketAccount(marketIndex);
console.log(perpMarket?.marketIndex);

Get all spot market accounts at once, useful for startup symbol/index mapping and dashboards.

const spotMarkets = velocityClient.getSpotMarketAccounts();
console.log(spotMarkets.length);

Get all perp market accounts at once, useful for scanning market metadata and risk parameters.

const perpMarkets = velocityClient.getPerpMarketAccounts();
console.log(perpMarkets.length);

Reading a Market's Tier

A perp market's contractTier and a spot market's assetTier are enums. The SDK converts them to an ordinal safety rank, where lower is safer, so they can be compared and sorted. The numbering follows the onchain enum declaration order, which is what the program compares against.

HelperInputReturns
getPerpMarketTierNumber(perpMarket)A PerpMarketAccount0 = A, 1 = B, 2 = C, 3 = Speculative, 4 = Highly Speculative, 5 = Isolated
getSpotMarketTierNumber(spotMarket)A SpotMarketAccount0 = Collateral, 1 = Protected, 2 = Cross, 3 = Isolated, 4 = Unlisted
perpTierIsAsSafeAs(perpTier, otherPerpTier, otherSpotTier)Three tier numberstrue if the perp tier is at least as safe as both references
import {
  getPerpMarketTierNumber,
  getSpotMarketTierNumber,
  perpTierIsAsSafeAs,
} from "@velocity-exchange/sdk";

const perpMarket = velocityClient.getPerpMarketAccount(0);
const perpTier = getPerpMarketTierNumber(perpMarket); // 0 (A) through 5 (Isolated)

// Filter to markets at tier C or safer
const safeMarkets = velocityClient
  .getPerpMarketAccounts()
  .filter((m) => getPerpMarketTierNumber(m) <= 2);

// Compare a market against the tiers already open on an account
const spotTier = getSpotMarketTierNumber(velocityClient.getSpotMarketAccount(1));
const ok = perpTierIsAsSafeAs(perpTier, 2, spotTier);

perpTierIsAsSafeAs mirrors the program's own comparison. A perp tier passes when it is numerically at or below otherPerpTier, and it is as safe as the spot reference: any tier beats Unlisted spot (4), and against Cross or Isolated spot (2 or 3) the perp tier must be C or safer (0 to 2).

Tier is not cosmetic. The program derives real limits from it: insurance-fund caps, the oracle confidence band before a price is treated as invalid, the TWAP sanitization band, the oracle-versus-mark divergence gate on PnL settlement, and the auction duration granted per 1% of price difference (100 steps per 1% for tier B or safer, 60 steps otherwise).

Code that predicts sanitized auction parameters, or builds a market-safety filter, should read the tier with these helpers rather than reimplementing the mapping. See Contract Tiers for every derived limit.

Oracle Price

Read the current oracle data for a perp market (price, confidence, and validity flags).

const marketIndex = 0;
const oracle = velocityClient.getOracleDataForPerpMarket(marketIndex);
console.log(oracle.price.toString());

Read the current oracle data for a spot market using its market index.

const marketIndex = 0;
const oracle = velocityClient.getOracleDataForSpotMarket(marketIndex);
console.log(oracle.price.toString());

Read market-maker-oriented oracle data for perp markets, typically used for DLOB/JIT pricing flows.

const marketIndex = 0;
const oracle = velocityClient.getMMOracleDataForPerpMarket(marketIndex);
console.log(oracle.price.toString());

Positions and Balances

Get the active subaccount's spot position for a given market index (deposit or borrow state).

const spotPosition = velocityClient.getSpotPosition(0);
console.log(spotPosition);

Get the active subaccount's perp position for a given perp market index, via the subaccount's User.

const perpPosition = velocityClient.getUser().getPerpPosition(0);
console.log(perpPosition);

Protocol State

The global state account holds protocol-level configuration including the number of active markets, the tiered admin key set (cold/warm/hot), and fee structures. It is the top-level entry point for querying protocol metadata.

const state = velocityClient.getStateAccount();
console.log(state);