Программ для анализа и управления портфелями опционов много. Они есть в торговых терминалах, в виде отдельных коммерческих продуктов или сервисов на сайтах. У таких программ есть ряд ограничений: портфели привязаны к торговой платформе, котировки подкачиваются из определённого источника, а рассчитать параметры или сценарии можно только предусмотренные ПО.
Задачу управления портфелями на разных рынках я решил с помощью R. Движок с открытым кодом даёт много возможностей: портфели хранятся в любой СУБД или Excel, или загружаются из терминала (QUIK, TWS, любого другого с API); котировки подкачиваются из своего источника (терминал, база данных или сайт) и доступна любая аналитика по портфелю!
Общее описание
Рыночные данные и портфель загружаются в объекты класса OptPort
и OptMarket
. Портфель переоценивается по рынку, на основе этих данных рассчитываются текущая прибыль и "греки", а также его профиль. Профиль портфеля (зависимость прибыли или "греков" от цены базисного актива) рассчитывается и хранится в объекте класса OptProfile
. Встроенные функции рисуют график профиля и позволяют сравнивать профили нескольких портфелей.
По ссылке (1) в конце статьи — вариант управления портфелем опционов Мосбиржи с подключением к QUIK и Access.
Рыночные котировки OptMarket
Объект класса OptMarket
нужен для хранения биржевых котировок опционов, информации о базисном активе, текущей дате.
Без рыночных цен портфель переоценивается по внутренней стоимости.
# Загружаем биржевые котировки (доску опционов) из Access
brd = GetBoard_fortsdb(ul)
# Создаём объект класса OptMarket
mrkt = OptMarket(ul = 'SiZ9', # тикер базисного актива
ul_price = brd$ul_price, # цена базисного актива
board = as.tbl(brd$board), # доска опционов
now = as.Date('2019-11-12')) # текущая дата
Портфель OptPort
Портфель может состоять из опционов и базисного актива. Конструктор
создаёт портфель на основе таблицы сделок по заданному базовому
активу. Сделки суммируются в общую позицию.
# Загружаем сделки из Access (в базу сделки импортированы из терминала QUIK)
trades = GetTrades_fortsdb()
# Т.к. в сделках указан только тикер, забираем параметры опционов из доски опционов
trades = TickerToParams_fortsboard(trades, mrkt$board)
На основании сделок создаём объект класса OptPort
:
port = OptPort(ul = 'SiZ9',
trades = trades,
name = 'Spread')
Анализ портфеля
Оценка портфеля
Функция PortPricing
переоценивает портфель по текущим ценам — выбирает цены опционов из OptMarket
и добавляет их в портфель OptPort
. Для опционов МосБиржи самое простое — переоценить их по теоретической цене, которую транслирует сама биржа и известна всегда (price_at = 'theor'
).
port = PortPricing(port, mrkt, price_at = 'theor')
Прибыль и “греки”
Функция PortValuation
рассчитывает параметры портфеля — нереализованную прибыль и "греков". Результаты сохраняются в поле total_value
объекта OptPort
.
port = PortValuation(port)
port$total_value
Профиль портфеля — OptProfile
Объект OptProfile
хранит профиль портфеля на интервале цен базисного актива.
Функция PlotProfile
строит график профиля на базе ggplot2
.
myprofile = OptProfile(optport = port,
params = c('pl', 'delta', 'theta', 'vega'),
ul_range = 0.05 # процентное отклонение от максимального и минимального страйков портфеля
)
PlotProfile(myprofile)
Изменение состава портфеля
Для изменения состава портфеля есть функция AddTrades
. Она добавляет сделку в портфель и рассчитывает новую позицию портфеля.
# Непосредственно сделка - продажа одного опциона из портфеля
newtrade = data.frame(ul='SiZ9', ticker='Si63500BX9', xtype='p', strike=63500,
expdate=as.Date('2019-12-19'), tradeprice=500, q=-1 )
# Портфель после изменений
port2 = AddTrades(port = port,
trades = newtrade)
port2$name = 'Changed'
Профиль нового портфеля можно сравнить со старым. Функция JoinProfiles
объединяет данные профилей для построения общего графика.
# Пересчитываем оценку и параметры нового портфеля
port2 = port2 %>% PortPricing(., mrkt, price_at = 'theor') %>% PortValuation(.)
# Профиль нового портфеля
myprofile2 = OptProfile(optport = port2, params = c('pl', 'delta','theta', 'vega'), ul_range = 0.05)
# Объединяем профили
profiles = JoinProfiles(list(myprofile, myprofile2))
PlotProfile(profiles)
Итого
Базовые функции решают базовые задачи. Мой решение было разработано для конкретной цели — анализ множества портфелей и моделирование изменений в эти портфели. Исходный код вы найдёте по ссылке ниже. Бонус — база для импорта данных из QUIK и настройки самого QUIK для экспорта.
Ссылки:
(1) Исходный код на GitHub.
Автор: andreal