# OHLC dan VWAP DEX harian untuk token dengan pecahan eksak

> Source: https://docs.blockvectra.com/id/guides/dex-daily-prices/

## Apa itu dataset harga DEX harian

Dataset DEX BlockVectra mengindeks aktivitas perdagangan bursa terdesentralisasi dan menghitung metrik harga harian agregat. Endpoint harga DEX harian (`getDexPrices`) menyediakan harga rata-rata tertimbang volume (VWAP) harian, indikator harga (bidang `first_price`, `last_price`, `min_price`, dan `max_price`), serta metrik volume untuk token tertentu selama rentang tanggal yang ditentukan.

Ketersediaan dataset ini berbeda antarjaringan; rantai yang menyediakan dataset ini mengikuti halaman [Rantai yang Didukung](https://docs.blockvectra.com/id/chains/).

Endpoint ini tidak menggunakan paginasi: semua baris harian yang cocok dalam rentang tanggal permintaan dikembalikan langsung dalam `data`, dan `next_cursor` tidak pernah disertakan. Jika aplikasi Anda memerlukan transaksi swap individual alih-alih agregat harian, gunakan `GET /{chain}/dex/swaps` (lihat [Referensi Data API](https://docs.blockvectra.com/en/api/data/)).

## Parameter permintaan dan batas

Rute endpoint adalah `GET https://api.blockvectra.com/v1/data/{chain}/dex/prices`. Semua permintaan memerlukan autentikasi dengan menyertakan API key Anda pada header `x-api-key`.

Endpoint ini menerima parameter kueri berikut:

| Parameter | Lokasi | Tipe        | Wajib | Deskripsi                                                                            |
| --------- | ------ | ----------- | ----- | ------------------------------------------------------------------------------------ |
| `chain`   | path   | string      | Ya    | Identitas rantai, misalnya `robinhood_mainnet`                                       |
| `token`   | query  | string      | Ya    | Alamat token dasar 20 byte, `0x` opsional, huruf besar atau kecil                    |
| `quote`   | query  | string      | Tidak | Alamat token kuotasi 20 byte opsional untuk membatasi ke satu pasangan dasar/kuotasi |
| `from`    | query  | date string | Ya    | Tanggal mulai UTC, inklusif, `YYYY-MM-DD`                                            |
| `to`      | query  | date string | Ya    | Tanggal akhir UTC, inklusif, `YYYY-MM-DD`. `to - from` harus `<= 90` hari            |

### Batasan dan kode error

Jika permintaan melanggar batasan, API mengembalikan body error terstruktur `{"error":{"code","message"}}`:

* **HTTP 400 (`bad_request`)**: Parameter kueri wajib (`token`, `from`, atau `to`) tidak disertakan, sintaks alamat `token`/`quote` tidak valid, tanggal kalender `YYYY-MM-DD` tidak valid, atau `from` berada setelah `to`.
* **HTTP 409 (`span_exceeded`)**: `to - from` lebih dari 90 hari.
* **HTTP 404 (`unknown_chain`)**: `{chain}` bukan rantai yang tercantum dalam `GET /chains`.
* **HTTP 422 (`no_coverage`)**: Rantai tidak mendukung kapabilitas dataset `dex_prices`.
* **HTTP 503 (`unavailable`)**: Layanan sementara tidak tersedia; coba lagi sesuai header `Retry-After`.

## Contoh permintaan

Contoh berikut mengueri harga DEX harian untuk token dasar sepanjang September 2026:

**cURL**

```bash
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"
```


  **TypeScript**

```ts
const url = new URL("https://api.blockvectra.com/v1/data/robinhood_mainnet/dex/prices");
url.searchParams.set("token", "0x1Cdad396DB64BDa184d5182A97Dd9B3C62100b7D");
url.searchParams.set("from", "2026-09-01");
url.searchParams.set("to", "2026-09-30");

const res = await fetch(url, {
  headers: {
    "x-api-key": process.env.BLOCKVECTRA_API_KEY!,
  },
});

if (!res.ok) {
  throw new Error(`Request failed with status ${res.status}`);
}

const body = await res.json();
console.log(body);
```


  **Python**

```python
import os
import requests

res = requests.get(
    "https://api.blockvectra.com/v1/data/robinhood_mainnet/dex/prices",
    params={
        "token": "0x1Cdad396DB64BDa184d5182A97Dd9B3C62100b7D",
        "from": "2026-09-01",
        "to": "2026-09-30",
    },
    headers={
        "x-api-key": os.environ["BLOCKVECTRA_API_KEY"],
    },
)
res.raise_for_status()
print(res.json())
```


## Referensi bidang terperinci

Setiap entri dalam `data` mewakili metrik DEX harian agregat untuk pasangan token pada tanggal UTC tersebut:

### Token dan aset kuotasi

* `day` (string): Tanggal UTC dalam format `YYYY-MM-DD`.
* `token` (string): Alamat token dasar 20 byte dalam heksadesimal huruf kecil dengan awalan `0x`.
* `token_symbol` (string atau `null`): Simbol token dasar.
* `token_name` (string atau `null`): Nama tampilan token dasar.
* `quote_token` (string): Alamat aset kuotasi. Alamat yang seluruhnya nol (`0x0000000000000000000000000000000000000000`) mewakili ETH native sebagai aset kuotasi.
* `quote_symbol` (string atau `null`): Simbol aset kuotasi (`"ETH"` jika `quote_token` adalah alamat yang seluruhnya nol).
* `quote_name` (string atau `null`): Nama tampilan aset kuotasi (`"Ether"` jika `quote_token` adalah alamat yang seluruhnya nol).
* `base_decimals` (integer atau `null`): Jumlah desimal token dasar (0–255).
* `quote_decimals` (integer atau `null`): Jumlah desimal aset kuotasi (`18` jika `quote_token` adalah alamat yang seluruhnya nol).

### Volume dan jumlah perdagangan

* `swap_count` (integer): Jumlah swap untuk baris ini.
* `base_volume_raw` (string): Volume dasar dalam unit atomik sebagai string desimal integer tanpa tanda (`UInt256String`).
* `quote_volume_raw` (string): Volume kuotasi dalam unit atomik sebagai string desimal integer tanpa tanda (`UInt256String`).
* `base_volume` (string atau `null`): Volume token dasar yang dapat dibaca manusia, diskalakan menurut `base_decimals` sebagai `DecimalString`; `null` jika `base_decimals` tidak diketahui.
* `quote_volume` (string atau `null`): Volume kuotasi yang diskalakan menurut jumlah desimal kuotasi sebagai `DecimalString`, atau `null`.

### Indikator harga dan VWAP

* `vwap` (string atau `null`): Harga rata-rata tertimbang volume sebagai `DecimalString`, atau `null`.
* `first_price` (string atau `null`): Indikator harga pertama sebagai `DecimalString`, atau `null`.
* `last_price` (string atau `null`): Indikator harga terakhir sebagai `DecimalString`, atau `null`.
* `min_price` (string atau `null`): Indikator harga minimum sebagai `DecimalString`, atau `null`.
* `max_price` (string atau `null`): Indikator harga maksimum sebagai `DecimalString`, atau `null`.

### Bidang pecahan eksak

* `first_price_numerator` / `first_price_denominator` (string): Pembilang dan penyebut integer eksak untuk `first_price` (`UInt256String`).
* `last_price_numerator` / `last_price_denominator` (string): Pembilang dan penyebut integer eksak untuk `last_price` (`UInt256String`).
* `min_price_numerator` / `min_price_denominator` (string): Pembilang dan penyebut integer eksak untuk `min_price` (`UInt256String`).
* `max_price_numerator` / `max_price_denominator` (string): Pembilang dan penyebut integer eksak untuk `max_price` (`UInt256String`).
* `refreshed_at` (string): Timestamp pembaruan untuk baris ini (timestamp UTC ISO-8601).

### Metadata struktur respons (`meta`)

* `chain`: Identitas rantai.
* `chain_slug`: Slug rantai kanonis dalam huruf besar.
* `chain_external_id`: Identitas rantai dalam format CAIP-2.
* `as_of_block`: Blok terbaru rantai yang sudah ditulis sepenuhnya (dilaporkan oleh dataset ini, tidak diperiksa terhadap parameter permintaan).
* `coverage`: Klasifikasi cakupan (melaporkan `"full"` untuk endpoint ini).
* `refreshed_at`: Timestamp pembaruan metadata. Dapat bernilai `null`: `null` berarti waktu pembaruan data ini tidak diketahui dan data harus dianggap usang; endpoint berbasis blok selalu mengembalikan nilai.

## Mengapa harga menggunakan pembilang dan penyebut eksak

Angka JSON standar menggunakan floating-point presisi ganda IEEE-754, yang memiliki keterbatasan presisi:

1. **Pemotongan dan penyimpangan floating-point**: Nilai Float64 hanya menyediakan presisi 53 bit, dan pembagian jumlah token menghasilkan penyimpangan pembulatan yang terakumulasi dalam perhitungan.
2. **Keamanan transmisi**: Memformat nilai sebagai string desimal (`UInt256String`) memastikan angka dikirim melalui HTTP tanpa kehilangan presisi di parser JSON.

Dengan menyediakan pembilang dan penyebut integer eksak untuk indikator harga, BlockVectra memungkinkan perhitungan matematika eksak tanpa konversi floating-point.

### Menangani pecahan eksak di TypeScript (BigInt)

Di TypeScript, Anda dapat menggunakan `BigInt` native untuk perbandingan dengan perkalian silang dan konversi fixed-point tanpa konversi floating-point:

```ts
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}`;
}
```

### Menangani pecahan eksak di Python

Python menyediakan modul pustaka standar yang khusus dibuat untuk perhitungan rasional dan desimal: `fractions.Fraction` dan `decimal.Decimal`.

```python
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}")
```

## Backfill harga harian selama satu tahun

Untuk melakukan backfill data satu tahun (365 hari) dalam batas rentang 90 hari, bagi seluruh rentang tanggal menjadi jendela berurutan yang masing-masing paling lama 90 hari dan kirim permintaan secara bertahap:

```ts
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;
}
```

## Perhitungan kapasitas dan penggunaan CU

Setiap endpoint Data API mengukur konsumsi dalam Compute Units (CU). Bobot CU per panggilan untuk `data.dex_prices` dan perkiraan konsumsi untuk backfill token dihitung di bawah:

- **Bobot metode:** `data.dex_prices` = 15 CU / panggilan.
- **Pengisian riwayat harga harian 1 tahun untuk 200 token:** dengan rentang maksimum 90 hari per permintaan, mencakup 365 hari memerlukan 5 bagian per token, dengan total 1,000 panggilan. Konsumsi total adalah 15,000 CU (sekitar <0.1% dari kuota siklus paket gratis), sekitar <$0.01 dengan harga terdaftar.
- **Pemeliharaan harian (menyegarkan 200 token sekali sehari):** 200 panggilan/hari (3,000 CU/hari), dengan total sekitar 6,000 panggilan per siklus 30 hari (90,000 CU, sekitar 0.3% dari kuota gratis), sekitar <$0.01/bulan dengan harga terdaftar.

Saat meningkatkan volume backfill atau memerlukan konkurensi permintaan yang lebih tinggi, lakukan top up on-chain pada [halaman Penagihan](https://console.blockvectra.com/billing/) di konsol untuk meningkatkan akun ke akun berbayar. Untuk tarif dan konversi unit terkini, lihat [halaman Harga](https://blockvectra.com/id/pricing/).

## Langkah selanjutnya

* [Telusuri direktori dataset](https://blockvectra.com/id/data/) untuk melihat setiap dataset yang diindeks oleh BlockVectra.
* [Lihat paket gratis dan harga](https://blockvectra.com/id/pricing/#free) untuk memeriksa apa yang termasuk dalam akun Anda.
* [Masuk ke konsol](https://console.blockvectra.com/login/?next=%2Fkeys%2F) untuk membuat API key.
