Okama 2.0: продвинутые стратегии изъятий и новая Граница эффективности

7 мин
Okama 2.0: продвинутые стратегии изъятий и новая Граница эффективности

Мы выпустили “юбилейную” версию okama 2.0. В релизе множество важных изменений. Основные темы: новые продвинутые стратегии снятия денег из портфеля и новая логика оптимизации портфелей для Границы эффективности.

Инсталлировать или обновить до последней версии библиотеку можно уже сейчас.

pip install okama -U

В okama 2.0 мы сознательно сделали шаг от учебных и академических кейсов к более прикладным и реалистичным сценариям. Во-первых, набор модулей получила новые инструменты, которые хорошо подходят для разработки “пенсионных стратегий” с регулярными изъятиями.

Построение попарных Границ эффективности с учетом ребалансировки
Построение попарных Границ эффективности с учетом ребалансировки

Во-вторых, изменилась логика работы с Границей эффективности: теперь многопериодная оптимизация с ребалансировкой стала поведением по умолчанию. И этот более сложный вид оптимизации работает кратно быстрее! Теперь не надо оставлять работать компьютер и уходить пить чай, пока идут расчеты… Это сделало okama гораздо пригодной для WEB приложений. Изменения на okama.io не за горами.

Стратегии с денежными потоками и дисконтированием

Новые стратегии изъятий встроены в уже существующую архитектуру анализа денежных потоков с дисконтированием в классе PortfolioDCF. Портфель остаётся отдельным объектом, а стратегия денежных потоков подключается через pf.dcf.cashflow_parameters. Такая схема даёт возможность независимо тестировать структуру портфеля, правила ребалансировки и логику изъятий.

Простейший инвестиционный портфель создается из двух строчек кода:

import okama as ok pf = ok.Portfolio() # по умолчанию это портфель из одного фонда SPY

Стратегия снятий Vanguard Dynamic Spending (VDS)

В версии 1.5.0 появилась стратегия изъятия портфеля, основанная на процентном снятии (PercentageStrategy). Свежий класс VanguardDynamicSpending (VDS) развивает идею, где снятия определяются фиксированным процентом от баланса портфеля. Но вводит дополнительные ограничения. Это значимый момент: новая стратегия не заменяет старую процентную схема, а расширяет её. Идеи этой стратегии разработаны в исследовании Vangard (прилагается).

Свежий параметр, который вводит VDS, это floor_ceiling. Он ограничивает изменение снятия по сравнению с предыдущего года. Например, пара (-0.025, 0.05) означает, что новое изъятие не может быть больше чем на 5% выше и не может быть больше чем на 2.5% ниже прошлогоднего значения. Благодаря этого стратегия не допускает слишком резких скачков расходов вслед за рынком.

Дополнительно можно задать абсолютные ограничения через min_max_annual_withdrawals. Если включён adjust_min_max=True, эти границы индексируются, в частности на инфляцию. Параметр adjust_floor_ceiling работает похожим образом: сначала прошлогоднее снятие может быть проиндексировано, а затем к нему применяются floor и ceiling. В итоге VDS сочетает процентную привязку к портфелю и контроль над волатильностью потребления.

Ограничения: VDS работает только с регулярными снятиями (без пополнений), частота снятий – всегда раз в год.

Создается стратегия следующим образом:

vds = ok.VanguardDynamicSpending( parent=pf, initial_investment=1_000_000, # размер стартового капитал percentage=-0.08, # процент снятия денег floor_ceiling=(-0.025, 0.05), # процент, на который может изменяться размер снятий
) pf.dcf.cashflow_parameters = vds

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

Стратегия снятий Cut Withdrawals If Drawdown (CWD)

Это некоторое количество другая философия снятий. Размер зависит от реальных потребностей пенсионера и не зависит от размера портфеля. Этот подход был создан в версии 1.5.0 через класс IndexationStrategy.

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

Класс CutWithdrawalsIfDrawdown (CWD) задает параметры такой стратегии через ограничения снятий, которые зависят от глубины просадки портфеля.

Параметр crash_threshold_reduction задаётся списком пар вида (порог просадки, коэффициент сокращения). В частности, запись (0.20, 0.40) означает: если просадка портфеля превышает 20%, текущее снятие сокращается на 40%. А пара (0.35, 1) означает фактическую остановку изъятий при просадке глубже 35%.

Такая стратегия особенно полезна в моделях, где потребитель хочет сохранить понятную базовую сумму расходов, но одновременно заранее закодировать антикризисное поведение. Это уже не просто “снимать фиксированную сумму с индексацией”, а управлять темпом изъятий зависимо от глубины drawdown.

Разработка CWD:

cwd = ok.CutWithdrawalsIfDrawdown( parent=pf, initial_investment=1_000_000, # стартовый капитал frequency="year", # периодичность снятий (здесь – раз в год) amount=-60_000, # целевой размер снятий в сегодняшних деньгах indexation="inflation", # индексация размера снятий на размер инфляции crash_threshold_reduction=[(.10, .25), (.20, .50), (.35, 1)], # список ограничений
) pf.dcf.cashflow_parameters = cwd

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

В следующих публикациях мы расскажем более подробно, как применять на практике стратегии VDS и CWD.

EfficientFrontier: единый класс для оптимизации с учетом ребалансировки

Следующий ключевой блок релиза — обновление EfficientFrontier. Мы объединили EfficientFrontier и EfficientFrontierReb в единый класс EfficientFrontier. Теперь Граница эффективности по умолчанию строится в многопериодной логике, с ребалансировкой.

За счет кэширования находимых решений, использования параллельных вычислений и оптимизации целевых функций удалось значительно ускорить расчеты.

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

ef = ok.EfficientFrontier( assets=["SPY.US", "GLD.US"], first_date="2004-12", last_date="2020-10", ccy="USD", rebalancing_strategy=ok.Rebalance(period="year"), n_points=40, ticker_names=True, bounds=((0.0, 1.0), (0.0, 0.20)), # процент золота в портфелях ограничен 20%
)

Быстрый поиск решений для заданной доходности:

ef.minimize_risk(target_value=0.11)
{'SPY.US': np.float64(0.9101000447520419), 'GLD.US': np.float64(0.08989995524795805), 'CAGR': 0.11, 'Mean return': np.float64(0.11403419643168483), 'Risk': np.float64(0.15083978371568296), 'Weights': array([0.91010004, 0.08989996]), 'iterations': 5}

Произвольные снятия и пополнения во всех стратегиях

Любая стратегия снятий/пополнений теперь включает параметр time_series_dic, который позволяет задавать любый снятия и пополнения по календарному принципу.

time_series_dic = { "2027-02": 2_000, # пополнение портфеля в феврале 2027 года "2030-03": -4_000 # изъятие денег в марте 2030
}

Бэктестинг распределения

Бэктестинг распределения – значимый этап подготовки к прогнозированию. Для его удобства появились новые инструменты.

Автоматический выбор распределения

В версии 2.0 появился метод kstest_for_all_distributions, который “прогоняет” проверка Колмогорова-Смирнова для всех поддерживаемы распределений и определяет, какое из них подходит лучше.

pf.dcf.mc.kstest_for_all_distributions

Подгонка параметров распределения

Любой параметр распределения теперь может быть задан в ручном режиме. Полностью или отчасти.

Это особенно важно для распределения Стьюдента, которое обычно подходит лучше всего для прогнозирования “толстых хвостов”.

В частности, параметры распределения Стьюдента можно теперь задать следующим образом:

pf.dcf.mc.distribution_parameters = (4.26, None, None) # df, loc, scale

Уровень свободы (df) задается вручную, а остальные параметры – автоматически.

Более того, теперь уровень свободы можно “подогнать” автоматически под прогноз для определенной перцентили:

pf.dcf.mc.optimize_df_for_students(var_level=5) # подгон уровня свободы для 5й перцентили
4.260007759068121

Q-Q Plot

Точность бэктестинга распределения удобно визуализировать на графике Квантиль-Квантиль (Q-Q Plot), где сравниваются исторические данные и сгенерированные.

Для этого в версии 2.0 появился метод plot_qq:

pf.dcf.mc.plot_qq(var_level=5) # 5 – это доверительный уровень для VAR и CVAR
График Квантиль-Квантиль (Q-Q Plot)
График Квантиль-Квантиль (Q-Q Plot)

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

Документы okama

Документы okama стала опрятнее и содержит подробную информацию по всем новшествам и примеры.

Сам раздел примеров на GitHub существенно доработан:

  • 04 investment portfolios with DCF.ipynb — множество новых примеров для стратегий изъятий VanguardDynamicSpending и CutWithdrawalsIfDrawdown

  • 07 efficient frontier multi-period.ipynb — Добавлены примеры для унифицированного класса EfficientFrontier и оптимизации с учетом ребалансировки

  • 10 forecasting.ipynb — обновлены примеры прогнозирования методом Монте-Карло, включая методы подгонки распределений в Монте-Карло

Дальнейшие планы okama

В ближайшее время мы начнем переносить самые важные изменения на okama.io.

В новых версиях okama появится поддержка Pandas 3 и Python 3.14.

Несколько более далекая перспектива – это создание аналога Личного финансового плана (ЛФП). ЛФП будет состоять из последовательности инвестиционных стратегий. В частности, агрессивный портфель для создания пенсионных накоплений и консервативный портфель для расходования средств на пенсии. Конечно, всю последовательность портфелей надо будет прогнать сквозь прогнозирование Монте-Карло. И мы уже придумали, как это сделать.

Источники

1. Форум проекта на русском языке: Новые релизы okama

2. GitHub okama

3. Документы okama

4. Примеры использования в Jupyter Notebook

Читают сейчас

Блогер запустил ПК без ОЗУ ради эксперимента

14 минут назад

Блогер запустил ПК без ОЗУ ради эксперимента

Блогер PortalRunner решил провести эксперимент — запустить компьютер без оперативной памяти. Он отмечает, что пошёл на такой шаг в условиях дефицита ОЗУ и роста цен на модули. Ознакомиться далее

OpenAI купила TBPN — популярное техношоу о бизнесе и ИИ

23 минуты назад

OpenAI купила TBPN — популярное техношоу о бизнесе и ИИ

OpenAI приобрела TBPN (Technology Business Programming Network) — популярное ежедневное техношоу, которое ведут бывшие основатели стартапов Джон Куган и Джорди Хейс. Это первая заметная покупка OpenAI

«Исходник Дурова»: пользователи из России теперь могут сменить регион App Store без отмены всех подписок

35 минут назад

«Исходник Дурова»: пользователи из России теперь могут сменить регион App Store без отмены всех подписок

Книга «Код Дурова» выяснило, что Apple упростила смену региона в App Store для пользователей из России. Теперь это можно сделать без отмены всех активных подписок. В дополнение к этого, в настройках м

В российских кафе и ресторанах начнут внедрять ИИ-кассиров

36 минут назад

В российских кафе и ресторанах начнут внедрять ИИ-кассиров

Организация inno clouds, резидент «Сколково», представила ИИ-кассира для заведений общепита. В соответствии с заявлению разработчика, система умеет вести диалог с посетителем, помогать с выбором блюд

VK назначила нового технического директора

43 минуты назад

VK назначила нового технического директора

Сергей Ляджин на позиции СТО будет отвечать за масштабирование ключевых технологических решений VK. В новой роли он объединит команды разработки в нескольких направлениях, в том числе социальные платф