Daily DEX OHLC and VWAP for a token, with exact fractions
Query daily DEX OHLC prices and VWAP from the Data API, handle exact rational fractions in TypeScript and Python, and backfill historical data efficiently.
What the DEX Daily Prices dataset is
BlockVectra's DEX dataset indexes decentralized exchange trade activity and computes aggregated daily pricing metrics. The DEX daily prices endpoint (getDexPrices) provides the daily volume-weighted average price (VWAP), price indicators (fields first_price, last_price, min_price, and max_price), and volume metrics for a specified token over a given date range.
Availability of this dataset varies across networks; chains providing this dataset are subject to the Supported Chains page.
This endpoint is not paginated: all matching daily rows within the requested date span are returned directly in data, and next_cursor is never present. If your application requires granular swap transactions rather than daily aggregates, use GET /{chain}/dex/swaps (see the Data API Reference).
Request parameters and specification limits
The endpoint route is GET https://dev-api.blockvectra.network/v1/data/{chain}/dex/prices. All requests require authentication by supplying your API key in the x-api-key header.
The endpoint accepts the following query parameters:
| Parameter | Location | Type | Required | Description |
|---|---|---|---|---|
chain | path | string | Yes | Chain identifier, e.g. robinhood_mainnet |
token | query | string | Yes | 20-byte base token address, 0x optional, either case |
quote | query | string | No | Optional 20-byte quote token address to restrict to a single base/quote pair |
from | query | date string | Yes | UTC start date, inclusive, YYYY-MM-DD |
to | query | date string | Yes | UTC end date, inclusive, YYYY-MM-DD. to - from must be <= 90 days |
Specification constraints and error codes
When a request violates specification constraints, the API returns a structured error body {"error":{"code","message"}}:
- HTTP 400 (
bad_request): Missing required query parameters (token,from, orto), invalidtoken/quoteaddress syntax, invalidYYYY-MM-DDcalendar dates, orfromis afterto. - HTTP 409 (
span_exceeded):to - fromis more than 90 days. - HTTP 404 (
unknown_chain):{chain}is not a chain listed byGET /chains. - HTTP 422 (
no_coverage): The chain does not support thedex_pricesdataset capability. - HTTP 503 (
unavailable): Service temporarily unavailable; retry according to theRetry-Afterheader.
Request examples
The following examples query daily DEX prices for a base token across September 2026:
curl -s "https://dev-api.blockvectra.network/v1/data/robinhood_mainnet/dex/prices?token=0x2260fac5e5542a773aa44fbcfedf7c193bc2c599&from=2026-09-01&to=2026-09-30" \
-H "x-api-key: $BLOCKVECTRA_API_KEY"Detailed field reference
Each entry in data represents aggregated daily DEX metrics for the token pair on that UTC date:
Token and quote assets
day(string): UTC date inYYYY-MM-DDformat.token(string): 20-byte base token address in lowercase0x-prefixed hex.token_symbol(string ornull): Base token symbol.token_name(string ornull): Base token display name.quote_token(string): Quote asset address. The all-zero address (0x0000000000000000000000000000000000000000) represents native ETH as the quote asset.quote_symbol(string ornull): Quote asset symbol ("ETH"whenquote_tokenis the all-zero address).quote_name(string ornull): Quote asset display name ("Ether"whenquote_tokenis the all-zero address).base_decimals(integer ornull): Base token decimals (0–255).quote_decimals(integer ornull): Quote asset decimals (18whenquote_tokenis the all-zero address).
Volume and trade counts
swap_count(integer): Swap count for this row.base_volume_raw(string): Atomic base volume as an unsigned integer decimal string (UInt256String).quote_volume_raw(string): Atomic quote volume as an unsigned integer decimal string (UInt256String).base_volume(string ornull): Human-readable base token volume scaled bybase_decimalsas aDecimalString;nullwhenbase_decimalsis unknown.quote_volume(string ornull): Quote volume scaled by quote decimals as aDecimalString, ornull.
Price indicators and VWAP
vwap(string ornull): Volume-weighted average price as aDecimalString, ornull.first_price(string ornull): First price indicator as aDecimalString, ornull.last_price(string ornull): Last price indicator as aDecimalString, ornull.min_price(string ornull): Minimum price indicator as aDecimalString, ornull.max_price(string ornull): Maximum price indicator as aDecimalString, ornull.
Exact fraction fields
first_price_numerator/first_price_denominator(string): Exact integer numerator and denominator forfirst_price(UInt256String).last_price_numerator/last_price_denominator(string): Exact integer numerator and denominator forlast_price(UInt256String).min_price_numerator/min_price_denominator(string): Exact integer numerator and denominator formin_price(UInt256String).max_price_numerator/max_price_denominator(string): Exact integer numerator and denominator formax_price(UInt256String).refreshed_at(string): Refresh timestamp for this row (ISO-8601 UTC timestamp).
Envelope metadata (meta)
chain: Chain identifier.chain_slug: Canonical uppercase chain slug.chain_external_id: CAIP-2 formatted chain identifier.as_of_block: The indexed head block number from which this response's finality watermark was computed (reported by this dataset, not checked against request parameters).finalized_block: Reorg-safety watermark block number (not consensus finality).coverage: Coverage classification (reports"full"for this endpoint).refreshed_at: Metadata refreshed timestamp.
Why prices use exact numerators and denominators
On-chain DEX pricing originates from Automated Market Maker (AMM) liquidity pool reserve ratios or swap formulas.
Standard JSON numbers rely on IEEE-754 double-precision floats, which present precision limitations:
- Floating-point truncation and drift: Float64 values provide only 53 bits of precision, and dividing token quantities yields rounding drift that compounds across calculations.
- Transport safety: Formatting values as decimal strings (
UInt256String) ensures numbers travel across HTTP without losing precision in JSON parsers.
By providing the exact integer numerator and denominator for price indicators, BlockVectra enables exact mathematical calculations without floating-point conversion. Quantitative models, arbitrage monitors, and financial accounting systems can evaluate prices and ratios without floating-point inaccuracies.
Handling exact fractions in TypeScript (BigInt)
In TypeScript, you can use native BigInt for cross-multiplication comparisons and fixed-point conversions without floating-point conversion:
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 provides standard library modules built specifically for rational and decimal calculations: fractions.Fraction and 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
To backfill a year of data (365 days) within the 90-day span limit, divide the full date range into consecutive windows of at most 90 days and issue chunked requests:
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://dev-api.blockvectra.network/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
Every Data API endpoint meters consumption in Compute Units (CU). The per-call CU weight for data.dex_prices and the estimated consumption for token backfills are calculated below. All figures are computed at build time from active platform plan data:
data.dex_prices: 15 CU / call- Backfilling 1 year of daily prices for 200 tokens: with a max span of 90 days per request, covering 365 days takes 5 chunks per token, totaling 1,000 calls. Total consumption is 15,000 CU (approx 0.1% of the free plan cycle allowance), about $0.0015 at list price.
- Daily maintenance (refreshing 200 tokens once per day): 200 calls/day (3,000 CU/day), totaling approximately 6,000 calls per 30-day cycle (90,000 CU, approx 0.3% of the free quota), about $0.009/month at list price.
When scaling your backfill volume or requiring higher request concurrency, top up your account balance in the Console to upgrade to a paid account. For active rates and unit conversions, see the Pricing page.
Daily on-chain metrics for tokenized stocks with the Data API
Learn how to query daily tokenized stock leaderboards and historical metrics with the Data API, covering fields, encoding conventions, pagination, and usage estimates.
One key, many chains: switching an example to another chain
The same API key works on every supported chain. Learn how URLs are structured, how to discover chains programmatically, and how balances and limits are pooled.