정확한 분수를 활용한 토큰의 일별 DEX OHLC 및 VWAP
Data API에서 일별 DEX OHLC 가격과 VWAP을 조회하고, TypeScript 및 Python에서 정확한 유리수 분수를 처리하며, 과거 데이터를 효율적으로 백필하세요.
DEX 일별 가격 데이터셋이란
BlockVectra의 DEX 데이터셋은 탈중앙화 거래소(DEX) 거래 활동을 인덱싱하고 집계된 일일 가격 지표를 계산합니다. 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입니다. 모든 요청은 x-api-key 헤더에 API key를 제공하여 인증해야 합니다.
엔드포인트는 다음 쿼리 파라미터를 허용합니다:
| 파라미터 | 위치 | 타입 | 필수 여부 | 설명 |
|---|---|---|---|---|
chain | path | 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헤더에 따라 재시도하세요.
요청 예제
다음 예제는 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"상세 필드 레퍼런스
data의 각 항목은 해당 UTC 날짜의 토큰 쌍에 대한 집계된 일일 DEX 지표를 나타냅니다:
토큰 및 호가 자산
day(string):YYYY-MM-DD형식의 UTC 날짜.token(string): 소문자0x접두사가 붙은 16진수 형태의 20바이트 기준 토큰 주소.token_symbol(string 또는null): 기준 토큰 심볼.token_name(string 또는null): 기준 토큰 표시 이름.quote_token(string): 호가 자산 주소. 전체가 0인 주소(0x0000000000000000000000000000000000000000)는 네이티브 ETH가 호가 자산임을 나타냅니다.quote_symbol(string 또는null): 호가 자산 심볼 (quote_token이 전체 0 주소인 경우"ETH").quote_name(string 또는null): 호가 자산 표시 이름 (quote_token이 전체 0 주소인 경우"Ether").base_decimals(integer 또는null): 기준 토큰 소수점 자리수 (0–255).quote_decimals(integer 또는null): 호가 자산 소수점 자리수 (quote_token이 전체 0 주소인 경우18).
거래량 및 거래 횟수
swap_count(integer): 이 행의 스왑 횟수.base_volume_raw(string): 부호 없는 정수 10진수 문자열(UInt256String) 형태의 원자 단위 기준 거래량.quote_volume_raw(string): 부호 없는 정수 10진수 문자열(UInt256String) 형태의 원자 단위 호가 거래량.base_volume(string 또는null):base_decimals로 환산된 사람이 읽을 수 있는 기준 토큰 거래량(DecimalString).base_decimals를 알 수 없는 경우null.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): 이 행의 갱신 타임스탬프 (ISO-8601 UTC 타임스탬프).
봉투 메타데이터 (meta)
chain: 체인 식별자.chain_slug: 정규화된 대문자 체인 슬러그.chain_external_id: CAIP-2 형식의 체인 식별자.as_of_block: 체인의 완전히 기록된 최신 블록 (이 데이터셋에서 보고하며, 요청 파라미터에 대해 검사되지 않음).coverage: 커버리지 분류 (이 엔드포인트의 경우"full"로 보고됨).refreshed_at: 메타데이터 갱신 타임스탬프.null일 수 있음:null은 이 데이터의 업데이트 시간을 알 수 없으며 오래된 것으로 간주해야 함을 의미합니다(블록 기반 엔드포인트는 항상 값을 반환함).
가격에 정확한 분자와 분모를 사용하는 이유
표준 JSON 숫자는 IEEE-754 배정밀도 부동 소수점에 의존하므로 다음과 같은 정밀도 한계가 있습니다:
- 부동 소수점 잘림 및 드리프트: Float64 값은 53비트의 정밀도만 제공하며, 토큰 수량을 나눌 때 계산 전반에 걸쳐 반올림 오차가 복합적으로 누적됩니다.
- 전송 안전성: 값을 10진수 문자열(
UInt256String)로 포맷팅하면 숫자가 JSON 파서에서 정밀도를 잃지 않고 HTTP를 통해 전달됩니다.
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은 유리수 및 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}")1년치 일별 가격 백필하기
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;
}용량 및 CU 사용량 계산
모든 Data API 엔드포인트는 Compute Unit(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입니다.
백필 볼륨을 확장하거나 더 높은 요청 동시성이 필요한 경우 콘솔 결제 페이지에서 온체인 충전을 통해 유료 계정으로 업그레이드하세요. 유효 요율 및 단위 변환은 요금 페이지를 참조하세요.
다음 단계
- 데이터셋 디렉터리 둘러보기: BlockVectra가 인덱싱하는 모든 데이터셋 확인.
- 무료 플랜 및 요금 확인: 내 계정에 포함된 혜택 확인.
- 콘솔 로그인: API key 생성.
최종 수정일: