代幣的每日 DEX OHLC 與 VWAP,使用精確分數
用 getDexPrices 端點按代幣與起迄日期查詢每日 VWAP 與開高低收:傳回開高低收價格欄位與分子分母精確分數,單次跨度不得超過 90 天,超出傳回 409 span_exceeded,並提供分段回填寫法。
什麼是 DEX 每日價格資料集
BlockVectra 的 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):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):計價資產符號(當quote_token為全零地址時為"ETH")。quote_name(string 或null):計價資產顯示名稱(當quote_token為全零地址時為"Ether")。base_decimals(integer 或null):基礎代幣小數位數(0–255)。quote_decimals(integer 或null):計價資產小數位數(當quote_token為全零地址時為18)。
成交量與交易筆數
swap_count(integer):此資料列的交換筆數。base_volume_raw(string):以最小單位表示的基礎代幣成交量,為無正負號的十進位整數字串(UInt256String)。quote_volume_raw(string):以最小單位表示的計價代幣成交量,為無正負號的十進位整數字串(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:標準的大寫鏈 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. 不經浮點數轉換的比率比較:檢查收盤價是否高於開盤價
// a / b > c / d 等價於 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. 將分數轉換為指定小數位數的定點十進位字串(不損失浮點精確度)
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. 使用 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"])
)
# 不經浮點數四捨五入誤差的精確價格變動
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. 使用 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}")回填一年的每日價格
若要在 90 天跨度限制內回填一整年(365 天)的資料,請將完整日期範圍切分為最多 90 天的連續視窗,並發出分段請求:
interface DateSpan {
from: string;
to: string;
}
/**
* 將大型日期範圍切分為最多 maxDays(預設: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;
}
/**
* 跨多個 90 天分段回填代幣每日價格
*/
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 端點都會以計算單位(CU)計量消耗。data.dex_prices 的每次呼叫 CU 權重,以及代幣回填的預估消耗,計算如下:
data.dex_prices: 15 CU / call- 回填 200 個代幣一年日線:單次請求最大跨度為 90 天,一年 365 天需分 5 段請求,單個代幣需 5 次呼叫,總計 1,000 次呼叫。 總計消耗 15,000 CU(約佔單用量週期免費額度的 <0.1%),按標價換算約 <$0.01。
- 日常維護(每天重新整理 200 個代幣的最新日線):每天呼叫 200 次(每天消耗 3,000 CU),每個 30 天週期約呼叫 6,000 次,消耗 90,000 CU(約佔免費額度的 0.3%),按標價約每月 <$0.01。
當你需要擴充回填量或需要更高的請求並行量時,請在控制台帳單頁面進行鏈上儲值,以升級為付費帳戶。關於目前的費率與單位換算,請參閱定價頁面。
下一步
最後更新: