Case Study/Studium przypadku z produkcji

Jak goldprice.dev wycenia złoto w walutach lokalnych

Jak goldprice.dev łączy ceny metalu w USD z kursami FX z exchangerate.dev, aby dostarczać ceny złota w walutach lokalnych bez ukrywania granic aktualności danych.

MMexchangerate.dev·Jul 16, 2026·7 min czytania

goldprice.dev i exchangerate.dev to produkty siostrzane prowadzone przez tę samą firmę. W produkcji goldprice.dev odpowiada za kontrakt cenowy metalu, a exchangerate.dev dostarcza składnik FX dla obsługiwanych walut płynnych. Ta granica ma znaczenie: lokalna cena złota zawiera dwie obserwacje rynkowe, a świeżość jednej z nich nie sprawia, że druga też jest świeża.

Key points
goldprice.dev odpowiada za cenę metalu i publiczną odpowiedź konwersji; exchangerate.dev dostarcza składnik FX.
Publiczny endpoint /v1/convert w goldprice.dev zapewnia ścieżkę produkcyjną w jednym wywołaniu.
Deweloperzy mogą pobierać oba API osobno, gdy potrzebują możliwego do audytu pochodzenia danych.
Przechowuj niezależnie computed_at dla złota oraz data_updated_at, timestamp, source i market_session dla FX.
Przeliczone ceny to orientacyjne wartości rynkowe, a nie wykonalne notowania dealerskie ani rozliczeniowe.

Granica produkcyjna

goldprice.dev zaczyna od obserwacji metalu w USD. exchangerate.dev dostarcza odpowiadającą jej obserwację FX USD-do-lokalnej dla obsługiwanych walut płynnych. goldprice.dev odpowiada następnie za kontrakt konwersji specyficzny dla metalu, obejmujący jednostki, obsługiwane symbole, walidację i ostateczną odpowiedź.

To jawnie ujawniona integracja między produktami siostrzanymi, a nie niezależna rekomendacja klienta. Jej wartość jako studium przypadku jest operacyjna: API FX dostarcza realny, produkcyjny składnik danych, a produkt korzystający zachowuje odpowiedzialność za własną domenę.

Formuła konwersji

Złoto jest zwykle kwotowane jako USD za uncję trojańską. Lokalne wyświetlanie zazwyczaj wymaga kwoty w walucie za gram. Najpierw przelicz wagę, a następnie zastosuj kurs wymiany USD:

formula · USD/oz to local currency/gramcopy
const GRAMS_PER_TROY_OZ = 31.1035;

function localGoldPerGram(usdPerTroyOz, usdToLocalRate) {
  return (usdPerTroyOz / GRAMS_PER_TROY_OZ) * usdToLocalRate;
}

Stała wagowa jest niezmienna. Dwa wejścia rynkowe już nie: zarówno notowanie złota, jak i kurs FX mają własny czas obserwacji i własne zasady aktualności.

Ścieżka produkcyjna w jednym wywołaniu

Dla wywołujących granicą produkcyjną jest goldprice.dev `/v1/convert`. Łączy on składniki metalu i FX za jednym endpointem świadomym metalu i nie wymaga klucza API. Ten przykład pobiera wartość jednego grama złota w rupiach indonezyjskich:

javascript · one-request conversioncopy
const params = new URLSearchParams({
  from: "XAU",
  to: "IDR",
  amount: "1",
  unit: "gram",
});

const response = await fetch(
  `https://api.goldprice.dev/v1/convert?${params}`,
);

if (!response.ok) {
  throw new Error(`goldprice.dev returned ${response.status}`);
}

const conversion = await response.json();
console.log(conversion.result, conversion.to, conversion.timestamp);

Ta ścieżka utrzymuje mały kontrakt dla wywołującego: jedno żądanie, jedna ilość, jedna jednostka metalu i jedna waluta docelowa. Jej pojedynczy timestamp nie dowodzi niezależnie aktualności obu składników rynkowych, więc konsumenci, którzy muszą audytować świeżość FX, powinni użyć poniższej ścieżki dwuskładnikowej.

Możliwa do audytu integracja dwuskładnikowa

Pobieraj oba API, gdy musisz zachować znacznik czasu każdego źródła, przechowywać wejścia w pamięci podręcznej niezależnie lub wyjaśnić, który składnik jest nieaktualny. goldprice.dev spot dostarcza cenę złota w USD za uncję trojańską; exchangerate.dev dostarcza kurs USD-do-lokalnej.

javascript · explicit gold and FX legscopy
const GRAMS_PER_TROY_OZ = 31.1035;

async function getGoldInCurrencies(currencies) {
  const symbols = currencies.join(",");
  const [spotResponse, fxResponse] = await Promise.all([
    fetch("https://api.goldprice.dev/v1/spot/XAU-USD-SPOT"),
    fetch(`https://api.exchangerate.dev/v1/latest/USD?symbols=${symbols}`),
  ]);

  if (!spotResponse.ok || !fxResponse.ok) {
    throw new Error("A market-data request failed");
  }

  const spot = await spotResponse.json();
  const fx = await fxResponse.json();
  const usdPerGram = Number(spot.price) / GRAMS_PER_TROY_OZ;

  return {
    goldComputedAt: spot.computed_at,
    fxDataUpdatedAt: fx.data_updated_at,
    fxResponseTimestamp: fx.timestamp,
    fxSource: fx.source,
    fxMarketSession: fx.market_session,
    prices: Object.fromEntries(
      currencies.map((currency) => [
        currency,
        usdPerGram * Number(fx.rates[currency]),
      ]),
    ),
  };
}

const result = await getGoldInCurrencies(["EUR", "IDR", "JPY"]);
Znacznik czasu odpowiedzi to nie znacznik czasu rynkowego
Zachowaj spot.computed_at dla obserwacji złota oraz fx.data_updated_at dla najstarszej obserwacji FX wchodzącej w skład odpowiedzi. Znacznik czasu FX (timestamp) to moment zbudowania odpowiedzi; source i market_session dodają kontekst klasy danych i sesji. Nie zastępuj tych pól przez Date.now().

Dlaczego usługi pozostają rozdzielone

Integracja nie zamienia exchangerate.dev w cały silnik wyceny złota. Pozostaje on warstwą FX. Utrzymanie tej granicy w sposób jawny zapobiega temu, by aktualność waluty, aktualność metalu i reguły konwersji specyficzne dla produktu zlewały się w jedną niejednoznaczną wartość.

  • goldprice.dev może udostępnić mały, specyficzny dla metalu interfejs, bez zmuszania wywołujących do samodzielnego składania typowej ścieżki.
  • exchangerate.dev zachowuje ogólny kontrakt FX, który jest użyteczny poza domeną metali.
  • Konsumenci wrażliwi na audyt mogą pobierać i przechowywać obie obserwacje niezależnie.
  • Każda usługa może raportować błędy i aktualność, używając słownictwa właściwego dla swoich danych rynkowych.

Jawnie obsługuj nieaktualne lub brakujące składniki

Połączona cena nie powinna przetrwać, jeśli którekolwiek wejście jest brakujące, zerowe, nienumeryczne lub wykracza poza akceptowane przez twój produkt okno aktualności. Zachowaj ostatnią prawidłową wartość tylko wtedy, gdy interfejs oznacza ją oryginalnymi czasami obserwacji.

  • Sprawdź obie odpowiedzi HTTP przed wykonaniem obliczeń.
  • Odrzucaj ceny i kursy, które nie są skończone lub nie są dodatnie.
  • Ustaw osobne progi aktualności dla złota i FX.
  • Traktuj market_session: weekend jako kontekst, a nie jako dowód, że przeniesiony kurs jest aktualny.
  • Loguj parę walutową oraz oba bazowe czasy obserwacji wraz z błędami konwersji.

Zaokrąglaj do wyświetlania, nie podczas obliczeń

Zachowaj pełną precyzję przez cały czas mnożenia i pozwól, aby to lokalizacja wyświetlania decydowała o ostatecznej liczbie miejsc po przecinku. Intl.NumberFormat obsługuje symbole walut i grupowanie, nie zmieniając przy tym wartości bazowej:

javascript · locale-aware displaycopy
function formatPrice(amount, currency, locale) {
  return new Intl.NumberFormat(locale, {
    style: "currency",
    currency,
  }).format(amount);
}

console.log(formatPrice(result.prices.IDR, "IDR", "id-ID"));
console.log(formatPrice(result.prices.JPY, "JPY", "ja-JP"));

Traktuj wynik jako wartość orientacyjną

Obliczona wartość rynkowa nie jest ceną detaliczną monety ani sztabki. Premie dealerskie, podatki, koszty wytworzenia, opłaty płatnicze i wykonalne spready FX pozostają poza tą formułą. Oznaczaj wynik jako orientacyjny, chyba że twoja aplikacja dodaje rzeczywiste notowanie dealerskie wraz z jego warunkami handlowymi.

Co udowadnia to studium przypadku

goldprice.dev stanowi dowód pierwszej strony na to, że exchangerate.dev potrafi dostarczyć składnik FX produkcyjnego procesu wyceny. Nie jest to niezależny dowód społeczny. Użyteczny dowód jest węższy i odtwarzalny: deweloperzy mogą wywołać te same publiczne produkty, zachować oba czasy obserwacji i samodzielnie zweryfikować obliczenia.

MM
exchangerate.dev
Notatki z produkcyjnej integracji dla deweloperów.

Keep reading

ReferenceJak czytać source i market_sessionRead TutorialKonwersja walut w JavaScript i Node.jsRead GuideOrientacyjne a wykonalne kursy FXRead