Новые релизы okama

Сегодня вышел довольно большой релиз okama (версия 0.90).
Новости в основном касаются методов работы с прогнозированием и тестирование распределений.

Теперь легко можно строить подобные прогнозы для инвестиционных портфелей:

Или с использования метода Монте-Карло (генерация случайных кривых накопленной доходности:

Сравнивать историческое распределение доходности с нормальным или логнормальным:

Подробности

Появилась возможности прогнозирования с использованием:

  • Нормального распределения
  • Логнормального распределения
  • Исторических данных

Новые методы визуализации (класс Portfolio):

  • plot_forecast
  • plot_forecast_monte_carlo
  • plot_plot_hist_fit
  • plot_percentiles_fit

Новые методы прогнозирования (класс Portfolio):

  • percentile_inverse
  • percentile_from_history
  • forecast_wealth_history
  • forecast_monte_carlo_cagr
  • forecast_wealth

Кроме того, для классов AssetList и Portfolio доступны тесты, которые помогут разобраться, подходит ли нормальное или логнормальное распределение для прогнозов:

Как обычно, примеры применения новых методов в jupyter notebooks.

Для установки новой версии okama:
pip install okama==0.90

Вышла версия 0.91 библиотеки с небольшими обновлениями.

1. Метод Монте-Карло для границы эффективности

Появился новый метод .get_monte_carlo для класса EfficientFrontier. Теперь можно генерировать с использование Монте-Карло случайные портфели для визуализации точек внутри границы эффективности.


Примеры использования нового метода в ноутбуке 03 efficient frontier.ipynb.

2. Точный расчет CAGR для границы эффективности

Для расчета точек на границе эффективности доступен атрибут kind='cagr', который позволяет получить точную величину среднегодовой доходности (для каждой точки).
Используемый ранее атрибут kind='cagr_app' для расчета приближенного значения среднегодовой доходности больше не используется.

1 лайк

Вышла версия 0.91 okama.
Основные изменения - это рефакторинг и исправление багов:

  • параметр валюты curr переименован в ccy
  • исправлены ошибки в методах dividend_yield (AssetList) и describe (Portfolio)

Кроме того:

  • добавлен ноутбук с примерами использования методов класса EfficientFrontierReb для портфелей с различными периодами ребалансировки ( 04 efficient frontier multi-period.ipynb )
  • в ноутбуке 01 howto.ipynb добавлены примеры вычисления корреляционных матриц для списка активов.
1 лайк

Версия 0.93 okama

  • Появилась возможность запросить список всех символов (тикеров) из определенного namespace при помощи symbols_in_namespace(). Например, для получения всех доступных индексов: symbols_in_namespace(INDX). Все тикеры Мосбиржи: symbols_in_namespace(MOEX).
  • В базу данных добавлены официальные курсы ЦБ России: USD, EUR, GBP, CNY, а также курсы валют стран СНГ: UAH, KZT, BYN. Курсы валюты доступны для всех дней (даже когда нет торгов). namespace для курсов валют центробанков: CBR.
    Список доступных сейчас валют можно посмотреть с помощью symbols_in_namespace(CBR)
1 лайк

Версия 0.95
Отдельные улучшения для класса Portfolio.

  • атрибут .cagr заменен на метод .get_cagr() по аналогии с AssetAllocation
  • в .description теперь включена дивидендная доходность портфеля во всех валютах активов.

Исправления:

  • исправлено __repr__ для EfficientFrontier
  • все импорты внутри библиотеки являются относительными

Версия 0.98
Новые методы для класса Portfolio

  • get_cumulative_return - расчет накопленной доходности портфеля
  • get_rolling_cumulative_return - расчет накопленной скользящей доходности портфеля

'YTD' - больше не является аргументом для get_cagr. По смыслу доход с начал года (YTD) - это не CAGR (среднегодовая доходность), а накопленная (за несколько месяцев) доходность. Поэтому аргумент ‘YTD’ перенесен в get_cumulative_return.

В репозитории библиотеки появилась ветка предрелиза dev.
Установить предрелизную версию можно через:

pip install git+https://github.com/mbk-dev/okama@dev

На сегодняшний день в предрелизной версии доступны улучшения нескольких методов AssetList и Portfolio для расчета реальной доходности:

  • get_cagr(real=True)
  • get_rolling_cagr(real=True)
  • get_cumulative_return(real=True)
  • get_rolling_cumulative_return(real=True)

Внимание: предрелизная версия может быть нестабильной

1 лайк

Версия 0.99
Улучшения для классов Portfolio и AssetList:

  • Portfolio.get_return_ts() имеет аргумент rebalancing_period
  • Portfolio.get_rebalanced_portfolio_return_ts упразднен и больше не используется
  • get_rolling_cagr, get_rolling_cumulative_return, get_cagr и cumulative_return методы в классах AssetList и Portfolio используют аргумент real=True для расчета реальной доходности

Добавлены строки документации в классах Portfolio and AssetLists.

Добавлена Дорожная карта развития и инструкция Contributing Guidelines для желающих участвовать в проекте.

Версия 1.0.0
Версия 1.0.0 доступна для установки через pip.

Ключевые изменения

  • Портфель теперь - это тип актива (такой же как акции, ETF, комодитиз и др.). Портфели можно добавлять в AssetList. Это позволяет, например, создавать портфели и сравнивать их между собой или с бенчмарками…
  • У портфеля теперь есть тикер (так же как у любого другого актива). Для портфелей зарезервировано расширение .PF. Тикер присваивается портфелю автоматически, но может быть изменен при помощи .symbol
  • Период ребалансировки (rebalancing_period) теперь является атрибутом портфеля. Он указывается при инициализации, по умолчанию равен одному месяцу. Доступны следующие периоды ребалансировки: год (year), месяц (month), без ребалансировки (none)
  • Asset получил методы .close и .adj_close. Теперь история цен закрытия доступна непосредственно из класса
  • Значения исторических данных по дивидендам приводятся к базовой валюте в классах AssetList и Portfolio
  • Дивидендная доходность портфеля .dividend_yield считается как взвешенная сумма дивидендных доходностей активов, в него входящих.
  • Портфель получил метод .dividends. Как в других активах, этот метод показывает историю дивидендов

Jupyter Notebook с примерами для инвестиционных портфелей

В классе Portfolio произошло много изменений. Поэтому для портфелей создан отдельный файл с примерами.
Все другие примеры применения библиотеки находятся в папке examples.

Изменения в системе абстракций

Новый абстрактный класс ListMaker является родительским для AssetList и Portfolio.

После изменений в версии 1.0.0 в шапке всех блокнотов с примерами находится ссылка, которая позволяет запустить блокнот в Google Colab. Это позволяет запускать Jupyter Notebook без локальной установки библиотеки.

Например, 01 howto.ipynb можно запустить в Google Colab по ссылке:

Версия 1.0.2
Версия 1.0.2 доступна для установки через pip.

ВНИМАНИЕ: В этом релизе исправлены некоторые неприятные ошибки. Рекомендую всем обновиться до последней версии!

pip install --upgrade okama

Улучшение работы поиска в базе данных: .search и .symbols_in_namespace

  • ok.search() принимает namespace в качестве параметра (по умолчанию None).
  • ok.search() и ok.symbols_in_namespace() по умолчанию возвращают результаты в DataFrame. Тип выдачи можно изменить с помощью параметра response_format (может быть ‘frame’ или ‘json’)

Исправление ошибок

  • длина временного ряда .inflation_ts ограничена значениями ‘first_date’ и ‘last_date’. Актуально для Portfolio и AssetList. Ошибка в некоторых случаях приводила к некорректным результатам расчета реальной доходности.
  • np.nan и np.inf заменены на 0 в расчетах среднегодового роста дивидендной доходности AssetList.get_dividend_mean_grow()

Пример работы нового поиска

Для поиска по тикерам конкретной биржи (или любого другого namespace) задаем параметр namespace=. Например для поиска всех ETF компании FinEx на Московской бирже:

Тоже самое для Лондонской биржи (LSE):

Версия 1.1.0
Версия 1.1.0 доступна для установки через pip.

Коэффициент Шарпа, Tangency Portfolio и Линия рынка капитала (CML)

  • get_sharpe_ratio позволяет рассчитать Коэффициент Шарпа в Portfolio и AssetList (для всех активов, включенных в список)
  • .get_tangency_portfolio позволяет оптимизировать портфели по Коэффициенту Шарпа. Портфель с максимальным Коэффициентом Шарпа называется Tangency Portfolio. Пока новый метод работает только в классе EfficientFrontier
  • .plot_cml() рисует Линию рынка капитала (Capital Market Line) и Tangency Portfolio вместе с Границей эффективности (EfficientFrontier класс)

Изменения в классах:
Соблюдая принцип “Бритвы Оккамы”, мы избавились от лишнего класса Plots. Теперь “графические методы”, облегчающие жизнь, при рисовании сложных объектов, доступны прямо из традиционных классов (AssetList, Portfolio и т.д.).

  • метод .plot_assets перемещен в родительский абстрактный класс ListMaker и теперь доступен во всех дочерних классах: AsstList, Portfolio, EfficientFrontier и EfficientFrontierReb
  • методы .plot_pair_ef и .plot__transition_map доступны из EfficientFrontier

Пример отображения Линии рынка капитала (CML)

image
image
На графике точка MSR - Maximum Sharpe Ratio, он же Tangency Portfolio.
Веса и другие характеристики точки MSR доступны через .get_tangency_portfolio:
image

Документация по новым методам доступна на ReadTheDocs

Сергей, добрый день! При расчёте коэффициента Шарпа что Вы рекомендуете принимать за безрисковый актив в базовой валюте (рубли, доллары США, Евро)?

1 лайк

Извиняюсь, что пропустил вопрос.
Размер безрисковой ставки зависит от инвестора. Если это частный инвестор, то можно брать размер ставки в банке или на госбонды (ОФЗ или трежуриз). Если это институциональный инвестор, то берут например ставку LIBOR или КС.

Версия 1.1.1
Ноябрьский релиз с небольшими дополнениями и исправлениями доступен через pip.

Ежегодное отклонение от индекса

Новый метод .tracking_difference_annual для AssetList позволяет рассчитать историю отклонения от бенчмарка по календарным годам. Метод может быть полезен для проверки стабильности качества управления фондом. Например, это график ежегодных отклонения двух популярных фондов на S&P500: VOO (Vanguard, NYSE) и SPXS (Invesco UCITS, LSE).
okama-AssetList-tracking_difference_annual-1

Подробное описание нового метода и примеры использования доступны в Документации.

Исправление ошибок

Перед инициализацией классы AssetList, Portfolio, EfficientFrontier проверяют активы на достаточность исторического периода данных. Теперь в список активов можно включить только тикеры, имеющие как минимум 3 месяца истории. В противном случае - ValueError.

Версия 1.1.2
Релиз посвящен работе с популярными финансовыми коэффициентами. Обновление доступно через pip.

Коэффициент Сортино

  • метод get_sortiono_ratio() доступен в классах AssetList и Portfolio

Коэффициент Сортино является аналогом Коэффициента Шарпа. Разница в том, что в знаменателе учитывается не волатильность а полуотклонение (среднеквадратичное отклонение ниже целевой доходности, downside deviation):

S = \frac{R_p-R_t}{DR}

R_p - матожидание доходности портфеля (среднее арифметическое доходности)
R_t - целевая доходность портфеля
DR - полутоклонение доходности

Пример сравнения Коэффициента Сортино для различных активов:

al = ok.AssetList(['VOO.US', 'BND.US'], last_date='2021-12')
al.get_sortino_ratio(t_return=0.03)  # целевая доходность равна 3%
VOO.US    1.321951
BND.US    0.028969

Коэффициент Сортино для инвестиционного портфеля:

pf = ok.Portfolio(['VOO.US', 'BND.US'], last_date='2021-12')
pf.get_sortino_ratio(t_return=0.02)
1.4377728903230174

Коэффициент диверсификации

Коэффициент диверсификации показывает на сколько эффективно применяется корреляция для снижения риска в портфеле. В отличие от коэффициентов Шарпа и Сортино в формуле не используется доходность. Речь идет только о снижении риска:

DR(w) = \frac{\sum_{i=1}^{N} w_i \times \sigma_i}{\sigma}

w_i - вес ценной бумаги в портфеле
\sigma_i - риск (среднеквадратическое отклонение) доходности ценной бумаги
\sigma - риск инвестиционного портфеля

Из формулы хорошо видно, что коэффициент диверсификации (КД) всегда больше единицы. Взвешенная сумма рисков активов всегда больше или равна риску портфеля.
Чем больше КД, тем выше снижен риск за счет низкой корреляции.

  • атрибут diversification_ratio доступен для Portfolio
  • оптимизации по КД возможна в классе EfficientFrontier через метод get_most_diversified_portfolio(). Метод позволяет получить как глобальный оптимизированный портфель, где КД достигает максимальной величины, так и локально оптимизированный портфель для заданной доходности портфеля.
  • множество оптимизированных по КД портфелей доступно через атрибут mdp_points в EfficientFrontier. Оптимизация происходит последовательно для промеж

Преимущество оптимизированных по КД портфелей заключается в том, что в отличие от Границы эффективности в них нет “вырожденных” весов. Поэтому для конструирования реальных инвестиционных портфелей распределение по КД - это хорошая подсказка.

ВНИМАНИЕ: использовать в явном виде эти веса нельзя, так же как и веса портфелей на Границе эффективности.

Пример построения кривой максимально диверсифицированных портфелей и Границы эффективности. В примере использованы портфели, составленные из:

  • Индекс S&P500 полной доходности (SP500TR.INDEX)
  • Индекс Мосбиржи полной доходности (MCFTR.INDEX)
  • Индекс облигаций федерального займа Мосбиржи (RGBITR.INDX)
  • Спотовые цены на золото (GC.COMM)
ls4 = ['SP500TR.INDX', 'MCFTR.INDX', 'RGBITR.INDX', 'GC.COMM']
y = ok.EfficientFrontier(assets=ls4, ccy='RUB', n_points=100)  
# n_points=100 задает количество точек на Границе эффективности и на кривой 
# максимально диверсифицированных портфелей

mdp = y.get_most_diversified_portfolio()   # Глобальный максимально диверсифицированный портфель
mdp
{'SP500TR.INDX': 0.18734372897034768,
 'MCFTR.INDX': 0.023902608406034215,
 'RGBITR.INDX': 0.6595979466663215,
 'GC.COMM': 0.12915571595729658,
 'Mean return': 0.12279521203933563,
 'CAGR': 0.12124953230039481,
 'Risk': 0.059120398386235534,
 'Diversification ratio': 1.9671253973462728}

df = y.mdp_points  # множество локально оптимизированных по КД портфелей (100 шт)
ef = y.ef_points  # портфели на Границе эффективности (100 шт)

Строим графики Границы эффективности, Кривой максимально диверсифицированных портфелей, отображаем точку, где КД максимален:

fig = plt.figure()
# Отображение точек риск-доходность для каждой ценной бумаги
y.plot_assets(kind='cagr')  # kind should be set to "cagr" as we take "CAGR" column from the ef_points.
ax = plt.gca()
# Отображение Границы эффективности
ax.plot(ef['Risk'], ef['CAGR'], label='Efficient Frontier')  # на оси Y мы отображаем среднегодовую доходность (CAGR)
# Отображение кривой с максимально диверсифицированными портфелями
ax.plot(df['Risk'], df['CAGR'], linestyle='dashed', label='Most diversified portfolios')
# Отображение точки с максимальным КД (глобальный максимум). Обозначен как MDP
ax.scatter(mdp['Risk'], mdp['CAGR'], s=30, marker='o', label='MDP')
# Название графика и надписи осей
ax.set_title('Efficient Frontier vs Most diversified portfolios frontier')
ax.set_xlabel('Risk (Standard Deviation)')
ax.set_ylabel('Return (CAGR)')
ax.legend();

Версия 1.1.3
Небольшой релиз, связанный с переходом на poetry для управления зависимостями библиотеки (до этого зависимости управлялись с помощью requirements.txt).

Кроме того, исправлен неприятный баг, приводивший к некорректному определению границ доступного исторического периода для Portfolio, AssetList и зависимых классов.

Обновление доступно через pip.

Версия 1.1.5
Релиз связан с переходом на новый API финансовой базы данных.
Новый сервер расположен по адресу api.okama.io:5000.

Рекомендую обновиться до новой версии. API по старому адресу будет поддерживаться еще примерно месяц. Уже сейчас по старому адресу не доступны новые типы данных (например расширенная база курсов валют ЦБ .CBR)

Пример запроса на новом API:
http://api.okama.io:5000/api/namespaces/

Версия 1.1.6
Параллельные вычисления теперь используются в “тяжелых” расчетах, связанных с оптимизацией портфеля с произвольной ребалансировкой портфеля (расчет Границы эффективности). Спасибо за помощь @alex

Для параллельных вычислений используется библиотека Joblib. Прирост скорости составил примерно 20%, но будет гораздо выше, когда сможем перейти на Pandas версии 1.4 и выше. Пока для совместимости с Python 3.7 используется Pandas версии 1.1.5. Версия Python 3.7 будет поддерживаться еще какое-то время до тех пор пока Google Colab не перейдет но более новую версию.

Другие изменения:

  • библиотека black используется для автоформатирования стиля кода
  • в зависимостях в версии для разработчика по умолчанию используется Python 3.7. При текущих зависимостях okama работает с версиями 3.7, 3.8 и 3.9

Версия 1.2.0

Новый класс для макроэкономических параметров Indicator

Теперь 3 макро-класса доступны (и отображены в Документации):

  • Indicator : Макроэкономические индикаторы. (.RATIO новый namespace)
  • Inflation : Инфляция и свойственные для нее методы (.INFL namespace)
  • Rates : Ставки банков и Центробанков (.RATE namesapce)

Циклический P/E Шиллера (CAPE10) для 20+ стран добавлен в базу данных. Новые тикеры: USA_CAPE10.RATIO, CHN_CAPE10.RATIO, CHN_CAPE10.RATIO и т.д.

Дневные данные в Макроэкономических классах

Rate класс теперь имеет .values_daily атрибут (по аналоги с Asset().daily_close):
ok.Rate("RUONIA.RATE").values_daily

Все макроэкономические классы имеют .values_monthly атрибут.

.describe() метод для все макро-классов

.describe() показывает статистику с начала года и для выбранного списка временных промежутков:

  • среднее (арфметическое)
  • медиана
  • макс. и мин. значения с датами

.describe() в классе Inflation отличается. Он показывает характерные для инфляции статистические величины:

  • Инфляция с начала года (YTD)
  • Среднегодовая инфляция (среднее геометрическое) для выбранных периодов и за весь срок
  • Максимальная 12-месячная инфляция для выбранных периодов и за весь срок
  • Покупательная способность для 1000 денежных единиц (для выбранных периодов и за весь срок)

Скользящие отклонения от индекса для ETF

.tracking_difference() и tracking_difference_annualized() теперь являются методами (были атрибутами). У них появился необязательный параметр rolling_window который задает размер окна для скользящего отклонения в месяцах.
Например, для расчета скользящего 24-месячного отклонения:
x.tracking_difference(rolling_window=24)