Historische Gold- und Silberpreise per API: 25 Jahre Tagesdaten
Historische Gold- und Silberpreise seit 2000 per /historical, /timeframe, /change und /ohlc abrufen, jahresweise nachladen, lokal speichern und visualisieren.
Welche Historie verfügbar ist
MetalAPI speichert pro Symbol und Tag einen Tagesbalken mit Eröffnungs-, Höchst-, Tiefst- und Schlusskurs. Für Gold und Silber sind das mehr als 25 Jahre Tagesdaten: genug, um langfristige Trends darzustellen, eine Preisregel an der Vergangenheit zu testen oder alte Rechnungen zum Preis des jeweiligen Tages neu zu bewerten.
| Kategorie | Symbole | Tageshistorie seit |
|---|---|---|
| Edelmetalle | XAU, XAG, XPT, XPD | 2000 |
| Industriemetalle und Energie | XCU, ALU, ZNC, HRC, WTI, BRENT und weitere | 2000 |
| Währungen | 57, darunter USD, EUR, GBP und JPY | 04.01.1999 |
| Kryptowährungen | 13, darunter BTC und ETH | 2014 |
Jeder Tarif kann die gesamte Historie abfragen. Die Tarife unterscheiden sich nur darin, wie viele Tage eine einzelne Zeitraumanfrage umfassen darf. Datumsangaben haben das Format YYYY-MM-DD in UTC, und die Werte eines Tages sind dessen Schlusskurse. Ein Datum vor Beginn der Historie eines Symbols liefert Fehler 300 (no_results).
Metallpreise vor Oktober 2026 sind aus Frontmonats-Futures abgeleitet und können daher leicht vom Spotpreis desselben Tages abweichen. Denken Sie daran, wenn Sie alte Werte mit Spotpreisen aus einer anderen Quelle vergleichen.
Vier Endpunkte decken die Arbeit mit historischen Daten ab: /historical für einen Tag, /timeframe für einen Zeitraum, /change für die Veränderung zwischen zwei Tagen und /ohlc für die Kerze eines Tages. Die folgenden Abschnitte behandeln sie der Reihe nach und bauen dann ein kleines lokales Archiv mit einem Chart darauf.
Ein Tag: /historical
Für die Schlusskurse eines einzelnen Tages setzen Sie das Datum in den Pfad. /historical?date=YYYY-MM-DD bewirkt dasselbe, und /yesterday ist eine Abkürzung für den vorherigen Tag (UTC):
curl "https://metalapi.com/api/v1/2024-01-15?currencies=XAU,XAG" \
-H "X-API-Key: $METALAPI_KEY"Die Antwort hat dieselbe Form wie bei /latest, ergänzt um historical: true. Dies sind die Beispielwerte aus der API-Referenz:
{
"success": true,
"timestamp": 1705276800,
"historical": true,
"date": "2024-01-15",
"base": "USD",
"rates": {
"XAU": 0.0004874244,
"USDXAU": 2051.6,
"XAG": 0.0431741646,
"USDXAG": 23.162
}
}USDXAU ist der Preis einer Feinunze Gold in der Basiswährung, XAU ihr Kehrwert. base und unit funktionieren wie gewohnt, base=EUR&unit=gram liefert also Euro pro Gramm für diesen Tag.
Wochenenden und Feiertage lassen die Anfrage nicht scheitern: Für einen Tag ohne Handel wird der Schlusskurs des letzten Handelstags zurückgegeben. Das date in der Antwort ist trotzdem der angefragte Tag. Wenn Sie wissen müssen, ob die Märkte geöffnet waren, führen Sie daher auf Ihrer Seite einen Handelskalender. Ein Datum in der Zukunft liefert Fehler 205 (invalid_date).
Zeiträume: /timeframe
Für eine Zeitreihe liefert /timeframe einen Eintrag pro Tag zwischen start_date und end_date (jeweils einschließlich), mit dem Datum als Schlüssel. /timeseries ist ein Alias, der die Antwort mit timeseries: true statt timeframe: true kennzeichnet.
curl "https://metalapi.com/api/v1/timeframe?start_date=2026-10-19&end_date=2026-10-23¤cies=XAU" \
-H "X-API-Key: $METALAPI_KEY"{
"success": true,
"timeframe": true,
"start_date": "2026-10-19",
"end_date": "2026-10-23",
"base": "USD",
"rates": {
"2026-10-19": { "XAU": 0.0002403788, "USDXAU": 4160.1 },
"2026-10-20": { "XAU": 0.0002413943, "USDXAU": 4142.6 },
"2026-10-21": { "XAU": 0.0002409639, "USDXAU": 4150 },
"2026-10-22": { "XAU": 0.0002462812, "USDXAU": 4060.4 },
"2026-10-23": { "XAU": 0.0002495072, "USDXAU": 4007.9 }
}
}Anders als der Endpunkt für einzelne Tage füllt /timeframe keine Lücken. Spot-Metalle werden von Freitag 17:00 Uhr bis Sonntag 17:00 Uhr New Yorker Zeit nicht gehandelt, daher können Wochenenden und Börsenfeiertage im Ergebnis fehlen. Gehen Sie nicht von einem Eintrag pro Kalendertag aus. Und wenn Sie Symbole mit unterschiedlichen Handelskalendern mischen, etwa Gold und Bitcoin, prüfen Sie, ob ein Schlüssel existiert, bevor Sie ihn lesen.
Wie lang der Zeitraum einer einzelnen Anfrage sein darf, hängt vom Tarif ab:
| Tarif | Längster Zeitraum pro Anfrage | Abschnitt, der immer passt |
|---|---|---|
| Free | 30 Tage | Ein Kalendermonat |
| Lite und höher | 365 Tage | Ein Kalenderjahr |
Das Limit bezieht sich auf den Abstand zwischen den beiden Daten. 2025-01-01 bis 2025-01-31 passt also in das Limit des Free-Tarifs und 2024-01-01 bis 2024-12-31 in das der kostenpflichtigen Tarife, selbst in einem Schaltjahr. Ein längerer Zeitraum liefert Fehler 207 (timeframe_too_long) mit einer upgrade_url. Jeder Aufruf von /timeframe zählt als eine Anfrage, egal wie viele Tage er zurückgibt.
Zwei Daten vergleichen: /change
Wenn Sie nur die Veränderung zwischen zwei Tagen brauchen, etwa die Wertentwicklung seit Jahresbeginn auf einem Dashboard, liefert /change Anfangskurs, Endkurs sowie absolute und prozentuale Veränderung, ohne dass Sie die Tage dazwischen herunterladen müssen:
curl "https://metalapi.com/api/v1/change?start_date=2026-01-02&end_date=2026-10-23¤cies=XAU,XAG" \
-H "X-API-Key: $METALAPI_KEY"{
"success": true,
"change": true,
"start_date": "2026-01-02",
"end_date": "2026-10-23",
"base": "USD",
"rates": {
"XAU": { "start_rate": 0.0002309682, "end_rate": 0.0002495072, "change": 0.000018539, "change_pct": 8.02665 },
"USDXAU": { "start_rate": 4329.6, "end_rate": 4007.9, "change": -321.7, "change_pct": -7.43025 }
}
}Lesen Sie den Schlüssel mit Präfix, USDXAU. Der Kehrwert-Schlüssel XAU bewegt sich in die entgegengesetzte Richtung, sein change_pct hat daher das umgekehrte Vorzeichen und einen anderen Betrag: In diesem Beispiel ist der Goldpreis um 7,43 % gefallen, während der Kehrwert um 8,03 % gestiegen ist. Den Prozentwert des Kehrwerts als Preisänderung anzuzeigen, ist ein Fehler, der leicht unbemerkt in die Produktion gelangt.
/change hat dieselben Zeitraumlimits wie /timeframe. Wie /historical verwendet der Endpunkt den letzten Schlusskurs, wenn ein Datum auf ein Wochenende oder einen Feiertag fällt.
Tageskerzen: /ohlc
/ohlc liefert Eröffnungs-, Höchst-, Tiefst- und Schlusskurs eines Tages in beiden Richtungen: USDXAU in Dollar pro Unze und XAU als Kehrwert. Ohne date oder mit date=latest erhalten Sie den bisherigen Balken des heutigen Tages.
curl "https://metalapi.com/api/v1/ohlc?date=2026-10-23¤cies=XAU" \
-H "X-API-Key: $METALAPI_KEY"{
"success": true,
"ohlc": true,
"date": "2026-10-23",
"base": "USD",
"rates": {
"USDXAU": { "open": 4042.2, "high": 4050.2, "low": 3989.1, "close": 4007.9 },
"XAU": { "open": 0.000247390, "high": 0.000250683, "low": 0.000246901, "close": 0.000249507 }
}
}Beachten Sie, dass im Kehrwert-Block das Hoch aus dem niedrigsten und das Tief aus dem höchsten Preis stammt, weil die Kehrwertbildung die Reihenfolge umkehrt. Verwenden Sie für Charts den Block USDXAU.
Jeder Aufruf umfasst einen Tag, ein Candlestick-Chart über ein ganzes Jahr kostet also eine Anfrage pro Handelstag. Für lange Charts sind Schlusskurse aus /timeframe weitaus günstiger. Nutzen Sie /ohlc für die jüngsten Kerzen oder um die Tagesspanne neben dem aktuellen Preis anzuzeigen.
Für Wochen- oder Monatskerzen über viele Jahre können Sie Balken auch aus gespeicherten Tagesschlusskursen bilden: Die Eröffnung ist der erste Schlusskurs des Zeitraums, der Schluss der letzte, und Hoch und Tief sind die Extremwerte der Schlusskurse. Intraday-Hochs und -Tiefs fehlen darin, kennzeichnen Sie solche Kerzen also als schlusskursbasiert. Für langfristige Charts eignen sie sich aber gut.
25 Jahre nachladen, ein Jahr pro Anfrage
Mit einem Limit von 365 Tagen pro Anfrage braucht die vollständige Gold- und Silberhistorie seit 2000 einen /timeframe-Aufruf pro Kalenderjahr: 27 Anfragen für 2000 bis 2026. Das passt problemlos in das Monatskontingent jedes kostenpflichtigen Tarifs. Im Free-Tarif wären mit 30-Tage-Fenstern mehr als 300 Anfragen nötig, etwa das Dreifache des Monatskontingents von 100. Ein vollständiges Nachladen ist dort also nicht praktikabel, einige Monate Historie dagegen schon.
Dieses Python-Skript lädt die Daten jahresweise, wartet das Limit pro Minute ab und schreibt die Preisschlüssel beider Metalle in SQLite. Speichern Sie es als backfill.py:
import os
import sqlite3
import time
from datetime import datetime, timezone
import requests
API = "https://metalapi.com/api/v1"
session = requests.Session()
session.headers["X-API-Key"] = os.environ["METALAPI_KEY"]
db = sqlite3.connect("metals.db")
db.execute(
"""create table if not exists daily_close (
day text not null,
symbol text not null,
base text not null,
price real not null,
primary key (day, symbol, base)
)"""
)
def fetch_timeframe(start, end, symbols, base="USD"):
"""Daily closes between start and end (inclusive), keyed by date."""
while True:
r = session.get(
f"{API}/timeframe",
params={"start_date": start, "end_date": end, "currencies": ",".join(symbols), "base": base},
timeout=30,
)
data = r.json()
if data.get("success"):
return data["rates"]
err = data["error"]
if err["code"] == 104: # Limit pro Minute: warten, dann erneut versuchen (nicht berechnet)
time.sleep(int(r.headers.get("Retry-After", "60")))
continue
if err["code"] == 300: # keine Daten in diesem Zeitfenster
return {}
raise RuntimeError(f"{err['code']} {err['type']}: {err['info']}")
def store(rates, symbols, base="USD"):
rows = [
(day, s, base, values[f"{base}{s}"])
for day, values in rates.items()
for s in symbols
if f"{base}{s}" in values
]
db.executemany("insert or replace into daily_close values (?, ?, ?, ?)", rows)
db.commit()
return len(rows)
def backfill(first_year, symbols=("XAU", "XAG"), base="USD"):
today = datetime.now(timezone.utc).date()
for year in range(first_year, today.year + 1):
start = f"{year}-01-01"
end = min(f"{year}-12-31", today.isoformat())
n = store(fetch_timeframe(start, end, symbols, base), symbols, base)
print(f"{year}: {n} rows")
if __name__ == "__main__":
backfill(2000)Das Skript kann gefahrlos erneut ausgeführt werden: insert or replace überschreibt bereits vorhandene Zeilen, ein unterbrochenes Nachladen lässt sich also einfach neu starten. Das laufende Jahr endet am heutigen Datum (UTC), weil ein end_date in der Zukunft Fehler 205 liefert. Die Limits pro Minute sind in den kleinsten Tarifen am niedrigsten (10 Anfragen pro Minute im Free-Tarif und 30 im Lite-Tarif). Deshalb beachtet das Skript bei Fehler 104 den Header Retry-After, statt abzubrechen.
Es speichert USDXAU und USDXAG, also die Preise, nicht die Kehrwert-Schlüssel. Wenn Sie die Historie in einer anderen Währung brauchen, übergeben Sie base oder speichern Sie zusätzlich die Dollarkurse der Währungen und rechnen lokal mit den Zeilen desselben Tages um.
Daten speichern und aktualisieren
Schlusskurse vergangener Tage ändern sich nicht. Eine lokale Kopie ist daher der günstigste und schnellste Weg, Charts und Berichte zu bedienen. Einige Regeln halten sie korrekt:
- Zeilen nach Tag, Symbol und Basis schlüsseln. Die Tabelle oben verwendet
(day, symbol, base)als Primärschlüssel. Wird ein Zeitraum zweimal abgerufen, werden Zeilen daher überschrieben statt dupliziert. - Festhalten, was Sie angefragt haben. Speichern Sie
baseund gegebenenfallsunitzusammen mit den Daten. Werte pro Gramm und pro Unze in einer Spalte zu mischen, ist eine klassische Ursache für Ausreißer in einem Chart. - Einmal täglich ergänzen. Nach dem Nachladen hält eine Anfrage pro Tag die Tabelle aktuell. Rufen Sie die letzten sieben Tage ab, damit ein ausgefallener Lauf oder ein verspäteter Schlusskurs automatisch nachgetragen wird.
- Den heutigen Tag als vorläufig behandeln. Nur der Balken des laufenden Tages bewegt sich noch. Halten Sie ihn aus dem Archiv heraus oder überschreiben Sie ihn beim nächsten Lauf, wie es das Skript unten tut.
from datetime import datetime, timedelta, timezone
from backfill import fetch_timeframe, store
SYMBOLS = ("XAU", "XAG")
today = datetime.now(timezone.utc).date()
start = (today - timedelta(days=7)).isoformat()
end = (today - timedelta(days=1)).isoformat()
print(store(fetch_timeframe(start, end, SYMBOLS), SYMBOLS), "rows updated")Bei einer Anfrage pro Tag kostet die Ergänzung etwa 30 Anfragen im Monat; das lässt sogar im Free-Tarif noch Spielraum. Für größere Archive funktioniert dasselbe Muster mit PostgreSQL, einer Parquet-Datei oder jeder Zeitreihendatenbank; nur die Funktion store ändert sich.
Prüfen Sie nachgeladene Daten, bevor Sie darauf aufbauen. Drei Prüfungen decken die meisten Probleme auf:
- Zeilen pro Jahr. Jedes vollständige Jahr sollte für jedes Metall ungefähr eine Zeile pro Handelstag haben. Ein Jahr mit deutlich weniger Zeilen bedeutet, dass eine Anfrage fehlgeschlagen ist oder keine Daten geliefert hat.
- Lücken. Ein normales Wochenende lässt drei Tage zwischen zwei Schlusskursen, ein langes Feiertagswochenende vier. Alles darüber verdient einen Blick, und das erneute Abrufen dieses Zeitfensters kostet nur eine Anfrage.
- Sprünge. Eine Veränderung von einem Tag zum nächsten um etwa den Faktor 31 oder 1.000 deutet auf gemischte Einheiten hin, ein Wert nahe null auf einen versehentlich übernommenen Kehrwert-Schlüssel.
Die ersten beiden sind kurze Abfragen in SQLite:
-- Zeilen pro Jahr: Ein vollständiges Jahr hat etwa eine Zeile pro Handelstag
select substr(day, 1, 4) as year, symbol, count(*) as days from daily_close
where base = 'USD' group by year, symbol order by year, symbol;
-- Lücken von mehr als vier Tagen zwischen gespeicherten Schlusskursen
select symbol, prev_day, day from (
select symbol, day, lag(day) over (partition by symbol order by day) as prev_day
from daily_close where base = 'USD'
) where julianday(day) - julianday(prev_day) > 4;Daten als Chart darstellen
Wenn die Daten lokal gespeichert sind, kosten Charts keine Anfragen. Dieses matplotlib-Skript zeichnet den Goldpreis in Dollar zusammen mit dem Gold-Silber-Verhältnis, also der Anzahl Unzen Silber, die man für eine Unze Gold erhält:
import sqlite3
from datetime import date
import matplotlib.dates as mdates
import matplotlib.pyplot as plt
db = sqlite3.connect("metals.db")
rows = db.execute(
"""select g.day, g.price, s.price
from daily_close g
join daily_close s on s.day = g.day and s.base = g.base and s.symbol = 'XAG'
where g.symbol = 'XAU' and g.base = 'USD'
order by g.day"""
).fetchall()
days = [date.fromisoformat(day) for day, _, _ in rows]
gold = [g for _, g, _ in rows]
ratio = [g / s for _, g, s in rows]
fig, (top, bottom) = plt.subplots(2, 1, sharex=True, figsize=(10, 6))
top.plot(days, gold, linewidth=1)
top.set_ylabel("Gold, USD per troy oz")
bottom.plot(days, ratio, linewidth=1)
bottom.set_ylabel("Gold/silver ratio")
bottom.xaxis.set_major_locator(mdates.YearLocator(base=5))
fig.tight_layout()
fig.savefig("gold-silver.png", dpi=150)Auf einer Website liefern Sie die gespeicherte Zeitreihe aus Ihrem eigenen Backend aus und zeichnen sie im Browser. Ihr API-Schlüssel bleibt auf dem Server, und Seitenaufrufe verbrauchen kein Kontingent. Eine minimale Chart.js-Seite, die ein JSON-Array mit { day, price }-Objekten von Ihrem eigenen Endpunkt liest:
<canvas id="gold" height="320"></canvas>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/chart.umd.js"></script>
<script>
// Ihr eigener Endpunkt, liefert [{ "day": "2026-10-23", "price": 4007.9 }, ...]
fetch("/api/gold-history")
.then((res) => res.json())
.then((points) => {
new Chart(document.getElementById("gold"), {
type: "line",
data: {
labels: points.map((p) => p.day),
datasets: [{ label: "Gold, USD per troy oz", data: points.map((p) => p.price), pointRadius: 0, borderWidth: 1 }],
},
options: {
animation: false,
scales: { x: { ticks: { maxTicksLimit: 10 } } },
},
});
});
</script>25 Jahre Handelstage sind mehr als 6.000 Punkte pro Zeitreihe. Wenn Sie wie oben Punktmarkierungen und Animationen abschalten, bleibt der Chart flüssig; auf kleinen Bildschirmen können Sie die Daten auf Wochenschlusskurse ausdünnen.
Die Anleitung zu historischen Daten enthält eine JavaScript-Hilfsfunktion für Zeiträume und ein Beispiel für einen gleitenden Durchschnitt, und die API-Dokumentation listet alle Parameter auf. Wenn Sie mit KI-Assistenten arbeiten, kann der MCP-Server von MetalAPI dieselben Zeitreihen direkt im Chat abrufen. Für Schlüssel, Fehler und Caching im Allgemeinen beginnen Sie am besten mit dem Leitfaden zur Goldpreis-API. Zeitraumlimits und Kontingente vergleichen Sie auf der Preisseite.
Probieren Sie es mit Ihren eigenen Daten aus
Erstellen Sie ein kostenloses Konto und senden Sie Ihre erste Anfrage in unter zwei Minuten. 100 Anfragen pro Monat, keine Kreditkarte.
Weiterlesen
Goldpreis-API: Der vollständige Leitfaden für Entwickler
So nutzen Sie eine Goldpreis-API: Schlüssel holen, Aufrufe mit curl, JavaScript und Python, Kurse richtig lesen sowie Historie, Fehler, Kontingente und Caching.
So binden Sie ein Live-Goldpreis-Widget in Ihre Website ein
Live-Goldpreis-Widget für WordPress, Shopify oder HTML: im MetalAPI-Dashboard erstellen, Symbole, Layout und Design wählen und zwei Zeilen Code einfügen.
Goldpreise nach Karat erklärt: 24K, 22K, 18K und wie man sie berechnet
Was 24, 22 und 18 Karat bedeuten, wie Feingehalte wie 916 und 750 zusammenhängen, wie Sie Karatpreise pro Gramm berechnen und per Goldpreis-API abrufen.