Дневные цены 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 никогда не возвращается. Если вашему приложению требуются детальные транзакции свопов, а не дневные агрегаты, используйте GET /{chain}/dex/swaps (см. справочник Data API).
Параметры запроса и ограничения
Маршрут эндпоинта — GET https://api.blockvectra.com/v1/data/{chain}/dex/prices. Все запросы требуют аутентификации путем передачи API key в заголовке x-api-key.
Эндпоинт принимает следующие параметры запроса:
| Параметр | Расположение | Тип | Обязательный | Описание |
|---|---|---|---|---|
chain | путь | string | Да | Идентификатор сети, например robinhood_mainnet |
token | query | string | Да | 20-байтовый адрес базового токена, 0x необязателен, регистр не имеет значения |
quote | query | string | Нет | Необязательный 20-байтовый адрес котируемого токена для ограничения одной парой база/котировка |
from | query | date string | Да | Начальная дата UTC, включительно, YYYY-MM-DD |
to | query | date string | Да | Конечная дата 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(string): дата UTC в форматеYYYY-MM-DD.token(string): 20-байтовый адрес базового токена в шестнадцатеричном формате нижнего регистра с префиксом0x.token_symbol(string илиnull): символ базового токена.token_name(string илиnull): отображаемое название базового токена.quote_token(string): адрес котируемого актива. Нулевой адрес (0x0000000000000000000000000000000000000000) обозначает нативный ETH в качестве котируемого актива.quote_symbol(string илиnull): символ котируемого актива ("ETH", когдаquote_tokenявляется нулевым адресом).quote_name(string илиnull): отображаемое название котируемого актива ("Ether", когдаquote_tokenявляется нулевым адресом).base_decimals(integer илиnull): количество десятичных знаков базового токена (0–255).quote_decimals(integer илиnull): количество десятичных знаков котируемого актива (18, когдаquote_tokenявляется нулевым адресом).
Объем и количество сделок
swap_count(integer): количество свопов в этой строке.base_volume_raw(string): атомарный объем базового актива в виде десятичной строки беззнакового целого числа (UInt256String).quote_volume_raw(string): атомарный объем котируемого актива в виде десятичной строки беззнакового целого числа (UInt256String).base_volume(string илиnull): человекочитаемый объем базового токена, масштабированный поbase_decimals, в видеDecimalString;null, еслиbase_decimalsнеизвестно.quote_volume(string илиnull): объем котируемого актива, масштабированный по его десятичным знакам, в видеDecimalStringилиnull.
Индикаторы цен и 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.
Поля точных дробей
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): временная метка обновления этой строки (временная метка UTC в формате ISO-8601).
Метаданные ответа (meta)
chain: идентификатор сети.chain_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.
Последнее обновление:
Развертывание контракта
Разверните Hello.sol в EVM-сети с помощью Foundry или Hardhat 2, проверьте chain ID, квитанцию транзакции и ответ контракта.
Историческое состояние EVM
Различие между аутентифицированными окнами состояния, историей без ключа и диапазонами логов. Выбор фиксированного блока для eth_call и диагностика ошибок state_window.