OHLC et VWAP quotidiens DEX pour un token, avec fractions exactes

Interrogez les prix OHLC et le VWAP quotidiens des DEX depuis la Data API, gérez les fractions rationnelles exactes en TypeScript et Python, et rattrapez efficacement les données historiques.

En quoi consiste le jeu de données des prix quotidiens DEX

Le jeu de données DEX de BlockVectra indexe l'activité d'échange sur les plateformes décentralisées et calcule des métriques de prix quotidiennes agrégées. Le point de terminaison des prix quotidiens DEX (getDexPrices) fournit le prix moyen pondéré par le volume quotidien (VWAP), des indicateurs de prix (champs first_price, last_price, min_price et max_price), ainsi que des métriques de volume pour un token spécifique sur une plage de dates donnée.

La disponibilité de ce jeu de données varie selon les réseaux ; les chaînes fournissant ce jeu de données sont régies par la page des Chaînes prises en charge.

Ce point de terminaison n'est pas paginé : toutes les lignes quotidiennes correspondantes dans la plage de dates demandée sont renvoyées directement dans data, et next_cursor n'est jamais présent. Si votre application nécessite des transactions de swap granulaires plutôt que des agrégats quotidiens, utilisez GET /{chain}/dex/swaps (voir la Référence de la Data API).

Paramètres de requête et limites

La route du point de terminaison est GET https://api.blockvectra.com/v1/data/{chain}/dex/prices. Toutes les requêtes nécessitent une authentification en fournissant votre clé API dans l'en-tête x-api-key.

Le point de terminaison accepte les paramètres de requête suivants :

ParamètreEmplacementTypeRequisDescription
chainpathstringOuiIdentifiant de la chaîne, par ex. robinhood_mainnet
tokenquerystringOuiAdresse du base token sur 20 octets, 0x facultatif, indifférent à la casse
quotequerystringNonAdresse facultative du quote token sur 20 octets pour restreindre à une seule paire base/quote
fromquerydate stringOuiDate de début UTC, incluse, YYYY-MM-DD
toquerydate stringOuiDate de fin UTC, incluse, YYYY-MM-DD. to - from doit être <= 90 jours

Contraintes et codes d'erreur

Lorsqu'une requête enfreint les contraintes, l'API renvoie un corps d'erreur structuré {"error":{"code","message"}} :

  • HTTP 400 (bad_request) : paramètres de requête requis manquants (token, from ou to), syntaxe d'adresse token/quote invalide, dates calendaires YYYY-MM-DD invalides, ou from est postérieur à to.
  • HTTP 409 (span_exceeded) : to - from est supérieur à 90 jours.
  • HTTP 404 (unknown_chain) : {chain} n'est pas une chaîne répertoriée par GET /chains.
  • HTTP 422 (no_coverage) : la chaîne ne prend pas en charge la fonctionnalité du jeu de données dex_prices.
  • HTTP 503 (unavailable) : service temporairement indisponible ; réessayez selon l'en-tête Retry-After.

Exemples de requêtes

Les exemples suivants interrogent les prix quotidiens DEX pour un base token sur l'ensemble du mois de septembre 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"

Référence détaillée des champs

Chaque entrée dans data représente des métriques quotidiennes agrégées DEX pour la paire de tokens à cette date UTC :

Actifs token et quote

  • day (string) : date UTC au format YYYY-MM-DD.
  • token (string) : adresse du base token sur 20 octets en hexadécimal préfixé par 0x en minuscules.
  • token_symbol (string ou null) : symbole du base token.
  • token_name (string ou null) : nom d'affichage du base token.
  • quote_token (string) : adresse de l'actif quote. L'adresse composée uniquement de zéros (0x0000000000000000000000000000000000000000) représente l'ETH natif comme actif quote.
  • quote_symbol (string ou null) : symbole de l'actif quote ("ETH" lorsque quote_token est l'adresse de zéros).
  • quote_name (string ou null) : nom d'affichage de l'actif quote ("Ether" lorsque quote_token est l'adresse de zéros).
  • base_decimals (integer ou null) : décimales du base token (0–255).
  • quote_decimals (integer ou null) : décimales de l'actif quote (18 lorsque quote_token est l'adresse de zéros).

Volume et décompte des transactions

  • swap_count (integer) : nombre de swaps pour cette ligne.
  • base_volume_raw (string) : volume atomique du token de base sous forme de chaîne décimale d'entier non signé (UInt256String).
  • quote_volume_raw (string) : volume atomique de la quote sous forme de chaîne décimale d'entier non signé (UInt256String).
  • base_volume (string ou null) : volume du base token lisible par l'humain ajusté par base_decimals sous forme de DecimalString ; null lorsque base_decimals est inconnu.
  • quote_volume (string ou null) : volume de la quote ajusté par les décimales de la quote sous forme de DecimalString, ou null.

Indicateurs de prix et VWAP

  • vwap (string ou null) : prix moyen pondéré par le volume sous forme de DecimalString, ou null.
  • first_price (string ou null) : indicateur de premier prix sous forme de DecimalString, ou null.
  • last_price (string ou null) : indicateur de dernier prix sous forme de DecimalString, ou null.
  • min_price (string ou null) : indicateur de prix minimum sous forme de DecimalString, ou null.
  • max_price (string ou null) : indicateur de prix maximum sous forme de DecimalString, ou null.

Champs de fraction exacte

  • first_price_numerator / first_price_denominator (string) : numérateur et dénominateur entiers exacts pour first_price (UInt256String).
  • last_price_numerator / last_price_denominator (string) : numérateur et dénominateur entiers exacts pour last_price (UInt256String).
  • min_price_numerator / min_price_denominator (string) : numérateur et dénominateur entiers exacts pour min_price (UInt256String).
  • max_price_numerator / max_price_denominator (string) : numérateur et dénominateur entiers exacts pour max_price (UInt256String).
  • refreshed_at (string) : horodatage d'actualisation pour cette ligne (horodatage UTC ISO-8601).

Métadonnées d'enveloppe (meta)

  • chain : identifiant de la chaîne.
  • chain_slug : slug canonique de la chaîne en majuscules.
  • chain_external_id : identifiant de chaîne formaté selon CAIP-2.
  • as_of_block : le bloc le plus récent entièrement écrit de la chaîne (rapporté par ce jeu de données, non vérifié par rapport aux paramètres de requête).
  • coverage : classification de la couverture (indique "full" pour ce point de terminaison).
  • refreshed_at : horodatage d'actualisation des métadonnées. Peut être null : null signifie que l'heure de mise à jour de ces données est inconnue et qu'elles doivent être traitées comme périmées ; les points de terminaison basés sur les blocs renvoient toujours une valeur.

Pourquoi les prix utilisent des numérateurs et dénominateurs exacts

Les nombres JSON standards reposent sur des nombres à virgule flottante double précision IEEE-754, qui présentent des limites de précision :

  1. Troncature et dérive en virgule flottante : les valeurs Float64 n'offrent que 53 bits de précision, et la division de quantités de tokens produit une dérive d'arrondi qui se cumule au fil des calculs.
  2. Sécurité de transport : le formatage des valeurs sous forme de chaînes décimales (UInt256String) garantit que les nombres circulent sur HTTP sans perte de précision dans les parseurs JSON.

En fournissant le numérateur et le dénominateur entiers exacts pour les indicateurs de prix, BlockVectra permet des calculs mathématiques exacts sans conversion en virgule flottante.

Gestion des fractions exactes en TypeScript (BigInt)

En TypeScript, vous pouvez utiliser les BigInt natifs pour les comparaisons par produits en croix et les conversions en virgule fixe sans conversion en virgule flottante :

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

// 1. Comparaison de ratios sans conversion en virgule flottante : vérifier si le cours de clôture est supérieur au cours d'ouverture
// a / b > c / d  équivaut à  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. Convertir la fraction en une chaîne décimale à virgule fixe avec une échelle arbitraire (sans perte de virgule flottante)
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}`;
}

Gestion des fractions exactes en Python

Python propose des modules de bibliothèque standard spécialement conçus pour les calculs rationnels et décimaux : fractions.Fraction et decimal.Decimal.

from decimal import Decimal, getcontext
from fractions import Fraction

# 1. Calculs rationnels exacts avec 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"])
)

# Delta de prix exact sans erreur d'arrondi en virgule flottante
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. Arithmétique décimale à précision arbitraire avec 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}")

Rattrapage d'une année de prix quotidiens

Pour rattraper une année de données (365 jours) dans la limite d'intervalle de 90 jours, divisez la plage complète de dates en fenêtres consécutives d'au maximum 90 jours et envoyez des requêtes par segments :

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

/**
 * Divise une grande plage de dates en intervalles consécutifs d'au maximum maxDays (par défaut : 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;
}

/**
 * Rattrape les prix quotidiens de tokens sur plusieurs segments de 90 jours
 */
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;
}

Calculs de capacité et d'utilisation des CU

Chaque point de terminaison de la Data API mesure la consommation en Compute Units (CU). La pondération en CU par appel pour data.dex_prices et la consommation estimée pour les rattrapages de tokens sont calculées ci-dessous :

Poids de la méthodedata.dex_prices: 15 CU / call
  • Rattrapage d'un an de prix quotidiens pour 200 tokens : avec une durée maximale de 90 jours par requête, couvrir 365 jours nécessite 5 segments par token, soit un total de 1,000 appels. La consommation totale est de 15,000 CU (env. <0.1% du quota de cycle du forfait gratuit), environ <$0.01 au tarif catalogue.
  • Maintenance quotidienne (actualisation de 200 tokens une fois par jour) : 200 appels/jour (3,000 CU/jour), pour un total d'environ 6,000 appels par cycle de 30 jours (90,000 CU, env. 0.3% du quota gratuit), environ <$0.01/mois au tarif catalogue.

Pour augmenter votre volume de rattrapage ou obtenir une concurrence de requêtes plus élevée, rechargez on-chain sur la page Facturation de la console pour passer à un compte payant. Pour les tarifs actifs et les conversions d'unités, consultez la page Tarifs.

Prochaines étapes

Dernière mise à jour :

Sur cette page