Щоденні ціни DEX OHLC та VWAP для токена з точними дробами
Отримуйте щоденні ціни DEX OHLC та VWAP через Data API, обробляйте точні раціональні дроби в TypeScript і Python та ефективно виконуйте бекфіл історичних даних.
Що являє собою набір даних щоденних цін DEX
Набір даних DEX від BlockVectra індексує торговельну активність децентралізованих бірж та розраховує агреговані щоденні показники цін. Ендпоінт щоденних цін DEX (getDexPrices) надає щоденну середньозважену за обсягом ціну (VWAP), цінові індикатори (поля first_price, last_price, min_price та max_price) і показники обсягу для вказаного токена за заданий діапазон дат.
Доступність цього набору даних різниться між мережами; перелік мереж, що надають цей набір даних, визначається на сторінці Підтримувані мережі.
Цей ендпоінт не підтримує пагінацію: всі відповідні щоденні записи в межах запитаного діапазону дат повертаються безпосередньо в полі data, а поле next_cursor ніколи не повертається. Якщо вашому застосунку потрібні детальні транзакції обміну (swaps), а не щоденні агреговані дані, використовуйте GET /{chain}/dex/swaps (дивіться довідник Data API).
Параметри запиту та обмеження
Маршрут ендпоінта — GET https://api.blockvectra.com/v1/data/{chain}/dex/prices. Усі запити вимагають автентифікації шляхом передачі вашого API key у заголовку x-api-key.
Ендпоінт приймає такі параметри запиту:
| Параметр | Розташування | Тип | Обов'язковий | Опис |
|---|---|---|---|---|
chain | path | рядок | Так | Ідентифікатор мережі, наприклад robinhood_mainnet |
token | query | рядок | Так | 20-байтна адреса базового токена, префікс 0x необов'язковий, будь-який регістр |
quote | query | рядок | Ні | Необов'язкова 20-байтна адреса котирувального токена для обмеження запиту однією парою base/quote |
from | query | рядок дати | Так | Початкова дата за UTC, включно, YYYY-MM-DD |
to | query | рядок дати | Так | Кінцева дата за UTC, включно, YYYY-MM-DD. Різниця to - from має бути <= 90 днів |
Обмеження та коди помилок
Коли запит порушує обмеження, 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.
Приклади запитів
У наведених нижче прикладах запитуються щоденні ціни DEX для базового токена за вересень 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"Детальний довідник полів
Кожен запис у масиві data представляє агреговані щоденні показники DEX для пари токенів за відповідну дату UTC:
Базовий та котирувальний активи
day(рядок): дата UTC у форматіYYYY-MM-DD.token(рядок): 20-байтна адреса базового токена в шістнадцятковому форматі в нижньому регістрі з префіксом0x.token_symbol(рядок абоnull): символ базового токена.token_name(рядок абоnull): відображувана назва базового токена.quote_token(рядок): адреса котирувального активу. Нульова адреса (0x0000000000000000000000000000000000000000) позначає нативний ETH як котирувальний актив.quote_symbol(рядок абоnull): символ котирувального активу ("ETH", якщоquote_token— нульова адреса).quote_name(рядок абоnull): відображувана назва котирувального активу ("Ether", якщоquote_token— нульова адреса).base_decimals(ціле число абоnull): кількість десяткових знаків базового токена (0–255).quote_decimals(ціле число абоnull): кількість десяткових знаків котирувального активу (18, якщоquote_token— нульова адреса).
Обсяг і кількість угод
swap_count(ціле число): кількість операцій обміну (swap) для цього рядка.base_volume_raw(рядок): атомарний обсяг базового токена у вигляді десяткового рядка беззнакового цілого числа (UInt256String).quote_volume_raw(рядок): атомарний обсяг котирувального токена у вигляді десяткового рядка беззнакового цілого числа (UInt256String).base_volume(рядок абоnull): зручний для читання людиною обсяг базового токена, масштабований заbase_decimals, у форматіDecimalString;null, якщоbase_decimalsневідомо.quote_volume(рядок абоnull): обсяг котирувального активу, масштабований за кількістю десяткових знаків, у форматіDecimalString, абоnull.
Цінові індикатори та VWAP
vwap(рядок абоnull): середньозважена за обсягом ціна у форматіDecimalString, абоnull.first_price(рядок абоnull): індикатор початкової ціни (першої ціни) у форматіDecimalString, абоnull.last_price(рядок абоnull): індикатор кінцевої ціни (останньої ціни) у форматіDecimalString, абоnull.min_price(рядок абоnull): індикатор мінімальної ціни у форматіDecimalString, абоnull.max_price(рядок абоnull): індикатор максимальної ціни у форматіDecimalString, абоnull.
Поля точних дробів
first_price_numerator/first_price_denominator(рядок): точні цілочисельні чисельник і знаменник дляfirst_price(UInt256String).last_price_numerator/last_price_denominator(рядок): точні цілочисельні чисельник і знаменник дляlast_price(UInt256String).min_price_numerator/min_price_denominator(рядок): точні цілочисельні чисельник і знаменник дляmin_price(UInt256String).max_price_numerator/max_price_denominator(рядок): точні цілочисельні чисельник і знаменник дляmax_price(UInt256String).refreshed_at(рядок): мітка часу оновлення для цього рядка (UTC-мітка часу за стандартом ISO-8601).
Метадані відповіді (meta)
chain: ідентифікатор мережі.chain_slug: канонічний ідентифікатор мережі у верхньому регістрі (slug).chain_external_id: ідентифікатор мережі у форматі CAIP-2.as_of_block: найновіший повністю записаний блок мережі (повідомляється цим набором даних, не зіставляється з параметрами запиту).coverage: класифікація покриття (для цього ендпоінта повідомляється"full").refreshed_at: мітка часу оновлення метаданих. Може бутиnull: значенняnullозначає, що час оновлення цих даних невідомий і їх слід вважати застарілими; ендпоінти на основі блоків завжди повертають значення.
Чому ціни використовують точні чисельники та знаменники
Стандартні числа в JSON покладаються на числа з рухомою комою подвійної точності IEEE-754, які мають обмеження точності:
- Усічення чисел з рухомою комою та похибка накопичення: значення Float64 забезпечують лише 53 біти точності, а ділення кількостей токенів призводить до похибки округлення, яка накопичується під час обчислень.
- Безпека передавання: представлення значень у вигляді десяткових рядків (
UInt256String) гарантує, що числа передаються через HTTP без втрати точності в парсерах JSON.
Надаючи точні цілочисельні чисельник і знаменник для цінових індикаторів, BlockVectra забезпечує можливість точних математичних розрахунків без перетворення в числа з рухомою комою.
Обробка точних дробів у 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}`;
}Обробка точних дробів у Python
Python надає модулі стандартної бібліотеки, створені спеціально для обчислень із раціональними та десятковими числами: 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}")Бекфіл щоденних цін за один рік
Щоб виконати бекфіл даних за один рік (365 днів) у межах 90-денного ліміту на один запит, розділіть повний діапазон дат на послідовні вікна тривалістю не більше 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;
}Розрахунок пропускної здатності та використання CU
Кожен ендпоінт Data API вимірює споживання в Compute Units (CU). Вага в CU за один виклик для data.dex_prices та розрахункове споживання для бекфілу токенів наведені нижче:
data.dex_prices: 15 CU / call- Поповнення щоденних цін за 1 рік для 200 токенів: з максимальним інтервалом у 90 дн. на запит охоплення 365 дн. потребує 5 частин на токен, загалом 1,000 викликів. Загальне споживання становить 15,000 CU (приблизно <0.1% від ліміту циклу безкоштовного плану), близько <$0.01 за прайс-листом.
- Щоденне оновлення (оновлення 200 токенів один раз на день): 200 викликів/день (3,000 CU/день), загалом приблизно 6,000 викликів за цикл у 30 дн. (90,000 CU, приблизно 0.3% від безкоштовної квоти), близько <$0.01/місяць за прайс-листом.
При збільшенні обсягу бекфілу або необхідності вищої кількості одночасних запитів здійсніть ончейн-поповнення на сторінці білінгу в консолі, щоб перейти на платний акаунт. Чинні тарифи та конвертацію одиниць дивіться на сторінці цін.
Наступні кроки
- Перегляньте каталог наборів даних, щоб ознайомитися з усіма наборами даних, які індексує BlockVectra.
- Дізнайтеся про безкоштовний план і ціни, щоб перевірити, що включено у ваш акаунт.
- Увійдіть до консолі, щоб створити API key.
Востаннє оновлено:
Безкоштовний план
Дізнайтеся, що покриває безкоштовний план на основі реальної ваги методів, із розрахунками під типові завдання та шляхами оновлення.
Base
Підключайтеся до Base mainnet за допомогою публічного RPC URL або API key. Використовуйте приклади з curl та viem, перевіряйте підтримувані методи й ліміти та переглядайте статус Data API.