OHLC diário de DEX e VWAP para um token, com frações exatas

Consulte preços diários de OHLC e VWAP de DEX na Data API, manipule frações racionais exatas em TypeScript e Python e faça o backfill de dados históricos com eficiência.

What the DEX daily prices dataset is

O conjunto de dados de DEX da BlockVectra indexa a atividade de negociação de exchanges descentralizadas e calcula métricas agregadas de preços diários. O endpoint de preços diários de DEX (getDexPrices) fornece o preço médio ponderado por volume (VWAP) diário, indicadores de preço (campos first_price, last_price, min_price e max_price) e métricas de volume para um token especificado ao longo de um determinado intervalo de datas.

A disponibilidade deste conjunto de dados varia entre as redes; as redes que fornecem este conjunto de dados estão sujeitas à página de Redes compatíveis.

Este endpoint não é paginado: todas as linhas diárias correspondentes dentro do intervalo de datas solicitado são retornadas diretamente em data, e next_cursor nunca está presente. Se a sua aplicação exigir transações de swap granulares em vez de agregações diárias, use GET /{chain}/dex/swaps (consulte a Referência da Data API).

Request parameters and limits

A rota do endpoint é GET https://api.blockvectra.com/v1/data/{chain}/dex/prices. Todas as requisições exigem autenticação fornecendo sua API key no cabeçalho x-api-key.

O endpoint aceita os seguintes parâmetros de query:

ParameterLocationTypeRequiredDescription
chainpathstringYesIdentificador da rede, por exemplo robinhood_mainnet
tokenquerystringYesEndereço do token base de 20 bytes, 0x opcional, maiúsculas ou minúsculas
quotequerystringNoEndereço opcional de token de cotação de 20 bytes para restringir a um único par base/cotação
fromquerydate stringYesData de início em UTC, inclusiva, YYYY-MM-DD
toquerydate stringYesData de término em UTC, inclusiva, YYYY-MM-DD. to - from deve ser <= 90 dias

Constraints and error codes

Quando uma requisição viola restrições, a API retorna um corpo de erro estruturado {"error":{"code","message"}}:

  • HTTP 400 (bad_request): parâmetros de query obrigatórios ausentes (token, from ou to), sintaxe de endereço de token/quote inválida, datas de calendário YYYY-MM-DD inválidas ou from posterior a to.
  • HTTP 409 (span_exceeded): to - from superior a 90 dias.
  • HTTP 404 (unknown_chain): {chain} não é uma rede listada por GET /chains.
  • HTTP 422 (no_coverage): a rede não é compatível com o recurso do conjunto de dados dex_prices.
  • HTTP 503 (unavailable): serviço temporariamente indisponível; tente novamente de acordo com o cabeçalho Retry-After.

Request examples

Os exemplos a seguir consultam os preços diários de DEX para um token base ao longo de setembro de 2026:

curl -s "https://api.blockvectra.com/v1/data/robinhood_mainnet/dex/prices?token=0x1Cdad396DB64BDa184d5182A97Dd9B3C62100b7D&from=2026-09-01&to=2026-09-30" \
  -H "x-api-key: $BLOCKVECTRA_API_KEY"

Detailed field reference

Cada entrada em data representa as métricas diárias agregadas de DEX para o par de tokens naquela data UTC:

Token and quote assets

  • day (string): data UTC no formato YYYY-MM-DD.
  • token (string): endereço do token base de 20 bytes em hexadecimal prefixado com 0x em letras minúsculas.
  • token_symbol (string ou null): símbolo do token base.
  • token_name (string ou null): nome de exibição do token base.
  • quote_token (string): endereço do ativo de cotação. O endereço todo zerado (0x0000000000000000000000000000000000000000) representa o ETH nativo como ativo de cotação.
  • quote_symbol (string ou null): símbolo do ativo de cotação ("ETH" quando quote_token for o endereço todo zerado).
  • quote_name (string ou null): nome de exibição do ativo de cotação ("Ether" quando quote_token for o endereço todo zerado).
  • base_decimals (integer ou null): casas decimais do token base (0–255).
  • quote_decimals (integer ou null): casas decimais do ativo de cotação (18 quando quote_token for o endereço todo zerado).

Volume and trade counts

  • swap_count (integer): contagem de swaps para esta linha.
  • base_volume_raw (string): volume base atômico como string decimal de inteiro não assinado (UInt256String).
  • quote_volume_raw (string): volume de cotação atômico como string decimal de inteiro não assinado (UInt256String).
  • base_volume (string ou null): volume legível do token base dimensionado por base_decimals como DecimalString; null quando base_decimals for desconhecido.
  • quote_volume (string ou null): volume de cotação dimensionado pelas casas decimais da cotação como DecimalString, ou null.

Price indicators and VWAP

  • vwap (string ou null): preço médio ponderado por volume como DecimalString, ou null.
  • first_price (string ou null): indicador de primeiro preço como DecimalString, ou null.
  • last_price (string ou null): indicador de último preço como DecimalString, ou null.
  • min_price (string ou null): indicador de preço mínimo como DecimalString, ou null.
  • max_price (string ou null): indicador de preço máximo como DecimalString, ou null.

Exact fraction fields

  • first_price_numerator / first_price_denominator (string): numerador e denominador inteiros exatos para first_price (UInt256String).
  • last_price_numerator / last_price_denominator (string): numerador e denominador inteiros exatos para last_price (UInt256String).
  • min_price_numerator / min_price_denominator (string): numerador e denominador inteiros exatos para min_price (UInt256String).
  • max_price_numerator / max_price_denominator (string): numerador e denominador inteiros exatos para max_price (UInt256String).
  • refreshed_at (string): timestamp de atualização para esta linha (timestamp UTC ISO-8601).

Envelope metadata (meta)

  • chain: identificador da rede.
  • chain_slug: slug canônico da rede em maiúsculas.
  • chain_external_id: identificador de rede formatado em CAIP-2.
  • as_of_block: o bloco mais recente totalmente gravado da rede (relatado por este conjunto de dados, não verificado em relação aos parâmetros da requisição).
  • coverage: classificação de cobertura (informa "full" para este endpoint).
  • refreshed_at: timestamp de atualização dos metadados. Pode ser null: null significa que o horário de atualização desses dados é desconhecido e eles devem ser tratados como desatualizados; endpoints baseados em blocos sempre retornam um valor.

Why prices use exact numerators and denominators

Números JSON padrão dependem de pontos flutuantes de precisão dupla IEEE-754, que apresentam limitações de precisão:

  1. Truncamento e desvio de ponto flutuante: valores Float64 fornecem apenas 53 bits de precisão, e a divisão de quantidades de tokens gera desvios de arredondamento que se acumulam ao longo dos cálculos.
  2. Segurança no transporte: formatar valores como strings decimais (UInt256String) garante que os números trafeguem via HTTP sem perda de precisão em analisadores JSON.

Ao fornecer o numerador e o denominador inteiros exatos para os indicadores de preço, a BlockVectra permite cálculos matemáticos exatos sem conversão para ponto flutuante.

Handling exact fractions in TypeScript (BigInt)

No TypeScript, você pode usar BigInt nativo para comparações por multiplicação cruzada e conversões para ponto fixo sem conversão para ponto flutuante:

interface DexDailyPrice {
  first_price_numerator: string;
  first_price_denominator: string;
  last_price_numerator: string;
  last_price_denominator: string;
}

// 1. Ratio comparison without floating-point conversion: check if close price is higher than open price
// a / b > c / d  is equivalent to  a * d > c * b
export function isPriceUp(row: DexDailyPrice): boolean {
  const openNum = BigInt(row.first_price_numerator);
  const openDen = BigInt(row.first_price_denominator);
  const closeNum = BigInt(row.last_price_numerator);
  const closeDen = BigInt(row.last_price_denominator);

  return closeNum * openDen > openNum * closeDen;
}

// 2. Convert fraction to a fixed-point decimal string with arbitrary scale (without floating-point loss)
export function fractionToFixedString(
  numeratorStr: string,
  denominatorStr: string,
  decimals = 18
): string {
  const num = BigInt(numeratorStr);
  const den = BigInt(denominatorStr);
  if (decimals === 0) {
    return (num / den).toString();
  }
  const scaleFactor = 10n ** BigInt(decimals);

  const scaled = (num * scaleFactor) / den;
  const intPart = scaled / scaleFactor;
  const remainder = scaled % scaleFactor;
  const fracPart = remainder.toString().padStart(decimals, "0");

  return `${intPart}.${fracPart}`;
}

Handling exact fractions in Python

O Python fornece módulos da biblioteca padrão criados especificamente para cálculos racionais e decimais: fractions.Fraction e decimal.Decimal.

from decimal import Decimal, getcontext
from fractions import Fraction

# 1. Exact rational calculations with fractions.Fraction
open_price = Fraction(
    int(row["first_price_numerator"]),
    int(row["first_price_denominator"])
)
close_price = Fraction(
    int(row["last_price_numerator"]),
    int(row["last_price_denominator"])
)

# Exact price delta without floating-point rounding error
price_delta = close_price - open_price
print(f"Price delta (fraction): {price_delta}")

if open_price != 0:
    percentage_change = (price_delta / open_price) * 100
    print(f"Percentage change: {float(percentage_change):.4f}%")

# 2. Arbitrary-precision decimal arithmetic with decimal.Decimal
getcontext().prec = 50

if int(row["first_price_denominator"]) != 0:
    open_decimal = Decimal(row["first_price_numerator"]) / Decimal(row["first_price_denominator"])
    print(f"High-precision open: {open_decimal}")

Backfilling one year of daily prices

Para fazer o backfill de um ano de dados (365 dias) dentro do limite de intervalo de 90 dias, divida o intervalo de datas completo em janelas consecutivas de no máximo 90 dias e envie requisições fragmentadas:

interface DateSpan {
  from: string;
  to: string;
}

/**
 * Split a large date range into consecutive spans of at most maxDays (default: 90)
 */
export function splitDateRange(startDateStr: string, endDateStr: string, maxDays = 90): DateSpan[] {
  const spans: DateSpan[] = [];
  let currentStart = new Date(startDateStr);
  const end = new Date(endDateStr);

  while (currentStart <= end) {
    const chunkEnd = new Date(currentStart);
    chunkEnd.setUTCDate(chunkEnd.getUTCDate() + (maxDays - 1));
    const effectiveEnd = chunkEnd < end ? chunkEnd : end;

    spans.push({
      from: currentStart.toISOString().slice(0, 10),
      to: effectiveEnd.toISOString().slice(0, 10),
    });

    const nextStart = new Date(effectiveEnd);
    nextStart.setUTCDate(nextStart.getUTCDate() + 1);
    currentStart = nextStart;
  }

  return spans;
}

/**
 * Backfill token daily prices across multiple 90-day chunks
 */
export async function backfillTokenDailyPrices(
  chain: string,
  token: string,
  startDate: string,
  endDate: string,
  apiKey: string
) {
  const chunks = splitDateRange(startDate, endDate, 90);
  const allDailyPrices = [];

  for (const chunk of chunks) {
    const url = new URL(`https://api.blockvectra.com/v1/data/${chain}/dex/prices`);
    url.searchParams.set("token", token);
    url.searchParams.set("from", chunk.from);
    url.searchParams.set("to", chunk.to);

    const res = await fetch(url, {
      headers: { "x-api-key": apiKey },
    });

    if (!res.ok) {
      throw new Error(`Failed to fetch span ${chunk.from}..${chunk.to}: HTTP ${res.status}`);
    }

    const json = await res.json();
    allDailyPrices.push(...json.data);
  }

  return allDailyPrices;
}

Capacity and CU usage calculations

Cada endpoint da Data API mede o consumo em Compute Units (CU). O peso de CU por chamada para data.dex_prices e o consumo estimado para backfills de tokens são calculados abaixo:

Peso do métododata.dex_prices: 15 CU / call
  • Preenchimento histórico de 1 ano de preços diários para 200 tokens: com um intervalo máximo de 90 dias por requisição, cobrir 365 dias requer 5 partes por token, totalizando 1,000 chamadas. O consumo total é de 15,000 CU (aprox. <0.1% da cota do ciclo do plano gratuito), cerca de <$0.01 a preço de tabela.
  • Manutenção diária (atualização de 200 tokens uma vez ao dia): 200 chamadas/dia (3,000 CU/dia), totalizando aproximadamente 6,000 chamadas por ciclo de 30 dias (90,000 CU, aprox. 0.3% da cota gratuita), cerca de <$0.01/mês a preço de tabela.

Ao escalar o volume de backfill ou necessitar de maior concorrência de requisições, recarregue on-chain na página de faturamento do console para fazer upgrade para uma conta paga. Para tarifas ativas e conversões de unidades, consulte a página de preços.

Next steps

Última atualização:

Nesta página