Изучаем опционы на Netflix: комплексный анализ и стратегии

Стоимость акций Netflix, одного из мировых лидеров стриминговой индустрии, перешагнула отметку в $1000 и демонстрирует значительную волатильность, что делает этот актив привлекательным инструментом для опционной торговли. Как специалист в области анализа данных и количественных исследований, я решил провести исследование опционов на Netflix, возможных стратегий торговли и поделиться с вами его результатами.

Типы опционов на Netflix и их особенности

Прежде чем погружаться в специфику опционов на Netflix, важно освежить в памяти фундаментальные концепции опционной торговли:

  • Опционный контракт представляет собой финансовый инструмент, дающий право, но не обязательство, купить или продать базовый актив по заранее определенной цене (страйк) до определенной даты истечения контракта;
  • Типы контрактов: call-опционы и put-опционы. Call-опцион дает право купить актив по оговоренной цене, тогда как put-опцион предоставляет право продать;
  • Страйк-цена (Strike Price) — цена исполнения опциона. Для Netflix, с учетом исторической волатильности акций, выбор правильного страйка имеет критическое значение;
  • Дата экспирации (Expiration Date) — дата, до которой действует опцион. Netflix часто демонстрирует значительные движения после выхода квартальных отчетов, что делает выбор даты экспирации стратегически важным решением;
  • Премия (Premium) — цена опциона, которую платит покупатель продавцу. Премии по опционам Netflix зачастую выше средних в сегменте техногигантов из-за высокой волатильности акций компании;
  • Внутренняя стоимость (Intrinsic Value) — разница между текущей ценой акции и страйк-ценой опциона (для call-опционов) или наоборот (для put-опционов);
  • Временная стоимость (Time Value) — компонент премии опциона, который отражает вероятность того, что опцион станет более прибыльным до истечения срока действия.

Эти параметры взаимосвязаны и определяют общую стоимость опциона.

Как уже отмечалось, для Netflix характерны некоторые особенности, которые делают опционы на его акции интересными для анализа:

  1. Высокая волатильность — Netflix известен значительными ценовыми движениями, особенно после публикации отчетов о подписчиках или запуска новых успешных проектов;
  2. Сезонность — наблюдается некоторая сезонность в поведении акций Netflix, связанная с циклами выпуска контента и отчетами о росте числа подписчиков;
  3. Реакция на макроэкономические факторы — как технологическая компания, Netflix чувствителен к изменениям процентных ставок и экономического климата.

С теорией разобрались, давайте переходить к практике. Рассмотрим пример анализа исторической волатильности Netflix с использованием Python:

import pandas as pd
import numpy as np
import yfinance as yf
import matplotlib.pyplot as plt
from scipy.stats import norm

# Загрузка исторических данных Netflix
netflix = yf.Ticker("NFLX")
hist_data = netflix.history(period="2y")

# Расчет дневной и годовой волатильности
hist_data['returns'] = hist_data['Close'].pct_change().dropna()
daily_volatility = hist_data['returns'].std()
annual_volatility = daily_volatility * np.sqrt(252)  # 252 торговых дня в году

# Расчет исторической волатильности за скользящее окно
hist_data['volatility_30d'] = hist_data['returns'].rolling(window=30).std() * np.sqrt(252)
hist_data['volatility_60d'] = hist_data['returns'].rolling(window=60).std() * np.sqrt(252)

# Визуализация волатильности
plt.figure(figsize=(12, 6))
plt.plot(hist_data.index, hist_data['volatility_30d'], label='30-дневная волатильность')
plt.plot(hist_data.index, hist_data['volatility_60d'], label='60-дневная волатильность')
plt.axhline(y=annual_volatility, color='r', linestyle='-', label='Годовая волатильность')
plt.title('Историческая волатильность акций Netflix')
plt.xlabel('Дата')
plt.ylabel('Волатильность')
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()

print(f"Текущая годовая волатильность Netflix: {annual_volatility:.2%}")

Текущая годовая волатильность Netflix: 34.73%

График исторической волатильности акций Netflix за последние 2 года

Рис. 1: График исторической волатильности акций Netflix за последние 2 года

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

Факторы, влияющие на ценообразование опционов Netflix

Стоимость опционов на акции Netflix зависит от множества факторов, которые важно учитывать при построении торговых стратегий:

  1. Волатильность базового актива — как уже упоминалось, Netflix характеризуется высокой волатильностью, что напрямую влияет на стоимость опционов. Более высокая волатильность обычно приводит к повышению премий опционов, так как увеличивается вероятность значительного движения цены;
  2. Время до экспирации — чем больше времени остается до истечения срока действия опциона, тем выше его временная стоимость. Опционы Netflix с более длительным сроком действия могут быть более ценными из-за возможности значительных движений цен в течение этого периода;
  3. Взаимосвязь текущей цены акции и страйк-цены — опционы бывают «в деньгах» (ITM), «при деньгах» (ATM) и «вне денег» (OTM). Для Netflix часто наблюдается интересная динамика premium skew — разницы в премиях между опционами с разными страйками;
  4. Корпоративные события — квартальные отчеты, объявления о новых сериалах или фильмах, изменения в руководстве или бизнес-модели могут существенно влиять на цену акций и, соответственно, на стоимость опционов;
  5. Рыночные условия — общая рыночная ситуация, настроения инвесторов, экономические показатели – все это тоже влияет на ценообразование этих опционов.

Мне всегда было интересно проводить анализ подразумеваемой волатильности (implied volatility) опционов Netflix до и после ключевых корпоративных событий. Вот пример кода для анализа этого явления:

import pandas as pd
import numpy as np
import yfinance as yf
from datetime import datetime, timedelta
import matplotlib.pyplot as plt
import seaborn as sns

# Функция для получения implied volatility для опционов с разными страйками
def get_options_iv_surface(ticker, date=None):
    stock = yf.Ticker(ticker)
    if date is None:
        # Получаем ближайшую доступную дату экспирации
        date = stock.options[0]
    
    options = stock.option_chain(date)
    calls = options.calls
    puts = options.puts
    
    # Добавляем тип опциона
    calls['option_type'] = 'call'
    puts['option_type'] = 'put'
    
    # Объединяем данные
    all_options = pd.concat([calls, puts])
    
    # Фильтруем только нужные столбцы
    all_options = all_options[['strike', 'impliedVolatility', 'option_type']]
    
    return all_options

# Получаем текущую цену акции
netflix = yf.Ticker("NFLX")
current_price = netflix.history(period="1d")['Close'].iloc[-1]

# Получаем данные о подразумеваемой волатильности
iv_data = get_options_iv_surface("NFLX")

# Визуализируем улыбку волатильности
plt.figure(figsize=(12, 6))
sns.lineplot(x='strike', y='impliedVolatility', hue='option_type', data=iv_data)
plt.axvline(x=current_price, color='black', linestyle='--', label='Текущая цена')
plt.title('Улыбка волатильности для опционов Netflix')
plt.xlabel('Страйк')
plt.ylabel('Подразумеваемая волатильность')
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()

# Анализ временной структуры волатильности
# Получаем данные для разных дат экспирации
dates = netflix.options[:4]  # берем первые 4 доступные даты экспирации
term_structure = pd.DataFrame()

for date in dates:
    iv_data = get_options_iv_surface("NFLX", date)
    # Находим опционы около текущей цены (ATM)
    atm_options = iv_data[(iv_data['strike'] > current_price*0.95) & 
                          (iv_data['strike'] < current_price*1.05)]
    
    # Вычисляем среднюю IV для ATM опционов
    avg_iv = atm_options['impliedVolatility'].mean()
    
    # Добавляем в DataFrame
    term_structure = pd.concat(
    [term_structure, pd.DataFrame([{
        'expiration': date,
        'days_to_expiry': (datetime.strptime(date, '%Y-%m-%d') - datetime.now()).days,
        'avg_iv': avg_iv
    }])],
    ignore_index=True)

# Визуализируем временную структуру волатильности
plt.figure(figsize=(10, 5))
plt.plot(term_structure['days_to_expiry'], term_structure['avg_iv'], marker='o')
plt.title('Временная структура волатильности опционов Netflix')
plt.xlabel('Дни до экспирации')
plt.ylabel('Средняя подразумеваемая волатильность (ATM)')
plt.grid(True)
plt.tight_layout()
plt.show()

Визуализация "улыбки волатильности" для опцинов Netflix

Рис. 2: Визуализация «улыбки волатильности» для опцинов Netflix

Временная структура волатильности опционов NFLX

Рис. 3: Временная структура волатильности опционов NFLX

Этот код позволяет визуализировать так называемую «улыбку волатильности» (volatility smile) и временную структуру волатильности (term structure) для опционов Netflix. Анализ этих графиков позволяет выявить рыночные ожидания относительно будущих движений цены акций и помогает в выборе оптимальных страйков и дат экспирации для различных опционных стратегий.

Количественный анализ опционов Netflix

После понимания основ опционов и факторов, влияющих на их ценообразование, перейдем к более глубокому количественному анализу опционов Netflix. В этом разделе я рассмотрю модели ценообразования опционов и проведу анализ рисков.

Модели ценообразования опционов

Для оценки стоимости опционов существует несколько моделей, но наиболее известной и широко используемой является модель Блэка-Шоулза (Black-Scholes). Несмотря на некоторые ограничения, она остается фундаментальным инструментом для оценки опционов. Давайте реализуем эту модель для опционов NFLX:

import numpy as np
from scipy.stats import norm

def black_scholes(S, K, T, r, sigma, option_type='call'):
    """
    Функция расчета стоимости опциона по модели Блэка-Шоулза
    
    Параметры:
    S - текущая цена акции
    K - цена исполнения (strike)
    T - время до истечения срока в годах
    r - безрисковая процентная ставка
    sigma - волатильность
    option_type - тип опциона ('call' или 'put')
    
    Возвращает:
    цена опциона
    """
    d1 = (np.log(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
    d2 = d1 - sigma * np.sqrt(T)
    
    if option_type == 'call':
        price = S * norm.cdf(d1) - K * np.exp(-r * T) * norm.cdf(d2)
    else:  # put
        price = K * np.exp(-r * T) * norm.cdf(-d2) - S * norm.cdf(-d1)
        
    return price

# Пример использования для Netflix
# Текущие параметры
S = current_price  # Текущая цена акции Netflix
K = 1000  # Страйк-цена
T = 0.25  # Время до экспирации в годах (3 месяца)
r = 0.05  # Безрисковая ставка
sigma = annual_volatility  # Годовая волатильность, рассчитанная ранее

# Расчет цены опционов
call_price = black_scholes(S, K, T, r, sigma, 'call')
put_price = black_scholes(S, K, T, r, sigma, 'put')

print(f"Текущая цена акций NFLX: ${current_price}")
print(f"Теоретическая цена call-опциона NFLX (страйк {K}): ${call_price:.2f}")
print(f"Теоретическая цена put-опциона NFLX (страйк {K}): ${put_price:.2f}")

# Анализ чувствительности к изменению параметров (греки)
def calculate_greeks(S, K, T, r, sigma):
    d1 = (np.log(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
    d2 = d1 - sigma * np.sqrt(T)
    
    # Delta - чувствительность к изменению цены базового актива
    call_delta = norm.cdf(d1)
    put_delta = call_delta - 1
    
    # Gamma - скорость изменения дельты
    gamma = norm.pdf(d1) / (S * sigma * np.sqrt(T))
    
    # Theta - чувствительность к изменению времени
    call_theta = -S * norm.pdf(d1) * sigma / (2 * np.sqrt(T)) - r * K * np.exp(-r * T) * norm.cdf(d2)
    put_theta = -S * norm.pdf(d1) * sigma / (2 * np.sqrt(T)) + r * K * np.exp(-r * T) * norm.cdf(-d2)
    
    # Vega - чувствительность к изменению волатильности
    vega = S * np.sqrt(T) * norm.pdf(d1)
    
    # Rho - чувствительность к изменению процентной ставки
    call_rho = K * T * np.exp(-r * T) * norm.cdf(d2)
    put_rho = -K * T * np.exp(-r * T) * norm.cdf(-d2)
    
    return {
        'call_delta': call_delta,
        'put_delta': put_delta,
        'gamma': gamma,
        'call_theta': call_theta,
        'put_theta': put_theta,
        'vega': vega,
        'call_rho': call_rho,
        'put_rho': put_rho
    }

# Рассчитываем греки для нашего примера
greeks = calculate_greeks(S, K, T, r, sigma)

print("\nГреческие параметры опционов Netflix:")
for greek, value in greeks.items():
    print(f"{greek}: {value:.6f}")

# Визуализация зависимости цены опциона от изменения волатильности
volatilities = np.linspace(0.2, 0.8, 30)  # диапазон волатильностей
call_prices = [black_scholes(S, K, T, r, vol, 'call') for vol in volatilities]
put_prices = [black_scholes(S, K, T, r, vol, 'put') for vol in volatilities]

plt.figure(figsize=(12, 6))
plt.plot(volatilities, call_prices, label='Call Option')
plt.plot(volatilities, put_prices, label='Put Option')
plt.axvline(x=sigma, color='red', linestyle='--', label=f'Текущая волатильность ({sigma:.2f})')
plt.title('Зависимость цены опционов Netflix от волатильности')
plt.xlabel('Волатильность (σ)')
plt.ylabel('Цена опциона ($)')
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()/code>
Текущая цена акций NFLX: $1138.43
Теоретическая цена call-опциона NFLX (страйк 1000): $172.22
Теоретическая цена put-опциона NFLX (страйк 1000): $21.36

Греческие параметры опционов Netflix:
call_delta: 0.817410
put_delta: -0.182590
gamma: 0.001339
call_theta: -142.588409
put_theta: -93.209519
vega: 150.705480
call_rho: 189.586933
put_rho: -57.307518

График зависимости цены опционов NFLX от волатильности

Рис. 4: График зависимости цены опционов NFLX от волатильности

Этот код реализует модель Блэка-Шоулза для оценки стоимости опционов Netflix и расчета «греков» — параметров чувствительности опционов к изменению различных факторов.

Читайте также:  Прогнозирование трафика и конверсий сайта с помощью XGBoost

Греки являются важными инструментами для управления рисками при торговле опционами:

  1. Delta (Δ) — показывает, как изменится цена опциона при изменении цены базового актива на $1. Для Netflix с его высокой волатильностью дельта может быстро меняться, что требует активного управления позицией;
  2. Gamma (Γ) — измеряет скорость изменения дельты. Высокая гамма означает, что дельта может быстро меняться при небольших изменениях цены базового актива;
  3. Theta (Θ) — показывает, как изменяется цена опциона с течением времени (временной распад). Для опционов Netflix с высокой временной стоимостью из-за высокой волатильности, тета может быть значительной;
  4. Vega (ν) — измеряет чувствительность опциона к изменениям подразумеваемой волатильности. Для Netflix, чья волатильность может значительно меняться после выхода квартальных отчетов, вега является критически важным параметром;
  5. Rho (ρ) — показывает чувствительность опциона к изменению процентной ставки.

Давайте теперь разберемся как интерпретировать те значения параметров греков, что мы получили выше:

  • Цена акции NFLX: $1138.44 — находится значительно выше страйка опционов ($1000), что делает call-опцион глубоко in-the-money, а put — out-of-the-money;
  • Теоретические цены call: $172.22, put: $21.36 — относительно высокие премии, особенно у колла, что отражает текущее положение цены относительно страйка и ожидаемую волатильность;
  • Delta (call 0.817 / put -0.183). Call-опцион реагирует на движение цены почти как сама акция, имеет высокую чувствительность. Put слабо реагирует — его используют скорее для защиты, чем для спекуляций;
  • Gamma: 0.0013. Низкая скорость изменения дельты. Подходит для менее активного хеджирования или позиций с длительным сроком;
  • Theta (call -142.59 / put -93.21). Высокое временное истощение (time decay) — особенно у колла. Это означает, что позиция теряет ценность быстро при прочих равных. Лучше подходят короткие позиции по времени или продажа этих опционов;
  • Vega: 150.71. Высокая чувствительность к изменению подразумеваемой волатильности. Если ожидается рост волатильности (например, перед отчетностью), такие опционы будут в хорошем плюсе. При снижении волатильности — потеряют в цене;
  • Rho (call 189.59 / put -57.31). Call сильно зависит от процентных ставок (чем выше ставки — тем дороже). Put, наоборот, дешевеет при их росте. В текущей ставочной среде это важно при долгосрочном трейдинге.

Таким образом, если мы собираемся купить такие опционы, важно в первую очередь учитывать высокий Theta — опцион выгоднее использовать до экспирации, либо при ожидании скачка волатильности.

Если мы собираемся продать такие опционы, то важно учесть что Calls теряют много на времени, можно рассматривать продажу с покрытием (covered call).

Если стоит задача использовать опционы для хеджирования портфеля, то Puts можно использовать, однако ввиду низкой Delta и высокой Theta лучше брать более глубокие страйки, либо с более дальними датами экспирации.

Анализ рисков опционных позиций на Netflix

При работе с опционами важно понимать и управлять рисками. Рассмотрим несколько ключевых аспектов риск-менеджмента:

Стресс-тестирование опционных позиций

Стресс-тестирование помогает понять, как будет вести себя опционная позиция при экстремальных движениях рынка. Для Netflix, учитывая его способность к резким ценовым скачкам после выхода квартальных отчетов, стресс-тестирование особенно важно.

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from scipy.stats import norm

# Black-Scholes formula
def black_scholes(S, K, T, r, sigma, option_type='call'):
    d1 = (np.log(S / K) + (r + 0.5 * sigma**2) * T) / (sigma * np.sqrt(T))
    d2 = d1 - sigma * np.sqrt(T)

    if option_type == 'call':
        return S * norm.cdf(d1) - K * np.exp(-r * T) * norm.cdf(d2)
    elif option_type == 'put':
        return K * np.exp(-r * T) * norm.cdf(-d2) - S * norm.cdf(-d1)
    else:
        raise ValueError("option_type must be 'call' or 'put'")

# Стресс-тест P&L
def stress_test(S, K, T, r, sigma, position, option_type='call'):
    price_changes = np.array([-0.2, -0.1, -0.05, 0.0, 0.05, 0.1, 0.2])  # ±20%
    vol_changes = np.array([-0.1, -0.05, 0.0, 0.05, 0.1])  # ±10%

    call_price_orig = black_scholes(S, K, T, r, sigma, option_type)
    pnl_matrix = []

    for price_change in price_changes:
        row = []
        new_S = S * (1 + price_change)
        for vol_change in vol_changes:
            new_sigma = max(0.01, sigma * (1 + vol_change))  # защита от нулевой волатильности
            call_price_new = black_scholes(S=new_S, K=K, T=T, r=r, sigma=new_sigma, option_type=option_type)
            pnl = (call_price_new - call_price_orig) * position
            row.append(round(pnl, 2))
        pnl_matrix.append(row)

    return np.array(pnl_matrix), price_changes, vol_changes

# Параметры опциона
S = current_price  # текущая цена акции
K = 1000  # страйк
T = 0.25  # до экспирации 3 месяца
r = 0.05  # безрисковая ставка
sigma = annual_volatility  # текущая волатильность
position = 1  # количество опционов (длинная позиция)

# Вычисление матрицы P&L
pnl_matrix, price_changes, vol_changes = stress_test(S, K, T, r, sigma, position)

# Построение тепловой карты
plt.figure(figsize=(10, 6))
ax = sns.heatmap(
    pnl_matrix,
    annot=True,
    fmt=".2f",
    cmap="RdYlGn",
    xticklabels=[f"{v*100:.2f}%" for v in vol_changes],
    yticklabels=[f"{p*100:.2f}%" for p in price_changes],
    cbar_kws={'label': 'P&L'}
)
ax.set_xlabel("Изменение волатильности")
ax.set_ylabel("Изменение цены акции")
plt.title("Стресс-тест P&L для позиции по опционам Netflix")
plt.tight_layout()
plt.show()

Стресс-тест P&L для позиции по опционам NFLX

Рис. 5: Стресс-тест P&L для позиции по опционам NFLX

Этот код проводит стресс-тестирование опционной позиции на Netflix, моделируя различные сценарии изменения цены акции и волатильности. Результаты визуализируются в виде тепловой карты, которая помогает быстро идентифицировать потенциально опасные сценарии.

Оценка Value-at-Risk (VaR)

Value-at-Risk — это статистическая мера риска, которая оценивает максимальный потенциальный убыток портфеля за определенный период времени с заданным уровнем доверия. Выше мы рассматривали примеры кода на Python для Call опционов, давайте теперь для этого примера рассмотрим покупку Put опциона со страйком $1000.

import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm

# Black-Scholes функция
def black_scholes(S, K, T, r, sigma, option_type='call'):
    d1 = (np.log(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
    d2 = d1 - sigma * np.sqrt(T)
    if option_type == 'call':
        return S * norm.cdf(d1) - K * np.exp(-r * T) * norm.cdf(d2)
    else:  # put
        return K * np.exp(-r * T) * norm.cdf(-d2) - S * norm.cdf(-d1)

# Функция расчёта VaR
def monte_carlo_var(position, S, K, T, r, sigma, days, confidence_level=0.95, simulations=10000):
    """
    Расчет Value-at-Risk методом Монте-Карло для опционной позиции.
    Параметры:
    - position: словарь с количеством опционов {'call': int, 'put': int}
    - S, K, T, r, sigma: параметры рынка
    - days: горизонт VaR в днях
    - confidence_level: уровень доверия (0.95 по умолчанию)
    - simulations: число симуляций
    """
    T_days = days / 252  # горизонт в годах

    # Рассчитываем текущую цену опционов
    call_price = black_scholes(S, K, T, r, sigma, 'call')
    put_price = black_scholes(S, K, T, r, sigma, 'put')
    initial_value = position.get('call', 0) * call_price + position.get('put', 0) * put_price

    # Генерация симуляций цен актива
    np.random.seed(42)
    Z = np.random.standard_normal(simulations)
    ST = S * np.exp((r - 0.5 * sigma**2) * T_days + sigma * np.sqrt(T_days) * Z)

    new_T = T - T_days
    pnl = np.zeros(simulations)

    for i in range(simulations):
        # Цена опционов в конце горизонта
        if new_T <= 0: new_call = max(0, ST[i] - K) if position.get('call', 0) > 0 else 0
            new_put = max(0, K - ST[i]) if position.get('put', 0) > 0 else 0
        else:
            new_call = black_scholes(ST[i], K, new_T, r, sigma, 'call') if position.get('call', 0) > 0 else 0
            new_put = black_scholes(ST[i], K, new_T, r, sigma, 'put') if position.get('put', 0) > 0 else 0

        new_value = position.get('call', 0) * new_call + position.get('put', 0) * new_put
        pnl[i] = new_value - initial_value

    pnl = np.sort(pnl)
    var_index = int(simulations * (1 - confidence_level))
    var = -pnl[var_index]  # знак минус, чтобы показать убыток как положительное число

    return var, pnl

# Параметры рынка и опциона
S = current_price      # текущая цена акции
K = 1000               # страйк
T = 90 / 365           # 90 дней до экспирации
r = 0.05               # безрисковая ставка
sigma = annual_volatility  # волатильность

position = {'call': 0, 'put': 1}  # позиция по опционам (один пут)

# Расчет VaR
var_30d_95, pnl_distribution = monte_carlo_var(
    position, S, K, T, r, sigma,
    days=30,
    confidence_level=0.95,
    simulations=10000
)

print(f"\nValue-at-Risk (30 дней, 95% доверие): ${var_30d_95:.2f}")

# Визуализация P&L
plt.figure(figsize=(12, 6))
plt.hist(pnl_distribution, bins=50, alpha=0.7, color='skyblue', edgecolor='black')
plt.axvline(x=-var_30d_95, color='red', linestyle='--', label=f'VaR (30д, 95%): ${var_30d_95:.2f}')
plt.title('Распределение P&L для Put позиции по опционам Netflix (30 дней)')
plt.xlabel('Прибыль / Убыток ($)')
plt.ylabel('Частота')
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()

Value-at-Risk (30 дней, 95% доверие): $20.88

Распределение P&L для Put позиции по опционам NFLX (30 дней)

Рис. 6: Распределение P&L для Put позиции по опционам NFLX (30 дней)

Этот код использует метод Монте-Карло для оценки Value-at-Risk опционной позиции на Netflix. Он генерирует множество случайных траекторий цены акции и рассчитывает соответствующие изменения стоимости позиции. VaR определяется как квантиль распределения убытков, соответствующий заданному уровню доверия.

Разработка опционных стратегий для Netflix

После того как мы рассмотрели теоретические основы опционов и методы их количественного анализа, перейдем к практическим стратегиям торговли опционами NFLX. В этом разделе я поделюсь несколькими стратегиями, которые могут быть эффективны для акций с высокой волатильностью, характерной для Netflix.

Читайте также:  Вероятностные модели для прогнозирования цен биржевых активов

Стратегии, основанные на ожидании значительного движения цены

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

Стратегия Long Straddle

Long Straddle подразумевает одновременную покупку call- и put-опционов с одинаковым страйком и датой экспирации. Эта стратегия прибыльна, если цена акции значительно двигается в любом направлении.

def long_straddle(S, K, T, r, sigma, price_range):
    """
    Анализ стратегии Long Straddle для Netflix
    
    Параметры:
    S - текущая цена акции
    K - цена исполнения (strike)
    T - время до истечения срока в годах
    r - безрисковая процентная ставка
    sigma - волатильность
    price_range - диапазон возможных цен акции при экспирации
    """
    # Расчет премий опционов
    call_premium = black_scholes(S, K, T, r, sigma, 'call')
    put_premium = black_scholes(S, K, T, r, sigma, 'put')
    total_premium = call_premium + put_premium
    
    # Расчет прибыли/убытка при различных ценах акции при экспирации
    prices = np.linspace(price_range[0], price_range[1], 100)
    payoffs = []
    
    for price in prices:
        call_payoff = max(0, price - K)
        put_payoff = max(0, K - price)
        total_payoff = call_payoff + put_payoff - total_premium
        payoffs.append(total_payoff)
    
    # Нахождение точек безубыточности
    break_even_low = K - total_premium
    break_even_high = K + total_premium
    
    # Визуализация
    plt.figure(figsize=(12, 6))
    plt.plot(prices, payoffs)
    plt.axhline(y=0, color='black', linestyle='-', alpha=0.3)
    plt.axvline(x=K, color='green', linestyle='--', label=f'Страйк ({K})')
    plt.axvline(x=break_even_low, color='red', linestyle='--', label=f'Нижняя точка безубыточности ({break_even_low:.2f})')
    plt.axvline(x=break_even_high, color='red', linestyle='--', label=f'Верхняя точка безубыточности ({break_even_high:.2f})')
    plt.axvline(x=S, color='blue', linestyle='--', label=f'Текущая цена ({S:.2f})')
    
    plt.title('Профиль прибыли/убытка стратегии Long Straddle для Netflix')
    plt.xlabel('Цена акции при экспирации')
    plt.ylabel('Прибыль/Убыток ($)')
    plt.legend()
    plt.grid(True)
    plt.tight_layout()
    plt.show()
    
    return {
        'call_premium': call_premium,
        'put_premium': put_premium,
        'total_premium': total_premium,
        'break_even_low': break_even_low,
        'break_even_high': break_even_high,
        'max_loss': total_premium,
        'max_profit': 'Неограничена при значительном движении цены'
    }

# Анализ стратегии Long Straddle для Netflix
price_range = [S * 0.7, S * 1.3]  # от -30% до +30% от текущей цены
straddle_results = long_straddle(S, 1200, T, r, sigma, price_range)  # используем ATM опционы

print("\nАнализ стратегии Long Straddle для Netflix:")
for key, value in straddle_results.items():
    print(f"{key}: {value}")
Анализ стратегии Long Straddle для Netflix:
call_premium: 58.57084893773367
put_premium: 105.42721244432232
total_premium: 163.998061382056
break_even_low: 1036.001938617944
break_even_high: 1363.998061382056
max_loss: 163.998061382056
max_profit: Неограничена при значительном движении цены

Профиль прибыли/убытка стратегии Long Straddle

Рис. 7: Профиль прибыли/убытка стратегии Long Straddle

Стратегия Long Straddle для Netflix особенно интересна перед выходом квартальных отчетов, когда ожидается значительное движение цены, но направление этого движения неизвестно. Исторический анализ показывает, что Netflix часто демонстрирует движения более 10% после публикации данных о росте подписчиков.

Стратегия Long Strangle

Long Strangle похожа на Long Straddle, но использует OTM-опционы (вне денег), что делает ее дешевле в реализации, но требует более значительного движения цены для получения прибыли.

def long_strangle(S, K_call, K_put, T, r, sigma, price_range):
    """
    Анализ стратегии Long Strangle для Netflix
    
    Параметры:
    S - текущая цена акции
    K_call - цена исполнения call-опциона (обычно выше текущей цены)
    K_put - цена исполнения put-опциона (обычно ниже текущей цены)
    T - время до истечения срока в годах
    r - безрисковая процентная ставка
    sigma - волатильность
    price_range - диапазон возможных цен акции при экспирации
    """
    # Расчет премий опционов
    call_premium = black_scholes(S, K_call, T, r, sigma, 'call')
    put_premium = black_scholes(S, K_put, T, r, sigma, 'put')
    total_premium = call_premium + put_premium
    
    # Расчет прибыли/убытка при различных ценах акции при экспирации
    prices = np.linspace(price_range[0], price_range[1], 100)
    payoffs = []
    
    for price in prices:
        call_payoff = max(0, price - K_call)
        put_payoff = max(0, K_put - price)
        total_payoff = call_payoff + put_payoff - total_premium
        payoffs.append(total_payoff)
    
    # Нахождение точек безубыточности
    break_even_low = K_put - total_premium
    break_even_high = K_call + total_premium
    
    # Визуализация
    plt.figure(figsize=(12, 6))
    plt.plot(prices, payoffs)
    plt.axhline(y=0, color='black', linestyle='-', alpha=0.3)
    plt.axvline(x=K_call, color='green', linestyle='--', label=f'Страйк Call ({K_call})')
    plt.axvline(x=K_put, color='green', linestyle=':', label=f'Страйк Put ({K_put})')
    plt.axvline(x=break_even_low, color='red', linestyle='--', label=f'Нижняя точка безубыточности ({break_even_low:.2f})')
    plt.axvline(x=break_even_high, color='red', linestyle='--', label=f'Верхняя точка безубыточности ({break_even_high:.2f})')
    plt.axvline(x=S, color='blue', linestyle='--', label=f'Текущая цена ({S:.2f})')
    
    plt.title('Профиль прибыли/убытка стратегии Long Strangle для Netflix')
    plt.xlabel('Цена акции при экспирации')
    plt.ylabel('Прибыль/Убыток ($)')
    plt.legend()
    plt.grid(True)
    plt.tight_layout()
    plt.show()
    
    return {
        'call_premium': call_premium,
        'put_premium': put_premium,
        'total_premium': total_premium,
        'break_even_low': break_even_low,
        'break_even_high': break_even_high,
        'max_loss': total_premium,
        'max_profit': 'Неограничена при значительном движении цены'
    }

# Анализ стратегии Long Strangle для Netflix
K_call = S * 1.10  # call-опцион на 10% выше текущей цены
K_put = S * 0.90   # put-опцион на 10% ниже текущей цены
strangle_results = long_strangle(S, K_call, K_put, T, r, sigma, price_range)

print("\nАнализ стратегии Long Strangle для Netflix:")
for key, value in strangle_results.items():
    print(f"{key}: {value}")
Анализ стратегии Long Strangle для Netflix:
call_premium: 41.596090438789815
put_premium: 27.18289953774513
total_premium: 68.77898997653494
break_even_low: 955.81695728909
break_even_high: 1321.0629255234098
max_loss: 68.77898997653494
max_profit: Неограничена при значительном движении цены

Профиль прибыли/убытка стратегии Long Strangle

Рис. 8: Профиль прибыли/убытка стратегии Long Strangle

Long Strangle требует меньших первоначальных вложений по сравнению с Long Straddle, но для прибыльности необходимо более сильное движение цены.

Стратегии, основанные на волатильности

Netflix характеризуется не только высокой волатильностью, но и циклами повышения и снижения волатильности. Рассмотрим стратегии, которые могут работать в разных фазах волатильности:

Стратегия Iron Condor

Iron Condor — это нейтральная по направлению стратегия, которая приносит прибыль, если цена акции остается в определенном диапазоне. Эта стратегия может быть эффективна в периоды низкой волатильности Netflix.

def iron_condor(S, K_put_sell, K_put_buy, K_call_buy, K_call_sell, T, r, sigma, price_range):
    """
    Анализ стратегии Iron Condor для Netflix
    
    Параметры:
    S - текущая цена акции
    K_put_sell - страйк проданного put-опциона
    K_put_buy - страйк купленного put-опциона (ниже K_put_sell)
    K_call_buy - страйк купленного call-опциона
    K_call_sell - страйк проданного call-опциона (выше K_call_buy)
    T - время до истечения срока в годах
    r - безрисковая процентная ставка
    sigma - волатильность
    price_range - диапазон возможных цен акции при экспирации
    """
    # Расчет премий опционов
    put_sell_premium = black_scholes(S, K_put_sell, T, r, sigma, 'put')
    put_buy_premium = black_scholes(S, K_put_buy, T, r, sigma, 'put')
    call_buy_premium = black_scholes(S, K_call_buy, T, r, sigma, 'call')
    call_sell_premium = black_scholes(S, K_call_sell, T, r, sigma, 'call')
    
    # Чистая премия (прибыль от продажи минус стоимость покупки)
    net_premium = put_sell_premium - put_buy_premium + call_sell_premium - call_buy_premium
    
    # Расчет прибыли/убытка при различных ценах акции при экспирации
    prices = np.linspace(price_range[0], price_range[1], 100)
    payoffs = []
    
    for price in prices:
        # Payoff для put spread
        if price <= K_put_buy: put_spread_payoff = K_put_buy - K_put_sell elif price >= K_put_sell:
            put_spread_payoff = 0
        else:
            put_spread_payoff = price - K_put_sell
            
        # Payoff для call spread
        if price >= K_call_sell:
            call_spread_payoff = K_call_buy - K_call_sell
        elif price <= K_call_buy:
            call_spread_payoff = 0
        else:
            call_spread_payoff = K_call_buy - price
            
        # Общий payoff с учетом полученной премии
        total_payoff = net_premium - put_spread_payoff - call_spread_payoff
        payoffs.append(total_payoff)
    
    # Нахождение точек безубыточности
    max_profit = net_premium
    max_loss = min(K_call_sell - K_call_buy, K_put_sell - K_put_buy) - net_premium
    
    # Визуализация
    plt.figure(figsize=(12, 6))
    plt.plot(prices, payoffs)
    plt.axhline(y=0, color='black', linestyle='-', alpha=0.3)
    plt.axvline(x=K_put_buy, color='green', linestyle=':', label=f'K put buy ({K_put_buy})')
    plt.axvline(x=K_put_sell, color='green', linestyle='--', label=f'K put sell ({K_put_sell})')
    plt.axvline(x=K_call_buy, color='red', linestyle=':', label=f'K call buy ({K_call_buy})')
    plt.axvline(x=K_call_sell, color='red', linestyle='--', label=f'K call sell ({K_call_sell})')
    plt.axvline(x=S, color='blue', linestyle='--', label=f'Текущая цена ({S:.2f})')
    
    plt.title('Профиль прибыли/убытка стратегии Iron Condor для Netflix')
    plt.xlabel('Цена акции при экспирации')
    plt.ylabel('Прибыль/Убыток ($)')
    plt.legend()
    plt.grid(True)
    plt.tight_layout()
    plt.show()
    
    return {
        'put_sell_premium': put_sell_premium,
        'put_buy_premium': put_buy_premium,
        'call_buy_premium': call_buy_premium,
        'call_sell_premium': call_sell_premium,
        'net_premium': net_premium,
        'max_profit': max_profit,
        'max_loss': max_loss
    }

# Анализ стратегии Iron Condor для Netflix
K_put_sell = S * 0.90
K_put_buy = S * 0.85
K_call_buy = S * 1.10
K_call_sell = S * 1.15
condor_results = iron_condor(S, K_put_sell, K_put_buy, K_call_buy, K_call_sell, T, r, sigma, price_range)

print("\nАнализ стратегии Iron Condor для Netflix:")
for key, value in condor_results.items():
    print(f"{key}: {value}")
Анализ стратегии Iron Condor для Netflix:
put_sell_premium: 27.18289953774513
put_buy_premium: 14.55832996526803
call_buy_premium: 41.596090438789815
call_sell_premium: 27.910113051836845
net_premium: -1.0614078144758707
max_profit: -1.0614078144758707
max_loss: 57.98340488478837

Профиль прибыли/убытка стратегии Iron Condor

Рис. 9: Профиль прибыли/убытка стратегии Iron Condor

Iron Condor позволяет зарабатывать на временном распаде опционов (theta decay) в периоды низкой волатильности Netflix. Однако важно правильно выбирать диапазон страйков, учитывая историческую волатильность акций и расстояние до ближайших значимых корпоративных событий.

Стратегия Calendar Spread

Calendar Spread (календарный спред) использует разницу во временной стоимости опционов с разными датами экспирации. Эта стратегия может быть эффективна, когда ожидается временное повышение волатильности, за которым последует ее снижение.

def calendar_spread(S, K, T_near, T_far, r, sigma, price_range, days_to_expiry_near):
    """
    Анализ стратегии Calendar Spread для Netflix
    
    Параметры:
    S - текущая цена акции
    K - цена исполнения (одинаковая для обоих опционов)
    T_near - время до истечения ближнего опциона в годах
    T_far - время до истечения дальнего опциона в годах
    r - безрисковая процентная ставка
    sigma - волатильность
    price_range - диапазон возможных цен акции при экспирации ближнего опциона
    days_to_expiry_near - дни до экспирации ближнего опциона
    """
    # Расчет премий опционов
    call_near_premium = black_scholes(S, K, T_near, r, sigma, 'call')
    call_far_premium = black_scholes(S, K, T_far, r, sigma, 'call')
    
    # Начальные инвестиции (покупка дальнего, продажа ближнего)
    initial_investment = call_far_premium - call_near_premium
    
    # Расчет прибыли/убытка при различных ценах акции при экспирации ближнего опциона
    prices = np.linspace(price_range[0], price_range[1], 100)
    payoffs = []
    
    # Оставшееся время до экспирации дальнего опциона после экспирации ближнего
    T_remaining = T_far - T_near
    
    for price in prices:
        # Стоимость дальнего опциона при экспирации ближнего
        call_far_value = black_scholes(price, K, T_remaining, r, sigma, 'call')
        
        # Стоимость ближнего опциона при экспирации (внутренняя стоимость)
        call_near_value = max(0, price - K)
        
        # Общий payoff
        total_payoff = call_far_value - call_near_value - initial_investment
        payoffs.append(total_payoff)
    
    # Визуализация
    plt.figure(figsize=(12, 6))
    plt.plot(prices, payoffs)
    plt.axhline(y=0, color='black', linestyle='-', alpha=0.3)
    plt.axvline(x=K, color='green', linestyle='--', label=f'Страйк ({K})')
    plt.axvline(x=S, color='blue', linestyle='--', label=f'Текущая цена ({S:.2f})')
    
    plt.title(f'Профиль прибыли/убытка стратегии Calendar Spread для Netflix через {days_to_expiry_near} дней')
    plt.xlabel('Цена акции при экспирации ближнего опциона')
    plt.ylabel('Прибыль/Убыток ($)')
    plt.legend()
    plt.grid(True)
    plt.tight_layout()
    plt.show()
    
    return {
        'call_near_premium': call_near_premium,
        'call_far_premium': call_far_premium,
        'initial_investment': initial_investment,
        'max_profit_estimate': 'Зависит от будущей волатильности и цены базового актива'
    }

# Анализ стратегии Calendar Spread для Netflix
T_near = 1/12  # 1 месяц до экспирации ближнего опциона
T_far = 3/12   # 3 месяца до экспирации дальнего опциона
calendar_results = calendar_spread(S, 1200, T_near, T_far, r, sigma, price_range, days_to_expiry_near=30)

print("\nАнализ стратегии Calendar Spread для Netflix:")
for key, value in calendar_results.items():
    print(f"{key}: {value}")
Анализ стратегии Calendar Spread для Netflix:
call_near_premium: 23.704215027612065
call_far_premium: 59.183164360452054
initial_investment: 35.47894933283999
max_profit_estimate: Зависит от будущей волатильности и цены базового актива

Профиль прибыли/убытка стратегии Calendar Spread для NFLX через 30 дней

Рис. 10: Профиль прибыли/убытка стратегии Calendar Spread для NFLX через 30 дней

Calendar Spread для Netflix может быть особенно интересен, когда ближайший опцион истекает вскоре после выхода квартального отчета (когда ожидается снижение волатильности), а дальний опцион имеет более длительный срок до экспирации.

Читайте также:  Показатели Альфа, Бета, коэффициент Шарпа: Расчеты в Python

Машинное обучение для оптимизации опционных стратегий

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

Прогнозирование волатильности с помощью Random Forest

Ниже пример использования машинного обучения для прогнозирования волатильности Netflix и оптимизации опционных стратегий с помощью алгоритма случайного леса.

from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.metrics import mean_squared_error, r2_score

def predict_volatility_with_ml(ticker="NFLX", lookback_period=252*2, prediction_days=30):
    """
    Функция для прогнозирования будущей волатильности с использованием машинного обучения
    
    Параметры:
    ticker - тикер акции
    lookback_period - период исторических данных для анализа (в днях)
    prediction_days - на сколько дней вперед делать прогноз
    """
    # Загрузка исторических данных
    stock = yf.Ticker(ticker)
    hist_data = stock.history(period=f"{lookback_period + 100}d")  # немного больше для создания фичей
    
    # Расчет исторической волатильности для разных окон
    hist_data['returns'] = hist_data['Close'].pct_change().dropna()
    hist_data['volatility_10d'] = hist_data['returns'].rolling(window=10).std() * np.sqrt(252)
    hist_data['volatility_20d'] = hist_data['returns'].rolling(window=20).std() * np.sqrt(252)
    hist_data['volatility_30d'] = hist_data['returns'].rolling(window=30).std() * np.sqrt(252)
    hist_data['volatility_60d'] = hist_data['returns'].rolling(window=60).std() * np.sqrt(252)
    
    # Создание целевой переменной - волатильность через prediction_days дней
    hist_data['target_volatility'] = hist_data['volatility_30d'].shift(-prediction_days)
    
    # Добавление технических индикаторов в качестве фичей
    hist_data['ma_20'] = hist_data['Close'].rolling(window=20).mean()
    hist_data['ma_50'] = hist_data['Close'].rolling(window=50).mean()
    hist_data['ma_ratio'] = hist_data['ma_20'] / hist_data['ma_50']
    hist_data['volume_change'] = hist_data['Volume'].pct_change().rolling(window=5).mean()
    
    # Дополнительные фичи, связанные с ценовыми паттернами
    hist_data['price_range'] = (hist_data['High'] - hist_data['Low']) / hist_data['Close']
    hist_data['price_range_ma5'] = hist_data['price_range'].rolling(window=5).mean()
    hist_data['returns_std_5d'] = hist_data['returns'].rolling(window=5).std()
    
    # Удаление строк с NaN
    hist_data = hist_data.dropna()
    
    # Выбор фичей и целевой переменной
    features = ['volatility_10d', 'volatility_20d', 'volatility_30d', 'volatility_60d', 
                'ma_ratio', 'volume_change', 'price_range', 'price_range_ma5', 'returns_std_5d']
    
    X = hist_data[features]
    y = hist_data['target_volatility']
    
    # Разделение на обучающую и тестовую выборки
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
    
    # Стандартизация данных
    scaler = StandardScaler()
    X_train_scaled = scaler.fit_transform(X_train)
    X_test_scaled = scaler.transform(X_test)
    
    # Обучение модели RandomForest с оптимизацией гиперпараметров
    param_grid = {
        'n_estimators': [50, 100, 200],
        'max_depth': [None, 10, 20, 30],
        'min_samples_split': [2, 5, 10]
    }
    
    rf = RandomForestRegressor(random_state=42)
    grid_search = GridSearchCV(rf, param_grid, cv=5, scoring='neg_mean_squared_error')
    grid_search.fit(X_train_scaled, y_train)
    
    # Лучшая модель
    best_rf = grid_search.best_estimator_
    
    # Оценка модели
    y_pred = best_rf.predict(X_test_scaled)
    mse = mean_squared_error(y_test, y_pred)
    r2 = r2_score(y_test, y_pred)
    
    print(f"\nРезультаты прогнозирования волатильности для {ticker}:")
    print(f"Mean squared error: {mse:.6f}")
    print(f"R² score: {r2:.6f}")
    
    # Важность фичей
    feature_importance = pd.DataFrame({
        'Feature': features,
        'Importance': best_rf.feature_importances_
    }).sort_values(by='Importance', ascending=False)
    
    plt.figure(figsize=(10, 6))
    plt.barh(feature_importance['Feature'], feature_importance['Importance'])
    plt.title('Важность признаков для прогнозирования волатильности')
    plt.xlabel('Важность')
    plt.tight_layout()
    plt.show()
    
    # Прогноз будущей волатильности
    current_features = scaler.transform(hist_data[features].iloc[-1:])
    predicted_volatility = best_rf.predict(current_features)[0]
    
    print(f"\nПрогнозируемая волатильность через {prediction_days} дней: {predicted_volatility:.2%}")
    
    return predicted_volatility, best_rf, scaler, features

# Прогнозирование волатильности Netflix
predicted_vol, volatility_model, vol_scaler, vol_features = predict_volatility_with_ml()

# Сравнение с текущей волатильностью
print(f"Текущая историческая волатильность (30 дней): {hist_data['volatility_30d'].iloc[-1]:.2%}")
print(f"Рыночная подразумеваемая волатильность (ATM опционы): {sigma:.2%}")
print(f"Прогнозируемая волатильностью моделью ML: {predicted_vol:.2%}")
Результаты прогнозирования волатильности для NFLX:
Mean squared error: 0.000708
R² score: 0.920535
Прогнозируемая волатильность через 30 дней: 43.33%
Текущая историческая волатильность (30 дней): 44.28%
Рыночная подразумеваемая волатильность (ATM опционы): 34.73%
Прогнозируемая волатильностью моделью ML: 43.33%

Визуализация важности признаков ML-модели для прогнозирования волатильности

Рис. 11: Визуализация важности признаков ML-модели для прогнозирования волатильности

Этот код использует алгоритм случайного леса (Random Forest) для прогнозирования будущей волатильности акций Netflix на основе исторических данных и различных технических индикаторов. Модель учитывает взаимосвязи между различными факторами, влияющими на волатильность, и может помочь в выборе оптимальных опционных стратегий.

Анализ важности признаков показывает, какие факторы наиболее сильно влияют на будущую волатильность Netflix, что может быть использовано для дальнейшего улучшения стратегий.

Прогнозирование оптимального типа опциона с помощью градиентного бустинга

Метод XGBoost может эффективно прогнозировать вероятность роста/падения цены для выбора между колл и пут опционами. Вот как можно создать такую ML-модель для Netflix (прогноз вероятности роста или снижения цены через 20 дней), используя как параметры фильтр Баттеруорта для определения тренда и фильтрации данных от шумов, плюс историческую 30-дневную волатильность:

import yfinance as yf
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from xgboost import XGBClassifier, plot_importance
from sklearn.metrics import classification_report, accuracy_score
from sklearn.model_selection import TimeSeriesSplit
from scipy.signal import butter, filtfilt

def butterworth_filter(signal, cutoff=0.15, fs=2.0, order=2):
    """
    Применяет фильтр Баттеруорта к временному ряду
    
    signal - входной временной ряд (np.array)
    cutoff - частота среза (чем меньше, тем больше сглаживание)
    fs     - частота дискретизации
    order  - порядок фильтра
    """
    nyquist = 0.5 * fs
    normal_cutoff = cutoff / nyquist
    b, a = butter(order, normal_cutoff, btype='low', analog=False)
    filtered_signal = filtfilt(b, a, signal)
    return filtered_signal

def option_direction_strategy(ticker="NFLX", lookback=252*3):
    """
    Прогнозирование направления цены для выбора типа опциона
    Использует фильтр Баттеруорта + историческую волатильность
    """
    window = 30  # 30-дневное окно
    data = yf.Ticker(ticker).history(period=f"{lookback}d") # Загрузка данных
    data['returns'] = np.log(data['Close']).diff() # Логарифмические доходности
    data['target'] = (data['Close'].shift(-20) > data['Close']).astype(int) # Целевая переменная: цена вырастет ли через 20 дней?
    
    data['bw_close'] = butterworth_filter(data['Close'].values) # Фильтр Баттеруорта для Close
    data['bw_volume'] = butterworth_filter(data['Volume'].values) # Фильтр Баттеруорта для объема
    data['bw_returns'] = butterworth_filter(data['returns'].fillna(0)) # Фильтр Баттеруорта для лог-доходностей

    # Историческая волатильность (rolling annualized volatility)    
    data['volatility'] = data['returns'].rolling(window=window).std() * np.sqrt(252)
    
    # Добавляем волатильность как фильтрованный сигнал
    data['bw_volatility'] = butterworth_filter(data['volatility'].fillna(0))
    
    # Формируем признаки
    features = ['bw_close', 'bw_volume', 'bw_returns', 'bw_volatility']

    # Убираем NaN
    data.dropna(inplace=True)
    
    X = data[features]
    y = data['target']
    
    # Разбиение по времени
    tscv = TimeSeriesSplit(n_splits=25)
    accuracies = []
    
    for train_index, test_index in tscv.split(X):
        X_train, X_test = X.iloc[train_index], X.iloc[test_index]
        y_train, y_test = y.iloc[train_index], y.iloc[test_index]
        
        model = XGBClassifier(
            n_estimators=250,
            max_depth=15,
            learning_rate=0.01,
            eval_metric='logloss',
            use_label_encoder=False,
            verbosity=0
        )
        model.fit(X_train, y_train)
        
        preds = model.predict(X_test)
        accuracies.append(accuracy_score(y_test, preds))
    
    print(f"Средняя точность прогноза: {np.mean(accuracies):.2%}")
    print(classification_report(y_test, preds))
    
    # Важность признаков
    plot_importance(model, importance_type='weight')
    plt.title('Важность признаков модели', fontsize=12)
    plt.tight_layout()
    plt.show()
    
    # Прогноз на сейчас
    latest_data = data[features].iloc[-1].values.reshape(1, -1)
    prob_up = model.predict_proba(latest_data)[0][1]

    if prob_up > 0.5:
        decision = "Рекомендуется покупать CALL опцион"
    else:
        decision = "Рекомендуется покупать PUT опцион"

    print(f"\nВероятность роста цены через ~20 дней: {prob_up:.2%}")
    print(decision)

    # График вероятности
    plt.figure(figsize=(6, 3))
    plt.barh(['Прогноз'], [prob_up], color='skyblue', edgecolor='black')
    plt.xlim(0, 1)
    plt.xlabel('Вероятность роста цены')
    plt.title('Вероятность роста цены (прогноз)')
    plt.axvline(x=0.5, color='red', linestyle='--', label='Порог 50%')
    plt.legend()
    plt.grid(True)
    plt.tight_layout()
    plt.show()

    return model

# Запуск модели
direction_model = option_direction_strategy()
Средняя точность прогноза: 60.44%
Вероятность роста цены через ~20 дней: 17.31%
Рекомендуется покупать PUT опцион

              precision    recall  f1-score   support

           0       1.00      0.95      0.97        20
           1       0.88      1.00      0.93         7

    accuracy                           0.96        27
   macro avg       0.94      0.97      0.95        27
weighted avg       0.97      0.96      0.96        27

Визуализация наиболее важных признаков модели

Рис. 12: Визуализация наиболее важных признаков модели

График вероятности роста цены (прогноз)

Рис. 13: График вероятности роста цены (прогноз)

Основная идея этой ML-модели заключается в комбинации фильтрации сигналов и машинного обучения. Сначала применяется фильтр Баттеруорта для сглаживания исторических данных: цены закрытия, объема торгов, логарифмической доходности и 30-дневной волатильности. Он позволяет удалить рыночный шум и выделить долгосрочные тренды. Затем модель XGBoost обучается на этих отфильтрованных признаках, чтобы предсказать вероятность роста цены через 20 торговых дней.

Алгоритм использует временное разделение данных (TimeSeriesSplit) для валидации, что критически важно для финансовых временных рядов, чтобы избежать утечки будущих данных в тренировочную выборку. Модель оценивает важность каждого фильтрованного признака (например, сглаженная цена bw_close оказалась ключевым фактором) и выводит итоговую рекомендацию.

Точность модели составляет около 60% при высоком F1, и это очень даже неплохо для финансовых прогнозов, поскольку есть потенциал извлечения прибыли с рынка при правильном управлении рисками.

Заключение

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

Исследуя конкретный биржевой актив, мы начали с анализа базовых параметров опционов, затем перешли к оценке рисков через стресс-тестирование и расчет Value-at-Risk, что позволяет количественно определить потенциальные убытки в экстремальных сценариях. Затем интегрировали количественные методы в модели машинного обучения.

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