Jak obliczyć VaR: trzy metody wyznaczania ryzyka
Analiza metod historycznej, parametrycznej oraz Monte Carlo dla stóp zwrotu SPY. Omówienie różnic w wynikach oraz wyjaśnienie koncepcji expected shortfall pomijanej przez VaR.
Wartość zagrożona (VaR)
2010 Wartość zagrożona, czyli VaR, jest wyliczana poprzez ustalenie horyzontu czasowego, określenie poziomu ufności, a następnie odczytanie percentyla z szeregu stóp zwrotu. Jednodniowy VaR na poziomie dziewięćdziesięciu dziewięciu procent wynoszący dwa procent oznaczałby, że strata pozostaje poniżej dwóch procent w dziewięćdziesięciu dziewięciu na każde sto sesji i przekracza tę wartość w setnej sesji. Trzy standardowe metody pozwalają odpowiedzieć na to pytanie przy użyciu identycznych danych wejściowych, a różnice między ich wynikami są większe, niż większość osób zakłada.
Czym w rzeczywistości jest wartość narażona na ryzyko (VaR)
VaR to kwantyl rozkładu strat. Należy uszeregować wszystkie dzienne stopy zwrotu w próbie od najgorszej do najlepszej, odliczyć jeden procent od strony wyników ujemnych, a stopa zwrotu, na której się zatrzymamy – zapisana jako dodatnia strata – stanowi jednodniowy, dziewięćdziesięciodziewięcioprocentowy historyczny VaR. Taka konstrukcja w żaden sposób nie gwarantuje określenia najgorszego możliwego scenariusza. Wyznacza ona jedynie granicę obszaru, którego szacunek nie obejmuje.
Jest to właściwość, o której czytelnicy zapominają najczęściej. Dziewięćdziesięciodziewięcioprocentowy VaR informuje, że najgorszy jeden procent dni znajduje się poza tym progiem, nie podaje jednak, jak głęboko w tym obszarze leżą straty. Maksymalne obsunięcie kapitału odpowiada na inne pytanie: dotyczy straty od szczytu do dołka, której portfel faktycznie doświadczył. Te dwie miary mogą uszeregować tę samą parę portfeli w odwrotnej kolejności.
Każda z poniższych liczb opiera się na jednej serii danych: dziennych cenach zamknięcia SPY od początku 2010 roku do końca 2025 roku, przeliczonych na procentowe zmiany między sesjami. Okno czasowe jest stałe, a nie kroczące, a każdy panel odtwarza serię z tych samych dat, dzięki czemu wartości nie zmieniają się między uruchomieniami.
Dokładny kod SQL dla każdej liczby
WITH
px AS
(
SELECT date, max(toFloat64(close)) AS close_px
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'SPY'
AND date >= '2009-12-01'
AND date < '2026-01-01'
GROUP BY date
),
rets AS
(
SELECT date, 100 * (close_px / prev_close - 1) AS ret_pct
FROM
(
SELECT date, close_px,
lagInFrame(close_px, 1) OVER (ORDER BY date ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS prev_close
FROM px
)
WHERE date >= '2010-01-01' AND prev_close > 0
)
SELECT
toString(toYear(date)) AS year,
count() AS sessions,
round(avg(ret_pct), 3) AS mean_return_pct,
round(stddevSamp(ret_pct), 2) AS daily_sigma_pct
FROM rets
GROUP BY year
ORDER BY yearSeria obejmuje 16 lat kalendarzowych, w tym 252 sesji w samym 2010. Dla wszystkiego, co następuje dalej, kluczowe znaczenie mają dwie cechy tej serii. Średnia sesyjna jest niemal nieistotna w tym horyzoncie: wynosi 0.054% w 2010 przy dziennym odchyleniu standardowym, sigma, na poziomie 1.13%. Sigma nie jest wartością stałą. W 2020 wynosiła ona 2.11% dziennie, a w 2017 – 0.43%. Jedna wartość sigma nie jest w stanie opisać obu tych okresów.
Trzy metody obliczania wartości zagrożonej (VaR)
Historyczna metoda VaR: odczyt percentyla z danych historycznych
Szeregi stóp zwrotu sortuje się, a następnie wyznacza odpowiedni percentyl. Metoda ta nie zakłada żadnego rozkładu prawdopodobieństwa, co stanowi o jej atrakcyjności. Zakłada natomiast, że w próbie historycznej wystąpiły już zdarzenia o skali, którą ma objąć szacunek. Przy wysokim poziomie ufności wynik zależy wyłącznie od kilku najgorszych sesji w całym badanym oknie czasowym.
Parametryczna metoda VaR: średnia minus iloczyn z oraz sigma
Szereg danych podsumowuje się za pomocą średniej oraz odchylenia standardowego (sigma), zakładając rozkład normalny stóp zwrotu. VaR oblicza się jako iloczyn wartości z oraz sigmy pomniejszony o średnią, gdzie z to kwantyl rozkładu normalnego: 1,645 dla poziomu 95%, 2,326 dla 99% oraz 3,090 dla 99,9%. Obliczenia są natychmiastowe, lecz założenie o rozkładzie normalnym zawodzi w określony sposób. Dzienne stopy zwrotu z akcji wykazują większe zagęszczenie wokół średniej niż krzywa rozkładu normalnego, a jednocześnie posiadają znacznie „grubsze” ogony. Sigma jest tu mianownikiem, który występuje również w wskaźniku Sharpe’a, przenosząc ten sam błąd poznawczy w przypadku danych o grubych ogonach.
Metoda Monte Carlo VaR: symulacja z ustalonym ziarnem losowości
Z założonego procesu generuje się dużą syntetyczną próbę, z której odczytuje się percentyl. Poniższy panel wykorzystuje czterdzieści tysięcy standardowych losowań z rozkładu normalnego, utworzonych za pomocą transformacji Boxa-Mullera z sekwencji liczb pseudolosowych o ustalonym ziarnie, przeskalowanych do średniej i sigmy szeregu. Ziarno jest zapisane w kodzie SQL, dzięki czemu losowania są identyczne przy każdym uruchomieniu. Symulacja zapewnia elastyczność, możliwość uwzględnienia zależności od ścieżki oraz korelacji między aktywami, jednak nie gwarantuje realizmu: przy założeniu rozkładu normalnego wynik będzie zbliżony do metody parametrycznej, wzbogacony jedynie o szum próbkowania. Zastosowanie próbkowania z powtórzeniami (resampling) na zaobserwowanych stopach zwrotu, czyli techniki leżącej u podstaw bootstrapowych przedziałów ufności, pozwala zachować rzeczywisty kształt ogonów rozkładu.
Dokładny kod SQL dla każdej liczby
WITH
px AS
(
SELECT date, max(toFloat64(close)) AS close_px
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'SPY'
AND date >= '2009-12-01'
AND date < '2026-01-01'
GROUP BY date
),
rets AS
(
SELECT date, 100 * (close_px / prev_close - 1) AS ret_pct
FROM
(
SELECT date, close_px,
lagInFrame(close_px, 1) OVER (ORDER BY date ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS prev_close
FROM px
)
WHERE date >= '2010-01-01' AND prev_close > 0
),
emp AS
(
SELECT
avg(ret_pct) AS mu,
stddevSamp(ret_pct) AS sd,
quantileExact(0.100)(ret_pct) AS h90,
quantileExact(0.050)(ret_pct) AS h95,
quantileExact(0.025)(ret_pct) AS h975,
quantileExact(0.010)(ret_pct) AS h99,
quantileExact(0.005)(ret_pct) AS h995,
quantileExact(0.001)(ret_pct) AS h999
FROM rets
),
draws AS
(
SELECT
quantileExact(0.100)(z) AS z90,
quantileExact(0.050)(z) AS z95,
quantileExact(0.025)(z) AS z975,
quantileExact(0.010)(z) AS z99,
quantileExact(0.005)(z) AS z995,
quantileExact(0.001)(z) AS z999
FROM
(
SELECT sqrt(-2 * log(u1)) * cos(2 * pi() * u2) AS z
FROM
(
SELECT
(cityHash64('var-seed-u1', i) % 999999937 + 1) / 999999938.0 AS u1,
(cityHash64('var-seed-u2', i) % 999999937 + 1) / 999999938.0 AS u2
FROM (SELECT arrayJoin(range(40000)) AS i)
)
)
)
SELECT
tupleElement(lvl, 1) AS confidence,
round(-1 * tupleElement(lvl, 2), 2) AS historical_var_pct,
round(tupleElement(lvl, 3) * sd - mu, 2) AS parametric_var_pct,
round(-1 * (mu + sd * tupleElement(lvl, 4)), 2) AS monte_carlo_var_pct,
round(-1 * tupleElement(lvl, 2) - (tupleElement(lvl, 3) * sd - mu), 2) AS method_spread
FROM
(
SELECT
mu,
sd,
arrayJoin([
('90.0%', h90, 1.281552, z90, 1),
('95.0%', h95, 1.644854, z95, 2),
('97.5%', h975, 1.959964, z975, 3),
('99.0%', h99, 2.326348, z99, 4),
('99.5%', h995, 2.575829, z995, 5),
('99.9%', h999, 3.090232, z999, 6)
]) AS lvl
FROM emp
CROSS JOIN draws
)
ORDER BY tupleElement(lvl, 5)Na poziomie 95.0% wyniki wszystkich trzech metod różnią się o mniej niż jeden punkt procentowy: 1.66% historyczna, 1.74% parametryczna, 1.71% symulowana. Na poziomie 99.9% drogi metod się rozchodzą: 5.85% historyczna kontra 3.31% parametryczna, co daje różnicę 2.54 punktu procentowego przy identycznych danych wejściowych. Kolumna symulowana znajduje się obok parametrycznej na każdym poziomie ufności, co stanowi raczej lekcję niż wadę metody. Symulacja jedynie odtwarza rozkład, który został jej narzucony.
Analiza panelu w pionie pokazuje, że każdy wzrost poziomu ufności zwiększa próg ryzyka. Analiza w poziomie wskazuje, że wybór metody ma znikome znaczenie w środkowej części rozkładu, natomiast dominuje w jego ogonach. Limit VaR podany bez wskazania metody obliczeń oraz okna czasowego jest wartością, której nie da się zweryfikować.
Czego nie mówi VaR: oczekiwany niedobór (expected shortfall)
Oczekiwany niedobór, nazywany również warunkowym VaR, stanowi średnią strat z dni, w których przekroczono wartość VaR. VaR wyznacza punkt, w którym zaczyna się ogon rozkładu. Oczekiwany niedobór mierzy to, co znajduje się wewnątrz tego obszaru.
Dokładny kod SQL dla każdej liczby
WITH
px AS
(
SELECT date, max(toFloat64(close)) AS close_px
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'SPY'
AND date >= '2009-12-01'
AND date < '2026-01-01'
GROUP BY date
),
rets AS
(
SELECT date, 100 * (close_px / prev_close - 1) AS ret_pct
FROM
(
SELECT date, close_px,
lagInFrame(close_px, 1) OVER (ORDER BY date ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS prev_close
FROM px
)
WHERE date >= '2010-01-01' AND prev_close > 0
),
qs AS
(
SELECT
quantileExact(0.100)(ret_pct) AS q90,
quantileExact(0.050)(ret_pct) AS q95,
quantileExact(0.025)(ret_pct) AS q975,
quantileExact(0.010)(ret_pct) AS q99,
quantileExact(0.005)(ret_pct) AS q995,
quantileExact(0.001)(ret_pct) AS q999
FROM rets
),
tails AS
(
SELECT
any(q90) AS var90,
any(q95) AS var95,
any(q975) AS var975,
any(q99) AS var99,
any(q995) AS var995,
any(q999) AS var999,
avgIf(ret_pct, ret_pct <= q90) AS es90,
avgIf(ret_pct, ret_pct <= q95) AS es95,
avgIf(ret_pct, ret_pct <= q975) AS es975,
avgIf(ret_pct, ret_pct <= q99) AS es99,
avgIf(ret_pct, ret_pct <= q995) AS es995,
avgIf(ret_pct, ret_pct <= q999) AS es999
FROM rets
CROSS JOIN qs
HAVING countIf(ret_pct <= q999) > 0
)
SELECT
tupleElement(lvl, 1) AS confidence,
round(-1 * tupleElement(lvl, 2), 2) AS historical_var_pct,
round(-1 * tupleElement(lvl, 3), 2) AS expected_shortfall_pct,
round(tupleElement(lvl, 3) / tupleElement(lvl, 2), 2) AS es_to_var_ratio
FROM
(
SELECT
arrayJoin([
('90.0%', var90, es90, 1),
('95.0%', var95, es95, 2),
('97.5%', var975, es975, 3),
('99.0%', var99, es99, 4),
('99.5%', var995, es995, 5),
('99.9%', var999, es999, 6)
]) AS lvl
FROM tails
)
ORDER BY tupleElement(lvl, 4)Przy 99.0%, VaR dla tej serii wynosi 3.09%, a oczekiwany niedobór wynosi 4.43%, czyli 1.44 wartości progu. W warunkach rozkładu normalnego wskaźnik ten przy tym samym poziomie wynosiłby około 1,15. Nawet przy 99.9%, gdzie próg osiągnął już 5.85%, średnia strata w dniu przekroczenia wynosi 8.14%. Limit oparty wyłącznie na VaR traktuje każde przekroczenie jako identyczne zdarzenie, a kolumna wskaźnika pokazuje, jak bardzo jest to nieprawdziwe.
Czy jednodniowy 99% VaR oznacza to samo dla instytucji i tradera?
Nie, a rozbieżność wynika głównie z horyzontu czasowego. Trader, który zamyka pozycje przed końcem sesji, ponosi ryzyko przez kilka godzin, więc próg jednodniowy pokrywa się z jego horyzontem inwestycyjnym, choć ścieżka wewnątrzsesyjna może znacznie wykraczać poza wynik obliczony na podstawie cen zamknięcia. Instytucja finansująca długoterminowe zobowiązania utrzymuje pozycje przez lata, jej ekspozycja trwa kwartałami, a jednodniowy wskaźnik 99% VaR pełni funkcję narzędzia kapitałowego i monitorującego, a nie opisuje faktycznego ryzyka portfela. Przez lata wymogi kapitałowe dla banków opierały się na jednodniowym 99% VaR, a późniejsze ramy ryzyka rynkowego Bazylei zastąpiły tę miarę 97,5% oczekiwanym niedoborem (expected shortfall).
Standardowym sposobem przejścia między horyzontami jest skalowanie za pomocą pierwiastka kwadratowego z czasu: mnoży się wynik dla jednej sesji przez pierwiastek kwadratowy z liczby sesji w danym horyzoncie. Metoda ta zakłada, że stopy zwrotu są niezależne i mają stałą sigmę, a kolumna z roczną sigmą powyżej pokazuje, że w praktyce założenie to nie jest spełnione.
Dokładny kod SQL dla każdej liczby
WITH
px AS
(
SELECT date, max(toFloat64(close)) AS close_px
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'SPY'
AND date >= '2009-11-01'
AND date < '2026-01-01'
GROUP BY date
),
multi AS
(
SELECT
date,
100 * (close_px / p1 - 1) AS r1,
100 * (close_px / p5 - 1) AS r5,
100 * (close_px / p10 - 1) AS r10,
100 * (close_px / p20 - 1) AS r20
FROM
(
SELECT
date,
close_px,
lagInFrame(close_px, 1) OVER (ORDER BY date ROWS BETWEEN 20 PRECEDING AND CURRENT ROW) AS p1,
lagInFrame(close_px, 5) OVER (ORDER BY date ROWS BETWEEN 20 PRECEDING AND CURRENT ROW) AS p5,
lagInFrame(close_px, 10) OVER (ORDER BY date ROWS BETWEEN 20 PRECEDING AND CURRENT ROW) AS p10,
lagInFrame(close_px, 20) OVER (ORDER BY date ROWS BETWEEN 20 PRECEDING AND CURRENT ROW) AS p20
FROM px
)
WHERE date >= '2010-01-01' AND p20 > 0
),
q AS
(
SELECT
quantileExact(0.01)(r1) AS q1,
quantileExact(0.01)(r5) AS q5,
quantileExact(0.01)(r10) AS q10,
quantileExact(0.01)(r20) AS q20
FROM multi
)
SELECT
tupleElement(h, 1) AS horizon,
round(-1 * tupleElement(h, 3), 2) AS actual_var_pct,
round(-1 * q1 * sqrt(tupleElement(h, 2)), 2) AS sqrt_scaled_var_pct,
round(tupleElement(h, 3) / (q1 * sqrt(tupleElement(h, 2))), 2) AS actual_to_scaled_ratio
FROM
(
SELECT
q1,
arrayJoin([
('1 session', 1.0, q1, 1),
('5 sessions', 5.0, q5, 2),
('10 sessions', 10.0, q10, 3),
('20 sessions', 20.0, q20, 4)
]) AS h
FROM q
)
ORDER BY tupleElement(h, 4)Pierwszy wiersz stanowi sprawdzenie tożsamości: przy 1 session wartość skalowana jest równa wartości zmierzonej, co daje stosunek 1. W punkcie 20 sessions wartości te rozbiegają się, przy czym nie w kierunku, przed którym zazwyczaj ostrzega się w kontekście tego uproszczenia: skalowanie wyniku dla jednej sesji daje 13.8%, podczas gdy stopy zwrotu zmierzone w tym horyzoncie wynoszą 10.7%, co daje stosunek 0.78. W tym oknie czasowym wartość skalowana znajduje się powyżej zmierzonego ogona rozkładu dla wielu sesji. Ścierają się tu dwa wzorce. Rozkład z grubymi ogonami dla pojedynczej sesji staje się cieńszy w miarę sumowania stóp zwrotu, a zagregowany kwantyl 99% rośnie wolniej niż pierwiastek kwadratowy z horyzontu. Klastrowanie zmienności działa w przeciwnym kierunku, kumulując gwałtowne sesje wewnątrz jednego okna. W tym szeregu pierwszy wzorzec dominuje, jednak żaden z nich nie jest gwarantowany w innym oknie lub dla innego aktywa, co stanowi sedno problemu: mnożnik jest założeniem, a nie pomiarem. To właśnie na klastrowaniu zmienności opiera się targetowanie zmienności przy dostosowywaniu wielkości pozycji.
Jeszcze jedno ograniczenie, sformułowane wprost. Wszystko powyżej dotyczy VaR dla pojedynczego aktywa w ramach szerokiego funduszu indeksowego. Portfel dziesięciu skorelowanych instrumentów niesie ze sobą ryzyko koncentracji, z którym portfelowy VaR radzi sobie poprzez szacunek korelacji, a korelacje zmieniają się najbardziej w momencie, gdy szacunek ten staje się kluczowy.
Uwagi metodologiczne i konwencje
- Percentyle pochodzą z dokładnego kwantyla, a nie z estymacji próbkowej, a losowania Monte Carlo pochodzą z sekwencji opartej na funkcji skrótu (hash) zapisanej w SQL, dzięki czemu każda liczba w tym miejscu przelicza się do tej samej wartości.
- Stopy zwrotu to zmiany cen między zamknięciami bez reinwestycji dywidend, co jest standardową konwencją dla jednodniowego VaR.
- Panel horyzontów wykorzystuje okna nakładające się: kolejne 20-sesyjne stopy zwrotu dzielą 19 dni, więc ogon rozkładu opiera się na znacznie mniejszej liczbie niezależnych obserwacji, niż sugeruje liczba wierszy.
Najczęściej zadawane pytania
Czym jest jednodniowy wskaźnik VaR na poziomie dziewięćdziesięciu dziewięciu procent?
Jest to poziom straty, który jest przekraczany w najgorszym z każdych stu dni sesyjnych, mierzony w horyzoncie jednej sesji. W powyższym szeregu szacunek historyczny wynosi 3.09%. Liczba ta określa próg i nie informuje o wielkości strat wykraczających poza ten poziom.
Która metoda obliczania VaR jest najdokładniejsza?
Żadna z trzech metod nie jest dokładna w ujęciu abstrakcyjnym, ponieważ każda z nich odpowiada na to pytanie przy odmiennych założeniach. Historyczny VaR jest wierny dostarczonej próbie i nie uwzględnia zdarzeń, których w niej zabrakło. Parametryczny VaR jest tani w obliczeniach, lecz niedoszacowuje tzw. grubych ogonów rozkładu stóp zwrotu z akcji. Metoda Monte Carlo jest natomiast tak dobra, jak rozkład, który został do niej wprowadzony.
Jaka jest różnica między VaR a oczekiwanym niedoborem (expected shortfall)?
VaR to próg przy wybranym poziomie ufności. Oczekiwany niedobór stanowi średnią strat z dni, w których próg ten został przekroczony. W tym szeregu oczekiwany niedobór na poziomie dziewięćdziesięciu dziewięciu procent wynosi 1.44 wartości VaR, podczas gdy w rozkładzie normalnym wskaźnik ten wynosi w przybliżeniu jeden i piętnaście setnych.
Czy można przeliczyć jednodniowy VaR na dziesięciodniowy VaR?
Mnożenie przez pierwiastek kwadratowy z dziesięciu jest standardowym uproszczeniem, które zakłada, że stopy zwrotu są niezależne, a zmienność pozostaje stała. Panel horyzontu mierzy tę różnicę: w okresie dwudziestu sesji wartość przeliczona wyniosła 13.8% wobec zmierzonej wartości 10.7%.
Każdy z powyższych paneli zawiera kod SQL, który wygenerował dane. Aby przeprowadzić te same trzy obliczenia dla innego tickera lub okna czasowego, należy wprowadzić odpowiednie polecenie w języku angielskim w terminalu Strasmore.