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ètre | Emplacement | Type | Requis | Description |
|---|---|---|---|---|
chain | path | string | Oui | Identifiant de la chaîne, par ex. robinhood_mainnet |
token | query | string | Oui | Adresse du base token sur 20 octets, 0x facultatif, indifférent à la casse |
quote | query | string | Non | Adresse facultative du quote token sur 20 octets pour restreindre à une seule paire base/quote |
from | query | date string | Oui | Date de début UTC, incluse, YYYY-MM-DD |
to | query | date string | Oui | Date 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,fromouto), syntaxe d'adressetoken/quoteinvalide, dates calendairesYYYY-MM-DDinvalides, oufromest postérieur àto. - HTTP 409 (
span_exceeded) :to - fromest supérieur à 90 jours. - HTTP 404 (
unknown_chain) :{chain}n'est pas une chaîne répertoriée parGET /chains. - HTTP 422 (
no_coverage) : la chaîne ne prend pas en charge la fonctionnalité du jeu de donnéesdex_prices. - HTTP 503 (
unavailable) : service temporairement indisponible ; réessayez selon l'en-têteRetry-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 formatYYYY-MM-DD.token(string) : adresse du base token sur 20 octets en hexadécimal préfixé par0xen minuscules.token_symbol(string ounull) : symbole du base token.token_name(string ounull) : 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 ounull) : symbole de l'actif quote ("ETH"lorsquequote_tokenest l'adresse de zéros).quote_name(string ounull) : nom d'affichage de l'actif quote ("Ether"lorsquequote_tokenest l'adresse de zéros).base_decimals(integer ounull) : décimales du base token (0–255).quote_decimals(integer ounull) : décimales de l'actif quote (18lorsquequote_tokenest 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 ounull) : volume du base token lisible par l'humain ajusté parbase_decimalssous forme deDecimalString;nulllorsquebase_decimalsest inconnu.quote_volume(string ounull) : volume de la quote ajusté par les décimales de la quote sous forme deDecimalString, ounull.
Indicateurs de prix et VWAP
vwap(string ounull) : prix moyen pondéré par le volume sous forme deDecimalString, ounull.first_price(string ounull) : indicateur de premier prix sous forme deDecimalString, ounull.last_price(string ounull) : indicateur de dernier prix sous forme deDecimalString, ounull.min_price(string ounull) : indicateur de prix minimum sous forme deDecimalString, ounull.max_price(string ounull) : indicateur de prix maximum sous forme deDecimalString, ounull.
Champs de fraction exacte
first_price_numerator/first_price_denominator(string) : numérateur et dénominateur entiers exacts pourfirst_price(UInt256String).last_price_numerator/last_price_denominator(string) : numérateur et dénominateur entiers exacts pourlast_price(UInt256String).min_price_numerator/min_price_denominator(string) : numérateur et dénominateur entiers exacts pourmin_price(UInt256String).max_price_numerator/max_price_denominator(string) : numérateur et dénominateur entiers exacts pourmax_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 êtrenull:nullsignifie 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 :
- 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.
- 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 :
data.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
- Parcourir le répertoire des jeux de données pour voir chaque jeu de données indexé par BlockVectra.
- Consulter le forfait gratuit et les tarifs pour vérifier ce que comprend votre compte.
- Se connecter à la console pour créer une clé API.
Dernière mise à jour :
Déploiement de contrat
Déployez Hello.sol sur un réseau EVM avec Foundry ou Hardhat 2, vérifiez le Chain ID, et inspectez le reçu de transaction et la réponse du contrat.
État historique de l'EVM
Distinguez les fenêtres d'état authentifiées, l'historique sans clé et les plages de logs. Choisissez un bloc fixe pour eth_call et diagnostiquez les erreurs state_window.