Добавьте динамическую дисперсию в модель Монте-Карло в numpy.

Вопрос или проблема

У меня есть элегантный код от других участников для метода Монте-Карло (случайное блуждание) с использованием броуновского движения. Однако в данный момент ‘волатильность’, то есть стандартное отклонение, является заданной константой. В идеале, она должна изменяться с течением времени (или цены). Есть ли способ адаптировать этот код, чтобы сделать волатильность функцией индексов numpy (как по горизонтальной, так и по вертикальной оси)? Я мог бы сделать это с помощью цикла for, но я пытаюсь сохранить векторизацию для повышения производительности.

import numpy as np

def montecarlo_brownian(start_value, T_years, steps, vol, rate = 0, sims = 1000): 
    """ генерирует случайные блуждания от начального значения для анализа Монте-Карло

    Аргументы:
        start_value (float):    начальное значение для случайных блужданий
        T_year (float):         количество рассматриваемых лет
        steps (int):            подшаги в каждом году 
        vol (float):            стандартизированное отклонение за год (т.е. подразумеваемая волатильность)
        rate (float):           безрисковая процентная ставка
        sims (int):             количество выполняемых симуляций

    Возвращает:
        (np.array)  столбцы случайных блужданий 
    """
    times = np.linspace(0, T_years, steps+1)
    dt = times[1] - times[0]

    B = np.random.normal(0, np.sqrt(dt), size=(sims, steps)).T
    S = np.exp((rate - vol ** 2 / 2) * dt + vol * B)
    S = start_value * S.cumprod(axis=0)
    return S

Комментатор jared запросил образец логики цикла for. Я определю функцию

def get_vol(t):
  pass
  #какая-то функция, которая вычисляет волатильность на основе оставшегося времени

затем использовать что-то вроде:


def monte_carlo_with_changing_vol(S0, r, T, num_sims, num_steps, volatility):
    dt = T / num_steps
    paths = np.zeros((num_sims, num_steps + 1))
    paths[:, 0] = S0

    for i in range(num_sims):
        for j in range(1, num_steps + 1):
            current_vol = vol(j)
            paths[i, j] = paths[i, j - 1] * np.exp((r - 0.5 * current_vol ** 2) * dt + current_vol * np.sqrt(dt) * np.random.normal(0, 1))

    return paths

Ответ или решение

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

1. Обзор существующего кода

У вас уже есть рабочая версия функции montecarlo_brownian, которая использует постоянное значение волатильности vol. Вот краткое описание ключевых моментов:

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

Тем не менее, для реализации динамической волатильности, нам необходимо внести изменения.

2. Определение функции волатильности

Сначала создадим функцию get_vol, которая вычисляет волатильность в зависимости от времени или других факторов, например, оставшегося времени до истечения контракта.

def get_vol(t, initial_vol, decay_factor=0.1):
    return initial_vol * np.exp(-decay_factor * t)  # примитивный пример

3. Модификация функции Монте-Карло

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

import numpy as np

def montecarlo_brownian_dynamic_vol(start_value, T_years, steps, initial_vol, rate=0, sims=1000):
    """ 
    Генерирует случайные блуждания с меняющейся волатильностью на основе времени соответствующим образом.

    Args:
        start_value (float): Начальное значение для случайных блужданий
        T_years (float): Количество лет в вопросе
        steps (int): Подшаги внутри каждого года
        initial_vol (float): Начальная волатильность
        rate (float): Безрисковая процентная ставка
        sims (int): Количество выполнения симуляций

    Returns:
        (np.array) Колонки случайных блужданий
    """

    times = np.linspace(0, T_years, steps + 1)  # Временные точки
    dt = times[1] - times[0]  # Размер временного шага

    # Получаем величину волатильности для каждого шага
    vol = get_vol(times, initial_vol)

    # Генерация случайных блужданий
    B = np.random.normal(0, np.sqrt(dt), size=(sims, steps)).T
    S = np.exp((rate - vol[:-1] ** 2 / 2) * dt + vol[:-1] * B)  # Волатильность для каждого шага
    S = start_value * S.cumprod(axis=0)  # Копируем произведения по оси 0

    return S

4. Пояснения к модификациям

  • Динамическая волатильность: Мы вычисляем волатильность vol как вектор, который изменяется в зависимости от времени. Это позволяет построить векторизованное решение без использования вложенных циклов, что увеличивает производительность.
  • Скажем, функция get_vol: Эта функция принимает временную точку и возвращает значение волатильности, зависящее от времени. Вы можете адаптировать эту функцию под свои специфические требования.
  • Обновленные формулы: Теперь для каждой временной точки используется соответствующее значение волатильности.

Таким образом, данный подход позволяет эффективно интегрировать динамическую волатильность в модель Монте-Карло без ущерба для производительности, полностью используя векторизацию numpy. Вы можете адаптировать функцию get_vol соответственно вашим потребностям и тестировать различными вариантами поведения волатильности.

Оцените материал
Добавить комментарий

Капча загружается...