Tägliche DEX-OHLC und VWAP für einen Token mit exakten Brüchen

Tägliche DEX-OHLC-Preise und VWAP über die Data-API abfragen, exakte rationale Brüche in TypeScript und Python verarbeiten und historische Daten effizient nacherfassen.

Was der DEX-Tagespreis-Datensatz ist

Der DEX-Datensatz von BlockVectra indiziert Handelsaktivitäten auf dezentralen Börsen und berechnet aggregierte tägliche Preiskennzahlen. Der Endpunkt für tägliche DEX-Preise (getDexPrices) liefert den täglichen volumengewichteten Durchschnittspreis (VWAP), Preisindikatoren (Felder first_price, last_price, min_price und max_price) sowie Volumenkennzahlen für einen bestimmten Token über einen angegebenen Datumsbereich.

Die Verfügbarkeit dieses Datensatzes variiert je nach Netzwerk; Chains, die diesen Datensatz bereitstellen, unterliegen der Seite Unterstützte Chains.

Dieser Endpunkt ist nicht paginiert: Alle übereinstimmenden täglichen Zeilen innerhalb der angeforderten Zeitspanne werden direkt in data zurückgegeben, und next_cursor ist niemals vorhanden. Wenn Ihre Anwendung granulare Swap-Transaktionen anstelle von täglichen Aggregaten benötigt, verwenden Sie GET /{chain}/dex/swaps (siehe die Data-API-Referenz).

Anfrageparameter und Limits

Die Endpunkt-Route lautet GET https://api.blockvectra.com/v1/data/{chain}/dex/prices. Alle Anfragen erfordern eine Authentifizierung durch Angabe Ihres API keys im x-api-key-Header.

Der Endpunkt akzeptiert die folgenden Abfrageparameter:

ParameterPositionTypErforderlichBeschreibung
chainpathstringJaChain-Bezeichner, z. B. robinhood_mainnet
tokenquerystringJa20-Byte-Basis-Token-Adresse, 0x optional, Groß-/Kleinschreibung beliebig
quotequerystringNeinOptionale 20-Byte-Quote-Token-Adresse zur Beschränkung auf ein einzelnes Basis/Quote-Paar
fromqueryDatums-StringJaUTC-Startdatum, inklusive, YYYY-MM-DD
toqueryDatums-StringJaUTC-Enddatum, inklusive, YYYY-MM-DD. to - from muss <= 90 Tage sein

Einschränkungen und Fehlercodes

Wenn eine Anfrage gegen Einschränkungen verstößt, gibt die API einen strukturierten Fehler-Body {"error":{"code","message"}} zurück:

  • HTTP 400 (bad_request): Fehlende erforderliche Abfrageparameter (token, from oder to), ungültige token/quote-Adresssyntax, ungültige YYYY-MM-DD-Kalenderdaten oder from liegt nach to.
  • HTTP 409 (span_exceeded): to - from beträgt mehr als 90 Tage.
  • HTTP 404 (unknown_chain): {chain} ist keine von GET /chains aufgelistete Chain.
  • HTTP 422 (no_coverage): Die Chain unterstützt die dex_prices-Datensatzfunktion nicht.
  • HTTP 503 (unavailable): Dienst vorübergehend nicht verfügbar; gemäß dem Retry-After-Header wiederholen.

Anfragebeispiele

Die folgenden Beispiele fragen tägliche DEX-Preise für einen Basis-Token im September 2026 ab:

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"

Detaillierte Feldreferenz

Jeder Eintrag in data stellt aggregierte tägliche DEX-Kennzahlen für das Token-Paar an diesem UTC-Datum dar:

Basis- und Quote-Assets

  • day (String): UTC-Datum im Format YYYY-MM-DD.
  • token (String): 20-Byte-Basis-Token-Adresse in kleingeschriebenem Hexadezimalformat mit 0x-Präfix.
  • token_symbol (String oder null): Symbol des Basis-Tokens.
  • token_name (String oder null): Anzeigename des Basis-Tokens.
  • quote_token (String): Adresse des Quote-Assets. Die reine Null-Adresse (0x0000000000000000000000000000000000000000) repräsentiert natives ETH als Quote-Asset.
  • quote_symbol (String oder null): Symbol des Quote-Assets ("ETH", wenn quote_token die Null-Adresse ist).
  • quote_name (String oder null): Anzeigename des Quote-Assets ("Ether", wenn quote_token die Null-Adresse ist).
  • base_decimals (Integer oder null): Dezimalstellen des Basis-Tokens (0–255).
  • quote_decimals (Integer oder null): Dezimalstellen des Quote-Assets (18, wenn quote_token die Null-Adresse ist).

Volumen und Trade-Zählungen

  • swap_count (Integer): Swap-Anzahl für diese Zeile.
  • base_volume_raw (String): Atomares Basis-Volumen als vorzeichenloser Integer-Dezimal-String (UInt256String).
  • quote_volume_raw (String): Atomares Quote-Volumen als vorzeichenloser Integer-Dezimal-String (UInt256String).
  • base_volume (String oder null): Für Menschen lesbares Basis-Token-Volumen, skaliert um base_decimals als DecimalString; null, wenn base_decimals unbekannt ist.
  • quote_volume (String oder null): Quote-Volumen, skaliert um Quote-Dezimalstellen als DecimalString, oder null.

Preisindikatoren und VWAP

  • vwap (String oder null): Volumengewichteter Durchschnittspreis als DecimalString oder null.
  • first_price (String oder null): Erster Preisindikator als DecimalString oder null.
  • last_price (String oder null): Letzter Preisindikator als DecimalString oder null.
  • min_price (String oder null): Minimaler Preisindikator als DecimalString oder null.
  • max_price (String oder null): Maximaler Preisindikator als DecimalString oder null.

Exakte Bruchfelder

  • first_price_numerator / first_price_denominator (String): Exakter ganzzahliger Zähler und Nenner für first_price (UInt256String).
  • last_price_numerator / last_price_denominator (String): Exakter ganzzahliger Zähler und Nenner für last_price (UInt256String).
  • min_price_numerator / min_price_denominator (String): Exakter ganzzahliger Zähler und Nenner für min_price (UInt256String).
  • max_price_numerator / max_price_denominator (String): Exakter ganzzahliger Zähler und Nenner für max_price (UInt256String).
  • refreshed_at (String): Aktualisierungszeitstempel für diese Zeile (ISO-8601 UTC-Zeitstempel).

Envelope-Metadaten (meta)

  • chain: Chain-Bezeichner.
  • chain_slug: Kanonischer, großgeschriebener Chain-Slug.
  • chain_external_id: Im CAIP-2-Format formatierter Chain-Bezeichner.
  • as_of_block: Der neueste vollständig geschriebene Block der Chain (von diesem Datensatz gemeldet, nicht mit Anfrageparametern abgeglichen).
  • coverage: Abdeckungsklassifizierung (meldet "full" für diesen Endpunkt).
  • refreshed_at: Zeitstempel der Metadaten-Aktualisierung. Kann null sein: null bedeutet, dass der Aktualisierungszeitpunkt dieser Daten unbekannt ist und sie als veraltet betrachtet werden sollten; blockbasierte Endpunkte geben immer einen Wert zurück.

Warum Preise exakte Zähler und Nenner verwenden

Standard-JSON-Zahlen basieren auf IEEE-754-Gleitkommazahlen mit doppelter Genauigkeit, die Präzisionseinschränkungen aufweisen:

  1. Gleitkomma-Kappung und -Drift: Float64-Werte bieten nur 53 Bit Präzision, und das Teilen von Token-Mengen führt zu Rundungsungenauigkeiten, die sich über Berechnungen hinweg verstärken.
  2. Übertragungssicherheit: Die Formatierung von Werten als Dezimal-Strings (UInt256String) stellt sicher, dass Zahlen über HTTP übertragen werden, ohne in JSON-Parsern an Präzision zu verlieren.

Durch die Bereitstellung des exakten ganzzahligen Zählers und Nenners für Preisindikatoren ermöglicht BlockVectra exakte mathematische Berechnungen ohne Gleitkommakonvertierung.

Verarbeitung exakter Brüche in TypeScript (BigInt)

In TypeScript können Sie natives BigInt für Kreuzmultiplikationsvergleiche und Festkommakonvertierungen ohne Gleitkommakonvertierung verwenden:

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

// 1. Verhältnisvergleich ohne Gleitkommakonvertierung: prüfen, ob Schlusskurs höher als Eröffnungskurs ist
// a / b > c / d  ist äquivalent zu  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. Bruch in Festkomma-Dezimal-String mit beliebiger Skalierung konvertieren (ohne Gleitkommaverlust)
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}`;
}

Verarbeitung exakter Brüche in Python

Python bietet Standardbibliotheksmodule, die speziell für rationale und dezimale Berechnungen entwickelt wurden: fractions.Fraction und decimal.Decimal.

from decimal import Decimal, getcontext
from fractions import Fraction

# 1. Exakte rationale Berechnungen mit 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"])
)

# Exakte Preisdifferenz ohne Rundungsfehler durch Gleitkommazahlen
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. Dezimalarithmetik mit beliebiger Genauigkeit mit 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}")

Nacherfassung eines Jahres an Tagespreisen

Um Daten für ein ganzes Jahr (365 Tage) innerhalb des 90-Tage-Spanne-Limits nachzuerfassen, teilen Sie den gesamten Datumsbereich in aufeinanderfolgende Fenster von maximal 90 Tagen auf und führen Sie segmentierte Anfragen durch:

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

/**
 * Einen großen Datumsbereich in aufeinanderfolgende Zeitspannen von maximal maxDays aufteilen (Standard: 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;
}

/**
 * Tägliche Token-Preise über mehrere 90-Tage-Segmente hinweg nacherfassen
 */
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;
}

Kapazität und CU-Verbrauchsberechnungen

Jeder Data-API-Endpunkt erfasst den Verbrauch in Compute Units (CU). Das CU-Gewicht pro Aufruf für data.dex_prices und der geschätzte Verbrauch für Token-Backfills werden unten berechnet:

Methodengewichtungdata.dex_prices: 15 CU / call
  • Nachträgliches Laden von 1 Jahr täglicher Preise für 200 Token: Bei einer maximalen Spanne von 90 Tagen pro Anfrage erfordert die Abdeckung von 365 Tagen 5 Abschnitte pro Token, insgesamt 1,000 Aufrufe. Der Gesamtverbrauch beträgt 15,000 CU (ca. <0.1% des Freikontingents pro Zyklus), ca. <$0.01 zum Listenpreis.
  • Tägliche Wartung (Aktualisierung von 200 Token einmal pro Tag): 200 Aufrufe/Tag (3,000 CU/Tag), insgesamt etwa 6,000 Aufrufe pro 30-Tage-Zyklus (90,000 CU, ca. 0.3% des Freikontingents), ca. <$0.01/Monat zum Listenpreis.

Wenn Sie Ihr Backfill-Volumen skalieren oder eine höhere Anforderungs-Parallelität benötigen, laden Sie On-Chain auf der Abrechnungsseite der Konsole auf, um auf ein kostenpflichtiges Konto hochzustufen. Aktuelle Tarife und Einheitenumrechnungen finden Sie auf der Preisseite.

Nächste Schritte

Zuletzt aktualisiert:

Auf dieser Seite