Terug naar Blog

Valutavolatiliteit berekenen: een gids voor developers

V
Vlado Grigirov
September 07, 2026
Currency API Exchange Rates Volatility Historical Data Python Risk Management

Weten hoe je valutavolatiliteit berekent is het verschil tussen een multi-valuta applicatie die een beweging van 2% over nacht geruisloos opvangt en een die je om drie uur 's nachts uit bed belt. Volatiliteit is het ene getal dat je vertelt hoe ver een wisselkoers zich waarschijnlijk zal bewegen — en vrijwel elke praktische beslissing in een FX-bewust systeem hangt ervan af: hoe lang een quote geldig blijft, hoeveel buffer je op een prijs zet, wanneer je afdekt en wanneer je een alert afvuurt.

Het lastige is dat de meeste tutorials over het berekenen van volatiliteit voor aandelen zijn geschreven. Ze gaan uit van een dagelijkse slotkoers, een handelsjaar van 252 dagen en één ondubbelzinnige notering. De valutamarkt heeft geen van die dingen. Die draait 24 uur per dag, vijf dagen per week, op een gedecentraliseerde OTC-markt zonder officiële slotkoers — en de "prijs" van EUR/USD hangt af van welke kant je het paar op noteert.

Deze gids loopt door de daadwerkelijke wiskunde, de FX-specifieke valkuilen en werkende code in Python en JavaScript die de gerealiseerde volatiliteit uit historische wisselkoersdata berekent.

Waarom valutavolatiliteit juist nu telt

September 2026 is een ongewoon goed moment om over volatiliteit na te denken, want de markt heeft het grootste deel van het jaar in een verdacht rustig regime doorgebracht — en hield daar toen even mee op.

De hele zomer waren valuta's uit opkomende markten minder volatiel dan G7-valuta's, bijna 200 handelsdagen op rij. Bloomberg merkte op dat dat de langste reeks sinds 2000 zou zijn als hij aanhield. In dollars gefinancierde carry trades regen hun langste winstreeks sinds 2008 aaneen, en een populair in euro's gefinancierd mandje van Braziliaanse real, Colombiaanse peso en Turkse lira stond volgens berichten ongeveer 19% in de plus sinds jaarbegin — de sterkste tussenstand sinds 2005. Carry-strategieën werken alleen in rustige markten, dus hun rendement is zelf al een volatiliteitssignaal.

Begin september sprong de yen vervolgens in één sessie meer dan 2% ten opzichte van de dollar, tot 155,28, het sterkste niveau sinds begin augustus, omdat handelaren zich positioneerden voor verdere interventie door het Japanse ministerie van Financiën. Daaraan vooraf gingen een gezamenlijke Amerikaans-Japanse interventie op 31 juli en een record van ¥11,73 biljoen (ruwweg 73 miljard dollar) aan MOF-interventie in april en mei, nadat USD/JPY door de 160 was gebroken.

Dat contrast is de hele les. De gemiddelde volatiliteit was laag. De gerealiseerde volatiliteit op één specifieke dag was enorm. Een systeem dat zijn FX-buffers op een voortschrijdend jaargemiddelde baseerde, zat er juist op de dag die ertoe deed volledig naast. Volatiliteit goed meten — en continu — is precies wat dat voorkomt.

Wat valutavolatiliteit werkelijk meet

Volatiliteit is de standaarddeviatie van rendementen, uitgedrukt op jaarbasis. Het is geen voorspelling van richting, en het is niet de omvang van een beweging. Het is een maat voor spreiding: hoe wijd de dagelijkse rendementen van een valutapaar rond hun gemiddelde verspreid liggen.

Twee smaken doen ertoe:

  • Gerealiseerde (historische) volatiliteit — achterwaarts berekend uit werkelijk waargenomen koersen. Dit is wat je zelf uit een tijdreeks kunt berekenen, en waar deze gids over gaat.
  • Impliciete volatiliteit — afgeleid uit de prijzen van FX-opties. Dit is de vooruitkijkende inschatting van de markt. Je kunt haar niet uit spotkoersen afleiden; daarvoor heb je een optiedatafeed nodig.

Voor de meeste applicatieontwikkelaars — pricing, facturatie, treasury-dashboards, risicoalerts — is gerealiseerde volatiliteit zowel voldoende als gratis te berekenen als je de historische koersen al hebt.

Een ruwe intuïtie voor de getallen: grote paren zoals EUR/USD zaten in rustige periodes doorgaans ergens tussen 5 en 10% op jaarbasis, en tussen 10 en 15% in gespannen periodes. Paren uit opkomende markten zitten routineus twee tot drie keer hoger. Die bandbreedtes verschuiven in de tijd, en dat is precies waarom je moet meten in plaats van aannemen.

De formule: log-rendementen, standaarddeviatie, annualisering

De berekening bestaat uit drie stappen.

Stap 1 — Zet koersen om naar log-rendementen.

r_t = ln(P_t / P_t-1)

Stap 2 — Neem de standaarddeviatie van die rendementen over het venster dat je kiest (gebruik de steekproefstandaarddeviatie, dus delen door n − 1).

Stap 3 — Annualiseer door te vermenigvuldigen met de wortel van het aantal waarnemingen per jaar.

annualised_volatility = stdev(r) * sqrt(N)

Samengevoegd:

σ_annual = stdev( ln(P_t / P_t-1) ) × √N

Waarom log-rendementen in plaats van procentuele verandering

Een eenvoudige procentuele verandering is asymmetrisch: een beweging van 1,10 naar 1,20 is +9,09%, maar de terugweg van 1,20 naar 1,10 is −8,33%. Die zouden gelijk en tegengesteld moeten zijn. Bij log-rendementen zijn ze dat wel — ln(1.20/1.10) en ln(1.10/1.20) verschillen alleen in teken.

Dit weegt in FX veel zwaarder dan bij aandelen, en wel vanwege omkering van de notering. EUR/USD en USD/EUR beschrijven dezelfde markt. Bereken je volatiliteit met procentuele veranderingen, dan krijg je twee licht verschillende antwoorden afhankelijk van welke kant je het paar hebt genoteerd, wat overduidelijk fout is. Log-rendementen zijn omkeringssymmetrisch: ln(1/x) = −ln(x), en de standaarddeviatie negeert het teken. Zelfde paar, zelfde volatiliteit, in beide richtingen.

Log-rendementen zijn bovendien optelbaar over de tijd, wat aggregatie over meerdere dagen triviaal maakt.

Waarom √N — en wat N moet zijn voor FX

Volatiliteit schaalt met de wortel van de tijd omdat variantie lineair met de tijd schaalt (onder de gebruikelijke random-walk-aanname). Om dagelijkse volatiliteit naar jaarbasis om te rekenen, vermenigvuldig je met √(days per year).

Aandelentutorials gebruiken 252, het geschatte aantal handelsdagen op Amerikaanse beurzen. FX werkt anders. De markt loopt onafgebroken van zondagavond tot vrijdagavond — ruwweg 260 doordeweekse sessies per jaar, min een handjevol dunne feestdagen. De meeste FX-dataleveranciers publiceren op elke werkdag koersen, ook op dagen dat de eigen markt van een bepaald land dicht is.

De praktische regel: N moet passen bij de bemonsteringsfrequentie van je data, niet bij een conventie die uit een andere beleggingscategorie is geleend.

DatafrequentieN (annualiseringsfactor)
Dagelijks (werkdagen, FX-conventie)260
Dagelijks (252-dagen aandelenconventie)252
Wekelijks52
Maandelijks12
Per uur (24×5)~6.240
Het verschil tussen 252 en 260 verandert je uitkomst met zo'n 1,6% relatief — verwaarloosbaar voor een dashboard, wel van belang als je je getal met dat van een leverancier vergelijkt. Wat je ook kiest: documenteer het en houd het constant.

Stap 1: haal schone historische wisselkoersdata op

Volatiliteit is niet beter dan de reeks eronder. Haal een dagreeks op met één aanroep van het /v1/timeseries-endpoint:

curl -G "https://api.finexly.com/v1/timeseries" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d base=EUR \
  -d symbols=USD,JPY,GBP \
  -d start_date=2026-06-08 \
  -d end_date=2026-09-05

De respons is een map met datums als sleutel:

{
  "success": true,
  "base": "EUR",
  "start_date": "2026-06-08",
  "end_date": "2026-09-05",
  "rates": {
    "2026-06-08": { "USD": 1.1421, "JPY": 178.62, "GBP": 0.8447 },
    "2026-06-09": { "USD": 1.1408, "JPY": 178.94, "GBP": 0.8451 }
  }
}

Eén request, één reeks, geen paginatielus. De volledige parameterreferentie staat in de Finexly API-documentatie, en de bredere patronen voor het werken met datumbereiken behandelen we in onze gids voor de API voor historische wisselkoersen.

Vier dataproblemen die alleen bij FX spelen

Voordat je de uitkomst vertrouwt, pak je deze aan. Geen van deze komt voor in een tutorial over aandelenvolatiliteit, en alle vier vertekenen je getal.

1. Er is geen officiële slotkoers. FX is gedecentraliseerd; niemand luidt een bel. Verschillende leveranciers nemen op verschillende momenten een momentopname — 22:00 UTC, middernacht UTC, de ECB-referentiefixing van 14:15 CET, of de 4pm London WM/Reuters-fixing. Momentopnametijden binnen één reeks door elkaar gebruiken voegt kunstmatige variantie toe. Kies één conventie en meng nooit. Weet je niet zeker wat jouw leverancier doet, dan is onze uitleg over waar wisselkoers-API's hun data vandaan halen een goed startpunt.

2. Weekenden en gaten. De markt sluit vrijdagavond en opent zondagavond weer. Een rendement van vrijdag op maandag beslaat ongeveer 65 kalenderuren, maar telt in een naïeve berekening als één "dag". De meeste practitioners accepteren dat en annualiseren op werkdagen — de standaardaanpak — maar je moet consistent blijven. Vul weekendkoersen niet met forward fill aan in de reeks; een rij identieke waarden trekt je standaarddeviatie kunstmatig omlaag.

3. Asymmetrie van de basisvaluta. Zoals hierboven beschreven lossen log-rendementen het omkeringsprobleem wiskundig op. Je moet nog steeds beslissen in welke basis je risico meet. De volatiliteit van je USD-exposure gemeten in EUR is een andere zakelijke vraag dan hetzelfde paar gemeten in USD, ook al komt er hetzelfde getal uit. Wees expliciet over de numéraire.

4. Getrianguleerde cross rates. Leidt je leverancier bijvoorbeeld SEK/NOK af door SEK/USD door NOK/USD te delen, dan erft het resultaat ruis van beide poten en van elke timingmismatch daartussen. Synthetische crosses kunnen een merkbaar hogere volatiliteit laten zien dan de direct genoteerde markt. Onze gids over cross rates legt uit wanneer triangulatie veilig is en wanneer niet.

Let ook op je precisie. JPY-paren op twee decimalen afkappen voordat je rendementen berekent, kwantiseert kleine bewegingen naar nul en drukt de volatiliteit omlaag — zie afronding van valuta en decimalen voor de algemene regel. Sla volledige precisie op en rond pas af bij weergave.

Stap 2: bereken gerealiseerde volatiliteit in Python

Hier is een volledige implementatie met weinig afhankelijkheden. Ze gebruikt requests en de standaardbibliotheek — pandas is niet nodig.

import math
import statistics
import requests

FX_DAYS_PER_YEAR = 260  # weekday sessions; use 252 for the equity convention


def fetch_series(base, symbol, start, end, api_key):
    url = "https://api.finexly.com/v1/timeseries"
    params = {
        "base": base,
        "symbols": symbol,
        "start_date": start,
        "end_date": end,
    }
    headers = {"Authorization": "Bearer " + api_key}
    response = requests.get(url, params=params, headers=headers, timeout=10)
    response.raise_for_status()
    return response.json()["rates"]


def log_returns(rates, symbol):
    """Ordered log returns from a date-keyed rates map."""
    dates = sorted(rates.keys())
    series = [rates[d][symbol] for d in dates]
    return [
        math.log(series[i] / series[i - 1])
        for i in range(1, len(series))
        if series[i] > 0 and series[i - 1] > 0
    ]


def annualised_volatility(returns, periods_per_year=FX_DAYS_PER_YEAR):
    if len(returns) < 2:
        raise ValueError("need at least two returns")
    return statistics.stdev(returns) * math.sqrt(periods_per_year)


rates = fetch_series("EUR", "USD", "2026-06-08", "2026-09-05", "YOUR_API_KEY")
returns = log_returns(rates, "USD")

vol = annualised_volatility(returns)
print("Observations:      {}".format(len(returns)))
print("Daily volatility:  {:.4%}".format(vol / math.sqrt(FX_DAYS_PER_YEAR)))
print("Annual volatility: {:.2%}".format(vol))

statistics.stdev is de steekproefstandaarddeviatie (noemer n − 1), en dat is wat je wilt. Stap je over op NumPy, onthoud dan dat numpy.std standaard de populatievariant gebruikt — geef ddof=1 mee om dezelfde uitkomst te krijgen.

Twee waarborgen die in productiecode thuishoren: sla niet-positieve koersen over voordat je een logaritme neemt, en weiger een getal terug te geven uit een venster met te weinig waarnemingen. Een 30-daagse volatiliteit berekend uit negen datapunten is geen 30-daagse volatiliteit.

Stap 3: dezelfde berekening in JavaScript

Ook hier is geen numerieke bibliotheek nodig.

const FX_DAYS_PER_YEAR = 260;

async function fetchSeries(base, symbol, start, end, apiKey) {
  const url = new URL('https://api.finexly.com/v1/timeseries');
  url.searchParams.set('base', base);
  url.searchParams.set('symbols', symbol);
  url.searchParams.set('start_date', start);
  url.searchParams.set('end_date', end);

  const res = await fetch(url, {
    headers: { Authorization: `Bearer ${apiKey}` },
  });
  if (!res.ok) throw new Error(`Finexly returned ${res.status}`);
  const body = await res.json();
  return body.rates;
}

function logReturns(rates, symbol) {
  const dates = Object.keys(rates).sort();
  const series = dates.map((d) => rates[d][symbol]);
  const out = [];
  for (let i = 1; i < series.length; i += 1) {
    if (series[i] > 0 && series[i - 1] > 0) {
      out.push(Math.log(series[i] / series[i - 1]));
    }
  }
  return out;
}

function annualisedVolatility(returns, periodsPerYear = FX_DAYS_PER_YEAR) {
  if (returns.length < 2) throw new Error('need at least two returns');
  const mean = returns.reduce((a, b) => a + b, 0) / returns.length;
  const variance =
    returns.reduce((acc, r) => acc + (r - mean) ** 2, 0) / (returns.length - 1);
  return Math.sqrt(variance) * Math.sqrt(periodsPerYear);
}

const rates = await fetchSeries('EUR', 'USD', '2026-06-08', '2026-09-05', 'YOUR_API_KEY');
const vol = annualisedVolatility(logReturns(rates, 'USD'));
console.log(`Annualised volatility: ${(vol * 100).toFixed(2)}%`);

Let op de noemer (returns.length - 1) — dezelfde steekproefvariantiecorrectie als in de Python-versie.

Rollende volatiliteit en het herkennen van een regimewisseling

Eén getal over een vast venster vertelt je bijna niets over wanneer het onrustig werd. Rollende volatiliteit wel, en dat is de versie die je op een dashboard echt wilt hebben.

def rolling_volatility(rates, symbol, window=30,
                       periods_per_year=FX_DAYS_PER_YEAR):
    dates = sorted(rates.keys())
    series = [rates[d][symbol] for d in dates]
    returns = [math.log(series[i] / series[i - 1]) for i in range(1, len(series))]
    return_dates = dates[1:]

    out = []
    for i in range(window - 1, len(returns)):
        chunk = returns[i - window + 1:i + 1]
        out.append((
            return_dates[i],
            statistics.stdev(chunk) * math.sqrt(periods_per_year),
        ))
    return out


for date, vol in rolling_volatility(rates, "USD", window=30)[-5:]:
    print("{}  {:.2%}".format(date, vol))

De keuze van het venster is een afweging, geen feit:

  • 10 dagen — zeer responsief, zeer ruizig. Goed voor alerting, slecht voor pricing.
  • 30 dagen — de gangbare standaard. Reageert binnen een paar sessies zonder alle kanten op te schieten.
  • 90 dagen — glad en stabiel. Goed voor het bepalen van hedgeratio's en prijsbuffers.

Een praktisch signaal voor een regimewisseling is de volatiliteitsratio: deel de 10-daagse volatiliteit door de 90-daagse. Aanhoudende waarden boven ongeveer 1,5 betekenen dat de kortetermijnspreiding de langere basislijn duidelijk voorbij is gestreefd. Toegepast op yen-paren rond de eerder beschreven interventie-episodes schiet die ratio hard omhoog terwijl het 90-daagse getal nauwelijks beweegt — en dat is precies het punt. Lange vensters verbergen gebeurtenissen; korte vensters vinden ze.

Wil je dit continu over veel paren draaien, lees dan eerst onze notities over caching en foutafhandeling voor valuta-API's. Historische dagkoersen zijn na publicatie onveranderlijk, dus die kun je onbeperkt cachen — herbereken alleen het nieuwste venster in plaats van bij elke paginaweergave een jaar historie opnieuw op te halen. De pagina prijsplannen laat zien hoe de requestvolumes over de tiers verdeeld zijn.

Van een volatiliteitsgetal naar een beslissing

Volatiliteit berekenen is makkelijk. De waarde zit in het gebruik ervan. Vier concrete toepassingen:

  1. Geldigheidsvensters voor quotes. Een prijs die je een klant laat zien, is een korte optie die je hem hebt geschreven. De verwachte drift over een houdperiode van t dagen is ruwweg σ_annual × √(t / 260). Bij 8% volatiliteit op jaarbasis draagt een quote van 24 uur ongeveer 0,5% verwachte drift; bij 20% eerder 1,2%. Verkort de TTL wanneer de volatiliteit stijgt, in plaats van voor altijd een vaste 15 minuten aan te houden.
  1. Prijsbuffers. In plaats van een FX-marge van 2% hard te coderen, schaal je hem: buffer = k × σ_annual × √(settlement_days / 260). De buffer verruimt automatisch in gespannen regimes en versmalt wanneer markten kalmeren, waardoor je concurrerend blijft zonder verborgen risico te lopen.
  1. Hedgetriggers. Exposure alleen is geen risico; exposure maal volatiliteit wel. Een exposure van 2 miljoen dollar op een paar met 4% volatiliteit is een kleiner probleem dan 400.000 dollar op een paar met 30%. Rangschik hedgebeslissingen op exposure × σ, niet op nominale waarde. Onze gids over valuta-hedging behandelt de instrumenten; het volatiliteitsgetal vertelt je wat er een verdient.
  1. Anomaliedetectie. Zet elke nieuwe dagbeweging om in een z-score ten opzichte van de standaarddeviatie over de afgelopen 30 dagen en alarmeer voorbij ±3. Dit vangt zowel echte marktgebeurtenissen als slechte data — een vastgelopen feed of een verkeerd getrianguleerde cross meldt zich meestal als een onwaarschijnlijke uitschieter voordat iemand het in een rapport opmerkt.

Wil je deze bewegingen in handelaarstermen uitdrukken in plaats van in procenten, lees dan wat een pip is.

Veelgemaakte fouten

  • Procentuele verandering gebruiken in plaats van log-rendementen. Introduceert asymmetrie en maakt je antwoord afhankelijk van de noteringsrichting.
  • De populatiestandaarddeviatie gebruiken. numpy.std() zonder ddof=1 onderschat de volatiliteit, en flink op korte vensters.
  • Weekenden en feestdagen met forward fill opvullen. Herhaalde waarden zijn dagen met nulrendement die de volatiliteit mechanisch omlaagtrekken.
  • Annualiseren met de verkeerde N. Weekdata geannualiseerd met 260 in plaats van 52 levert een getal op dat ongeveer 2,2× te groot is.
  • Volatiliteiten vergelijken die op verschillende momentopnametijden zijn berekend. Twee leveranciers, twee fixingtijden, twee onvergelijkbare getallen.
  • Eén jaarcijfer rapporteren en dat risico noemen. Volatiliteit clustert. Rustige maanden en heftige weken middelen uit tot een middelmatig getal dat geen van beide beschrijft. Publiceer altijd een rollende reeks naast de hoofdwaarde.
  • Aannemen dat lage volatiliteit lage risico's betekent. De rustige, carry-vriendelijke regimes van 2026 waren rustig tot precies het moment waarop interventiekoppen de yen 2% in één sessie bewogen. Lage gerealiseerde volatiliteit beschrijft het recente verleden, het is geen belofte over volgende week.

Veelgestelde vragen

Wat is een normaal volatiliteitsniveau voor een valutapaar?

Grote paren zoals EUR/USD en GBP/USD zaten historisch rond 5-10% op jaarbasis onder rustige omstandigheden en 10-15% onder spanning. Paren uit opkomende markten liggen doorgaans twee tot drie keer hoger. Vertrouw niet op vuistregels, maar bereken een rollende 90-daagse volatiliteit voor de paren die jij belangrijk vindt en gebruik je eigen basislijn — de niveaus verschuiven met het regime.

Moet ik 252 of 260 handelsdagen gebruiken om FX-volatiliteit te annualiseren?

260 past beter, omdat de FX-markt elke werkdag handelt in plaats van de kalender van één beurs te volgen. 252 is de aandelenconventie en wordt toch veel gebruikt. Het verschil is relatief zo'n 1,6%, dus het belangrijkste is dat je er één kiest, die documenteert en consistent toepast overal waar je getallen vergelijkt.

Kan ik impliciete volatiliteit berekenen uit een wisselkoers-API?

Nee. Impliciete volatiliteit wordt afgeleid uit de prijzen van FX-opties en vereist een optiedatafeed. Wat je uit een spot- of historische koersreeks wel kunt berekenen, is gerealiseerde volatiliteit. Voor pricing, hedgedrempels en alerting in applicatiecode is gerealiseerde volatiliteit meestal de juiste maatstaf.

Hoeveel historische data heb ik nodig?

Minimaal één waarneming meer dan je vensterlengte — maar dat geeft een instabiele schatting. Als praktische ondergrens: gebruik 30 waarnemingen voor een venster van 30 dagen en haal minstens een jaar historie op, zodat je de huidige waarde tegen een langere basislijn kunt afzetten. Het /v1/timeseries-endpoint geeft een willekeurig datumbereik terug in één request.

Waarom wijkt mijn volatiliteitsgetal af van dat van mijn dataleverancier?

Bijna altijd door een van vier oorzaken: een andere annualiseringsfactor (252 versus 260), populatie- in plaats van steekproefstandaarddeviatie, een ander momentopnametijdstip voor de dagkoers, of enkelvoudige in plaats van log-rendementen. Controleer die vier voordat je aanneemt dat de data fout is.

Voorspelt volatiliteit welke kant een valuta op beweegt?

Nee. Volatiliteit meet spreiding, geen richting. Van een paar met 20% volatiliteit op jaarbasis verwacht je dat het veel beweegt; de berekening zegt niets over de vraag of het omhoog of omlaag gaat. Gebruik haar om risico te dimensioneren, niet om een standpunt in te nemen.


Klaar om volatiliteit op live data te berekenen? Haal je gratis Finexly API-key op — geen creditcard nodig. Je krijgt toegang tot realtime en historische koersen voor meer dan 170 valuta's, met 1.000 gratis requests per maand en een /v1/timeseries-endpoint dat een volledig datumbereik in één aanroep teruggeeft. Begin met de gratis wisselkoers-API en upgrade naarmate je databehoefte groeit.

Vlado Grigirov

Senior Currency Markets Analyst & Financial Strategist

Vlado Grigirov is a senior currency markets analyst and financial strategist with over 14 years of experience in foreign exchange markets, cross-border finance, and currency risk management. He has wo...

View full profile →