Strasmore Research
Deep Dives · Matt ConnorBy Matt Connor · · Updated 2026-08-21

Як розрахувати Value at Risk: 3 методи

Історичний, параметричний метод і Monte Carlo для VaR на одному ряді дохідностей SPY, а також expected shortfall, якого VaR не враховує.

Value at risk, або VaR, розраховують, визначаючи часовий горизонт і рівень довіри, а потім зчитуючи відповідний перцентиль із ряду дохідностей. Одноденний VaR на рівні 99% у розмірі 2% означає, що збиток не перевищує 2% у 99 із кожних 100 торгових сесій, а на сотій сесії перевищує цей рівень. На це запитання відповідають три стандартні методи, використовуючи однакові вхідні дані. Водночас їхні результати відрізняються сильніше, ніж очікує більшість учасників ринку.

Що насправді вимірює Value at Risk

VaR — це квантиль розподілу збитків. Розташуйте всі денні доходності у вибірці від найгіршої до найкращої, пройдіть 1% від найгіршого краю, і дохідність у цій точці, записана як додатний збиток, буде історичним 1-day 99% VaR. Ця конструкція не обіцяє оцінки найгіршого сценарію. Вона позначає межу ділянки, яку оцінка більше не описує.

Саме цю властивість читачі найчастіше трактують неправильно. 99% VaR означає, що найгірші 1% днів лежать за цим порогом, але нічого не говорить про те, наскільки далеко. Максимальна просадка відповідає на інше запитання — яким було фактичне падіння портфеля від піку до дна. Тому ці два показники можуть розташувати ту саму пару портфелів у протилежному порядку.

Усі наведені нижче значення розраховано за одним рядом даних: денними цінами закриття SPY від початку 2010 року до кінця 2025 року, перетвореними на відсоткові зміни від закриття до закриття. Період зафіксований, а не ковзний. Кожна панель відновлює ряд за тими самими датами, тому значення не змінюються між запусками.

ЗапитЗакріплений ряд дохідності: денна дохідність SPY за календарними роками, 2010–2025
Точний SQL-код для кожного числа
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 year
Run this yourself

Ряд охоплює 16 календарних років, зокрема 252 торгових сесій у 2010. Для всього подальшого аналізу важливі дві його особливості. Середня дохідність сесії на цьому горизонті майже не має значення: 0.054% у 2010 проти денної стандартної девіації, sigma, на рівні 1.13%. І sigma не є сталою. У 2020 вона становила 2.11% на день, а у 20170.43%. Одна sigma не може описати обидва періоди.

Як розраховують value at risk: три методи

Історичний VaR: перцентиль за фактичними результатами

Фактичні доходності сортують і визначають потрібний перцентиль. Розподіл не задається, і саме це є перевагою методу. Водночас метод передбачає, що вибірка вже містить день такого типу, який має охопити оцінка. Якщо підвищити рівень довіри достатньо високо, результат визначатимуть лише кілька найгірших сесій за весь період.

Параметричний VaR: середнє мінус z, помножене на sigma

Ряд доходностей узагальнюють за допомогою середнього значення та sigma, а потім припускають, що доходності мають нормальний розподіл. VaR дорівнює добутку z на sigma мінус середнє значення, де z — квантиль стандартного нормального розподілу: 1.645 за рівня довіри 95%, 2.326 за 99% і 3.090 за 99.9%. Розрахунок виконується миттєво, але припущення помиляється в конкретному напрямі. Денна дохідність акцій щільніше концентрується в центральній частині, ніж передбачає нормальна крива, і має значно довші хвости. Sigma тут є знаменником, який також використовується в коефіцієнті Sharpe, тому метод має ту саму слабку сторону під час роботи з даними з товстими хвостами.

VaR методом Monte Carlo: симуляція з фіксованим seed

Формують велику синтетичну вибірку на основі припущеного процесу та визначають перцентиль за змодельованими значеннями. Нижче використано 40,000 стандартних нормальних випадкових значень, згенерованих за допомогою перетворення Box-Muller із рівномірної послідовності, отриманої хешуванням і заданою seed, а потім масштабованих до середнього значення та sigma ряду. Seed зберігається в SQL, тому під час кожного повторного запуску отримують однакові значення. Симуляція забезпечує гнучкість, залежність від траєкторії та кореляцію між кількома активами, але не додає реалістичності: якщо передати їй нормальний розподіл, вона поверне параметричний результат із додатковим шумом вибірки. Натомість повторне формування вибірки з фактичних доходностей — метод, що лежить в основі бутстрепованих довірчих інтервалів, — зберігає реальний хвіст розподілу.

ЗапитОдин ряд, три методи: 1-денний VaR за шістьма рівнями довіри
Точний SQL-код для кожного числа
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)
Run this yourself

За рівня 95.0% три методи дають результати, що відрізняються менш ніж на один пункт: 1.66% історичний, 1.74% параметричний, 1.71% симульований. За рівня 99.9% результати розходяться: 5.85% історичний проти 3.31% параметричного, різниця становить 2.54 процентних пунктів за однакових даних. На кожному рівні симульований стовпець розташований поруч із параметричним. Саме це є висновком, а не недоліком. Симуляція відтворює той розподіл, який їй передали.

Якщо читати таблицю вниз по стовпцю, кожне підвищення рівня довіри розширює поріг. Якщо читати її по рядку, вибір методу майже непомітний у центральній частині розподілу, але визначає результат у хвості. Ліміт VaR без зазначення методу та періоду розрахунку — це не число, яке може відтворити хтось інший.

Що VaR не показує: expected shortfall

Expected shortfall, також відомий як conditional VaR, усереднює збитки за днями, коли перевищено VaR. VaR показує, де починається хвіст розподілу. Expected shortfall вимірює, що відбувається всередині нього.

ЗапитVaR проти очікуваного дефіциту, середній збиток понад поріг
Точний SQL-код для кожного числа
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)
Run this yourself

На рівні 99.0% VaR для цього ряду становить 3.09%, а expected shortfall — 4.43%, або 1.44 від порогового значення. За нормального розподілу це співвідношення на тому самому рівні було б близьким до 1,15. Навіть на рівні 99.9%, коли порогове значення вже сягнуло 5.85%, середній збиток у день перевищення становить 8.14%. Ліміт, встановлений лише на основі VaR, розглядає кожне перевищення як однакову подію, а стовпчик зі співвідношенням показує, наскільки це не відповідає дійсності.

Чи означає 1-денний VaR на рівні 99% те саме для установи й трейдера?

Ні. Різниця здебільшого пов’язана з горизонтом. Трейдер, який не залишає позицій на ніч, утримує ризик протягом кількох годин. Тому односесійний поріг відповідає періоду утримання, хоча внутрішньоденна траєкторія може значно перевищити показник від закриття до закриття. Установа, яка фінансує довгострокові зобов’язання, утримує позиції роками. Її експозиція реалізується протягом кварталів, а показник 1-денного VaR на рівні 99% слугує інструментом для розрахунку капіталу та моніторингу, а не описом ризику, який вона фактично несе. Протягом багатьох років правила банківського капіталу ґрунтувалися на 1-денному VaR на рівні 99%. Згодом ринкова ризикова модель Basel перевела цей показник на expected shortfall на рівні 97,5%.

Стандартний спосіб узгодити горизонти — масштабувати показник через квадратний корінь із часу: помножити односесійний показник на квадратний корінь із кількості сесій у горизонті. Цей крок передбачає незалежність дохідностей і сталу sigma. Наведена вище річна колонка sigma вже показує, що друга передумова не виконується.

ЗапитМасштабування за квадратним коренем із часу проти виміряних збитків за кілька сесій, рівень 99%
Точний SQL-код для кожного числа
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)
Run this yourself

Перший рядок — це перевірка тотожності: на горизонті 1 session масштабований показник дорівнює виміряному, а співвідношення становить 1. На горизонті 20 sessions показники розходяться, причому не в тому напрямку, про який зазвичай попереджають у разі такого спрощення: масштабування односесійного показника дає 13.8%, тоді як дохідності, виміряні за цим горизонтом, показують 10.7%. Співвідношення становить 0.78. У цьому вікні масштабований показник перевищує виміряний хвостовий показник для кількох сесій. Тут діють два протилежні фактори. Розподіл дохідностей за одну сесію має товсті хвости, але під час підсумовування дохідностей вони стають тоншими. Тому агрегований 99%-й квантиль розширюється повільніше, ніж передбачає квадратний корінь із горизонту. Кластеризація волатильності діє в протилежному напрямку, концентруючи різкі рухи в межах одного вікна. У цьому ряді перший фактор сильніший за другий. Водночас жоден із цих напрямків не гарантований для іншого вікна чи іншого активу. Саме в цьому полягає суть: множник є припущенням, а не вимірюванням. На цю кластеризацію також спирається таргетування волатильності, коли змінює розмір позицій.

Є ще одне обмеження, яке варто сформулювати прямо. Усе наведене вище стосується VaR для одного активу — широкого індексного фонду. Портфель із десяти корельованих паперів має ризик концентрації, який портфельний VaR враховує через оцінку кореляції. Водночас кореляції найсильніше змінюються саме в момент, коли ця оцінка стає важливою.

Методологічні примітки та конвенції
  • Перцентилі розраховано через точний квантиль, а вибірка для Monte Carlo формується за допомогою рівномірної послідовності з seed на основі hash, записаної в SQL. Тому кожен показник можна повторно розрахувати з тим самим результатом.
  • Дохідності — це зміни ціни від закриття до закриття без реінвестування дивідендів, що є стандартною конвенцією для односесійного VaR.
  • На панелі горизонтів використовуються перекривні вікна: сусідні 20-сесійні дохідності мають 19 спільних днів. Тому їхній хвіст ґрунтується на значно меншій кількості незалежних спостережень, ніж випливає з кількості рядків.

Поширені запитання

Що таке одноденний VaR на рівні 99%?

Це рівень збитку, який перевищується в найгірший один зі ста торгових днів, якщо вимірювати його за одну сесію. Для наведеного вище ряду історична оцінка становить 3.09%. Ця цифра визначає поріг і нічого не говорить про розмір збитків понад нього.

Який метод розрахунку VaR є найточнішим?

Абстрактно — жоден із трьох, оскільки кожен відповідає на запитання за різних припущень. Історичний VaR точно відображає надану вибірку, але не враховує події, яких у ній не було. Параметричний VaR є недорогим у розрахунку, але занижує ризик екстремальних збитків на ринку акцій. Метод Монте-Карло настільки якісний, наскільки якісним є розподіл, закладений у модель.

У чому різниця між VaR та expected shortfall?

VaR — це поріг за обраного рівня довіри. Expected shortfall показує середній збиток у дні, коли цей поріг перевищено. Для цього ряду expected shortfall на рівні 99% становить 1.44 значення VaR, тоді як за нормального розподілу це приблизно 1.15 значення VaR.

Чи можна перерахувати одноденний VaR у VaR за 10 днів?

Множення на квадратний корінь із 10 є стандартним спрощеним підходом. Він передбачає незалежність доходностей і сталу волатильність. Панель горизонтів показує різницю: за 20 сесій масштабоване значення становило 13.8%, тоді як виміряне — 10.7%.


Кожна наведена вище панель містить SQL-запит, на основі якого її побудовано. Щоб виконати ті самі три розрахунки для іншого тикера або часового проміжку, сформулюйте запит звичайною англійською мовою в терміналі Strasmore.

#risk#value at risk#expected shortfall#quant#position sizing