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

Как рассчитать Value at Risk: три основных метода

Изучите методы расчета исторического, параметрического и Монте-Карло VaR на примере доходности SPY. Узнайте, почему эти подходы дают разные результаты и что такое ожидаемый дефицит.

Методология Value at Risk

Показатель Value at Risk, или VaR, рассчитывается путем фиксации временного горизонта, уровня доверия и последующего определения процентиля по ряду доходности. Однодневный VaR на уровне девяноста девяти процентов, равный двум процентам, означает, что убыток не превысит два процента в девяноста девяти из ста торговых сессий, а в сотой сессии — превысит. Три стандартных метода позволяют ответить на этот вопрос, используя идентичные входные данные, однако их результаты расходятся сильнее, чем ожидает большинство участников рынка.

Что на самом деле измеряет Value at Risk

VaR — это квантиль распределения убытков. Расположите все дневные доходности в выборке от худшей к лучшей, отступите один процент от начала «плохого» края, и полученное значение, выраженное как положительная величина убытка, будет представлять собой однодневный исторический VaR с уровнем доверия девяносто девять процентов. В этой конструкции нет обещания худшего сценария. Она лишь отмечает границу области, которую перестает описывать данная оценка.

Это свойство читатели упускают из виду чаще всего. VaR на уровне девяноста девяти процентов утверждает, что худший один процент дней лежит за пределами этого порога, но ничего не говорит о том, насколько далеко. Максимальная просадка отвечает на другой вопрос: это убыток от пика до впадины, который портфель фактически пережил. Эти два показателя могут ранжировать одну и ту же пару портфелей в противоположном порядке.

Каждая цифра ниже основана на одном ряде данных: дневных ценах закрытия SPY с начала две тысячи десятого года по конец две тысячи двадцать пятого года, преобразованных в процентные изменения от закрытия до закрытия. Окно зафиксировано, а не является скользящим, и каждая панель восстанавливает ряд из тех же дат, поэтому значения не меняются между запусками.

ЗапросРяды доходности: ежедневная доходность 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 году против дневного стандартного отклонения, сигмы, равного 1.13%. И сигма не является константой. В 2020 году она составляла 2.11% в день, а в 2017 году — 0.43%. Одно значение сигмы не может описать оба периода.

Три способа расчета показателя Value at Risk

Исторический VaR: определение процентиля по прошлым данным

Отсортируйте фактические доходности и выберите нужное значение процентиля. Преимущество метода в том, что он не предполагает следования какому-либо распределению. Однако метод исходит из допущения, что в выборке уже присутствуют рыночные условия того типа, который оценивается. Если задать достаточно высокий уровень доверия, результат будет определяться лишь несколькими худшими торговыми сессиями за весь период.

Параметрический VaR: среднее значение минус z, умноженное на сигму

Обобщите ряд данных с помощью среднего значения и сигмы, а затем предположите, что доходности подчиняются нормальному распределению. VaR равен z, умноженному на сигму, минус среднее значение, где z — это квантиль стандартного нормального распределения: одна целая шестьсот сорок пять тысячных для уровня девяносто пять процентов, две целых триста двадцать шесть тысячных для девяноста девяти процентов и три целых девяносто тысячных для девяноста девяти и девяти десятых процента. Расчеты выполняются мгновенно, но допущение имеет систематическую ошибку. Дневные доходности акций в центре распределения сгруппированы плотнее, чем предполагает нормальная кривая, а на «хвостах» распределения уходят значительно дальше. Сигма здесь выступает знаменателем, который также используется в коэффициенте Шарпа, и привносит ту же «слепую зону» для данных с «тяжелыми хвостами».

VaR методом Монте-Карло: симуляция с фиксированным начальным числом

Сгенерируйте большую синтетическую выборку на основе предполагаемого процесса и определите процентиль по полученным значениям. В приведенной ниже таблице используются сорок тысяч стандартных нормальных величин, полученных с помощью преобразования Бокса-Мюллера из последовательности равномерно распределенных чисел с фиксированным начальным значением (seed), масштабированных до среднего значения и сигмы ряда. Начальное число заложено в SQL-запрос, поэтому результаты симуляции идентичны при каждом повторном запуске. Симуляция обеспечивает гибкость, учет зависимости от пути и корреляции между активами, но не гарантирует реалистичность: если задать нормальное распределение, метод выдаст параметрический результат с наложением шума выборки. Использование метода перевыборки (resampling) наблюдаемых доходностей, лежащего в основе бутстреп-доверительных интервалов, позволяет сохранить реальные характеристики «хвостов».

ЗапросОдин ряд, три метода: 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)

Ожидаемый дефицит, также называемый условным VaR, представляет собой среднее значение убытков в те дни, когда показатель VaR был превышен. VaR отмечает точку, где начинается «хвост» распределения. Ожидаемый дефицит измеряет величину потерь внутри этого «хвоста».

ЗапросVaR в сравнении с ожидаемым дефицитом (ES), средний убыток сверх порогового значения
Точный 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%, а ожидаемый дефицит — 4.43%, или 1.44 от порогового значения. При нормальном распределении это соотношение находилось бы вблизи 1,15 на том же уровне. Даже при 99.9%, где пороговое значение уже достигло 5.85%, средний убыток в день превышения составляет 8.14%. Лимит, установленный только на основе VaR, рассматривает каждое превышение как идентичное событие, а столбец с соотношением показывает, насколько это не соответствует действительности.

Означает ли однодневный 99% VaR одно и то же для институционала и трейдера?

Нет, и основное различие заключается в горизонте планирования. Трейдер, закрывающий позиции к концу дня, несет риск в течение нескольких часов, поэтому однодневный порог соответствует периоду удержания, хотя внутридневная динамика может значительно отклоняться от изменения цены от закрытия до закрытия. Институциональный инвестор, финансирующий долгосрочные обязательства, удерживает позиции годами, его экспозиция измеряется кварталами, а показатель 1-дневного 99% VaR служит для него инструментом контроля капитала и отчетности, а не описанием реального риска. Правила банковского капитала годами строились на 1-дневном 99% VaR, прежде чем Базельская система оценки рыночного риска перешла к показателю ожидаемого дефицита (expected shortfall) на уровне 97,5%.

Стандартным способом пересчета между горизонтами является масштабирование через квадратный корень из времени: однодневный показатель умножается на квадратный корень из количества сессий в горизонте. Этот метод предполагает, что доходности независимы, а сигма постоянна, однако столбец с годовой сигмой выше уже демонстрирует несостоятельность этого допущения.

ЗапросМасштабирование по квадратному корню из времени в сравнении с фактическими многосессионными убытками, уровень 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 портфеля учитывает через оценку корреляции, а корреляции меняются сильнее всего именно в тот момент, когда эта оценка наиболее важна.

Методические примечания и условные обозначения
  • Процентили рассчитаны на основе точного квантиля, а не выборочной оценки; выборки методом Монте-Карло получены из равномерно распределенной последовательности с хеш-сидом, прописанной в SQL, поэтому каждое значение здесь пересчитывается в идентичный результат.
  • Доходности представляют собой изменение цены от закрытия до закрытия без реинвестирования дивидендов, что является стандартной практикой для однодневного VaR.
  • Панель горизонтов использует скользящие окна: последовательные 20-дневные доходности имеют 19 общих дней, поэтому «хвост» распределения опирается на гораздо меньшее количество независимых наблюдений, чем предполагает количество строк.

Часто задаваемые вопросы

Что такое однодневный VaR с уровнем доверия 99%?

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

Какой метод расчета VaR является наиболее точным?

Ни один из трех методов не является точным в отрыве от контекста, так как каждый из них отвечает на вопрос исходя из различных допущений. Исторический VaR точно отражает предоставленную выборку, но не учитывает события, не попавшие в нее. Параметрический VaR прост в расчетах, но недооценивает «толстые хвосты» распределения доходности акций. Метод Монте-Карло эффективен лишь настолько, насколько корректно задано распределение вероятностей.

В чем разница между VaR и ожидаемым дефицитом (expected shortfall)?

VaR — это пороговое значение при выбранном уровне доверия. Ожидаемый дефицит представляет собой среднее значение убытков в те дни, когда порог был пройден. Для данного ряда ожидаемый дефицит на уровне 99% составляет 1.44 от величины VaR, тогда как при нормальном распределении этот коэффициент равен примерно 1,15.

Можно ли конвертировать однодневный VaR в десятидневный?

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


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

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