トークンの日次 DEX OHLC と VWAP(厳密な分数付き)

Data API から日次 DEX OHLC 価格と VWAP を照会し、TypeScript と Python で厳密な有理分数を処理し、過去データを効率的にバックフィルします。

What the DEX daily prices dataset is

BlockVectra の DEX データセットは、分散型取引所での取引アクティビティをインデックス化し、集計された日次価格指標を計算します。DEX 日次価格エンドポイント(getDexPrices)は、指定された日付範囲における指定トークンの日次出来高加重平均価格(VWAP)、価格指標(first_price、last_price、min_price、max_price フィールド)、および出来高指標を提供します。

このデータセットの提供状況はネットワークによって異なります。このデータセットを提供するチェーンについては、対応チェーンページを参照してください。

このエンドポイントはページネーションされません。要求された日付範囲内のすべての一致する日次行が data 内に直接返され、next_cursor は一切存在しません。日次集計ではなく詳細なスワップトランザクションをアプリケーションが必要とする場合は、GET /{chain}/dex/swaps を使用してください(Data API リファレンスを参照)。

Request parameters and limits

エンドポイントのルートは GET https://api.blockvectra.com/v1/data/{chain}/dex/prices です。すべてのリクエストにおいて、x-api-key ヘッダーに API key を指定して認証を行う必要があります。

このエンドポイントは以下のクエリパラメータを受け付けます:

ParameterLocationTypeRequiredDescription
chainpathstringYesチェーン識別子(例:robinhood_mainnet)
tokenquerystringYes20 バイトのベーストークンアドレス(0x は任意、大文字小文字不問)
quotequerystringNo特定のベース/クォートペアに限定するための任意の 20 バイトクォートトークンアドレス
fromquerydate stringYesUTC 開始日(当日含む)、YYYY-MM-DD
toquerydate stringYesUTC 終了日(当日含む)、YYYY-MM-DD。to - from は <= 90 日である必要があります

Constraints and error codes

リクエストが制約に違反した場合、API は構造化されたエラーボディ {"error":{"code","message"}} を返します:

  • HTTP 400 (bad_request):必須クエリパラメータ(token、from、to)の不足、無効な token/quote アドレス構文、無効な YYYY-MM-DD カレンダー日付、または from が to より後である場合。
  • HTTP 409 (span_exceeded):to - from が 90 日を超えている場合。
  • HTTP 404 (unknown_chain):{chain} が GET /chains にリストされているチェーンではない場合。
  • HTTP 422 (no_coverage):チェーンが dex_prices データセット機能に対応していない場合。
  • HTTP 503 (unavailable):サービスが一時的に利用不可。Retry-After ヘッダーに従って再試行してください。

Request examples

以下の例では、2026 年 9 月のベーストークンの日次 DEX 価格を照会します:

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

data 内の各エントリは、その UTC 日付におけるトークンペアの集計された日次 DEX 指標を表します:

Token and quote assets

  • day (string):YYYY-MM-DD 形式の UTC 日付。
  • token (string):先頭に 0x が付いた小文字の 16 進数表記の 20 バイトのベーストークンアドレス。
  • token_symbol (string または null):ベーストークンのシンボル。
  • token_name (string または null):ベーストークンの表示名。
  • quote_token (string):クォート資産のアドレス。すべてゼロのアドレス(0x0000000000000000000000000000000000000000)は、クォート資産としてのネイティブ ETH を表します。
  • quote_symbol (string または null):クォート資産のシンボル(quote_token が全ゼロアドレスの場合は "ETH")。
  • quote_name (string または null):クォート資産の表示名(quote_token が全ゼロアドレスの場合は "Ether")。
  • base_decimals (integer または null):ベーストークンの小数点桁数(0〜255)。
  • quote_decimals (integer または null):クォート資産の小数点桁数(quote_token が全ゼロアドレスの場合は 18)。

Volume and trade counts

  • swap_count (integer):この行のスワップ回数。
  • base_volume_raw (string):符号なし整数の 10 進数文字列(UInt256String)としての原子単位ベース出来高。
  • quote_volume_raw (string):符号なし整数の 10 進数文字列(UInt256String)としての原子単位クォート出来高。
  • base_volume (string または null):DecimalString として base_decimals でスケールされた可読なベーストークン出来高。base_decimals が不明な場合は null。
  • quote_volume (string または null):DecimalString としてクォートの小数点桁数でスケールされたクォート出来高、または null。

Price indicators and VWAP

  • vwap (string または null):DecimalString としての出来高加重平均価格、または null。
  • first_price (string または null):DecimalString としての始値指標、または null。
  • last_price (string または null):DecimalString としての終値指標、または null。
  • min_price (string または null):DecimalString としての最安値指標、または null。
  • max_price (string または null):DecimalString としての最高値指標、または null。

Exact fraction fields

  • first_price_numerator / first_price_denominator (string):first_price の厳密な整数の分子と分母(UInt256String)。
  • last_price_numerator / last_price_denominator (string):last_price の厳密な整数の分子と分母(UInt256String)。
  • min_price_numerator / min_price_denominator (string):min_price の厳密な整数の分子と分母(UInt256String)。
  • max_price_numerator / max_price_denominator (string):max_price の厳密な整数の分子と分母(UInt256String)。
  • refreshed_at (string):この行の更新タイムスタンプ(ISO-8601 UTC タイムスタンプ)。

Envelope metadata (meta)

  • chain:チェーン識別子。
  • chain_slug:大文字の正規チェーンスラッグ。
  • chain_external_id:CAIP-2 形式のチェーン識別子。
  • as_of_block:チェーンの完全に書き込まれた最新ブロック(このデータセットによって報告され、リクエストパラメータとは照合されません)。
  • coverage:対応範囲の分類(このエンドポイントでは "full" を報告)。
  • refreshed_at:メタデータの更新タイムスタンプ。null の場合があります:null はこのデータの更新時刻が不明であり、古くなったデータとして扱う必要があることを意味します。ブロックベースのエンドポイントは常に値を返します。

Why prices use exact numerators and denominators

標準的な JSON の数値は IEEE-754 倍精度浮動小数点数に依存しており、精度の限界が存在します:

  1. 浮動小数点の切り捨てと誤差の蓄積:Float64 の値は 53 ビットの精度しか提供せず、トークン数量の除算では計算を重ねるごとに丸め誤差が蓄積します。
  2. 送信の安全性:値を 10 進数文字列(UInt256String)としてフォーマットすることで、JSON パーサーで精度を損なうことなく数値が HTTP 経由で転送されます。

価格指標に対して厳密な整数の分子と分母を提供することで、BlockVectra は浮動小数点変換を行わずに厳密な数学的計算を可能にします。

Handling exact fractions in TypeScript (BigInt)

TypeScript では、浮動小数点変換を行わずに、ネイティブの BigInt を使用してたすき掛けによる比較や固定小数点変換を実行できます:

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

Python は、有理数および 10 進数の計算専用に構築された標準ライブラリモジュール fractions.Fraction および 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

90 日間の期間制限内で 1 年分のデータ(365 日)をバックフィルするには、日付範囲全体を最大 90 日間の連続したウィンドウに分割し、チャンク化されたリクエストを発行します:

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

Data API のすべてのエンドポイントは、消費量を Compute Units(CU)単位で計測します。data.dex_prices のコールあたりの CU 重み付けと、トークンバックフィルの推定消費量は以下のように計算されます:

メソッドの重み付けdata.dex_prices: 15 CU / call
  • 200 トークンの 1 年分の日次価格をバックフィル: リクエストあたりの最大範囲は 90 日であり、365 日分をカバーするにはトークンあたり 5 チャンク、合計 1,000 回の呼び出しが必要です。 総消費量は 15,000 CU(無料プランのサイクル枠の約 <0.1%)、定価換算で約 <$0.01。
  • 日常のメンテナンス(毎日 200 トークンを 1 回更新): 200 コール/日(3,000 CU/日)、30 日のサイクルあたり約 6,000 コール(90,000 CU、無料枠の約 0.3%)、定価換算で月額約 <$0.01。

バックフィル量を拡張する場合や、より高いリクエスト同時実行数が必要な場合は、コンソールの請求ページでオンチェーンチャージを行い、有料アカウントにアップグレードしてください。有効な料金レートとユニット換算については、料金ページを参照してください。

Next steps

最終更新:

このページの目次