Вопрос или проблема
У меня есть элегантный код от других участников для метода Монте-Карло (случайное блуждание) с использованием броуновского движения. Однако в данный момент ‘волатильность’, то есть стандартное отклонение, является заданной константой. В идеале, она должна изменяться с течением времени (или цены). Есть ли способ адаптировать этот код, чтобы сделать волатильность функцией индексов 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
соответственно вашим потребностям и тестировать различными вариантами поведения волатильности.