У меня, как у пользователя Тинькофф Инвестиций, часто возникали вопросы: какие акции за весь период торговли принесли мне наибольший доход; сколько всего я заплатил за обслуживание тарифа и прочие комиссии; какие акции в портфеле давно лежат и не приносят мне доход; как отсортировать акции в своем портфеле по какому-либо критерию.
Текущая аналитика брокера показывает только открытые позиции, а профиль в "пульсе" подсчитывает лишь общий процент, без конкретики. Это не дает возможность увидеть «настоящую» картину своего портфеля.
К примеру, покупаем 1 акцию по 1000, после падения до 900 усредняем еще одной акцией. Затем при отскоке до 950 продаем 1 акцию. В итоге оставшаяся акция в портфеле "горит зеленым" (образуется плюс +50 по правилу fifo), хотя фактический результат бумаги на данный момент будет 0 (без учета комиссий). Такое отображение бумаг в приложении может сбить с толку, и привести к неправильным решениям и большим потерям, при совершении множества сделок.
Идея вести дневник сделок в excel, или периодически копаться в налоговом/брокерском отчете, мне не понравилась. Зато приглянулась мысль - обрабатывать данные полученные из официального API.
Результатом стал онлайн-инструмент, в который легко загрузить историю операций. После чего она отображается в табличном виде, с которыми удобно работать.
В статье я продемонстрирую, как пользоваться созданным инструментом, и какие задачи решаются. Подсвечу некоторые особенности данных полученных из API.
![Web-интерфейс Web-интерфейс](https://habrastorage.org/getpro/habr/upload_files/975/604/d7f/975604d7f3f6e4db185ac63af546a69a.png)
Об инструменте, немного лирики
Мои первые шаги по анализу истории были сделаны года два назад. Результатом были таблицы, которые помогали мне закрыть любые вопросы:
![Скрин статистики 2020 года Скрин статистики 2020 года](https://habrastorage.org/getpro/habr/upload_files/e8a/633/ef6/e8a633ef6275cd6393c30abe110ba122.png)
Я даже периодически делал разного роды выгрузки друзьям и знакомым. Передавать VM/doсker образ со скриптами людям без навыков в IT было сложно, поэтому делалось все мною вручную. Зародилась мысль автоматизировать и вывести процесс в онлайн.
По акции от AWS достался бесплатный сервер на год, куда я перенес базу и продолжил изучение python, придумывая себе различные задачи, позволяющие автоматизировать торговлю.
Позже к разработке подключился друг. И вот мы больше года держим сервер, где крутятся наши наработки на python (Telegram-боты, скринеры и прочее). К примеру, боты уведомляют о различных событиях по акциям наших портфелей.
Разработка велась нерегулярно, в свободное время. Различных скриптов со временем стало много, для этого мы создали единый модуль с веб-интерфейсом для управления всеми наработками, заодно изучили React. Начали с отображения табличных данных.
Результатом полуторамесячной работы по выходным стал сайт https://tstocks.ru/, который использует:
Front: ReactJS (Nginx)
Backend: Python Flask
СУБД: Postgres
Немного внутренностей
Все запросы и параметры хранятся в БД. Получился достаточно удобный конструктор таблиц и прочих методов
![Управление таблицами в БД Управление таблицами в БД](https://habrastorage.org/getpro/habr/upload_files/073/80c/cbf/07380ccbf8dcc9e5b199b94e71c5c763.png)
![Меню Меню](https://habrastorage.org/getpro/habr/upload_files/72d/835/6af/72d8356afeeba26c66ecca3f7d9ffa57.png)
Сайт должен работать во всех современных браузерах. Публично пока доступен лишь анализ истории.
Ближе к делу, как загрузить данные для анализа
Для анализа требуется история сделок, которую можно забрать в формате json из API Тинькофф. Пример для curl, а ниже будут команды и для Windows.
Следует ознакомиться с правилами использования OpenApi Тинькофф. Никому не передавайте токен и не оставляйте его в истории команд, т.к. с помощью него можно совершать операции. Если вы считаете, что токен мог быть скомпрометирован, то отзовите его на странице банка https://id.tinkoff.ru/account
Если вы ранее не работали с консолью, и у вас вопросы по использованию команд, то лучше спросите в ЛС/комментариях перед использованием.
curl -X GET "https://api-invest.tinkoff.ru/openapi/operations?from=2015-01-01T00%3A00%3A00%2B03%3A00&to=2025-01-01T00%3A00%3A00%2B03%3A00" -H "accept: application/json" -H "Authorization: Bearer t.TOKEN" > _my_invest_operations.json
Параметры запроса CURL
Можно изменить параметры запроса в url к api-invest.tinkoff.ru/openapi/operations:
from=2015-01-01 - период выгрузки ОТ
to=2025-01-01 - период выгрузки ДО* лучше указывать максимальный период, для консистентности данных
&figi=******* - необязательный параметр, выгрузка операций по конкретному FIGI
&brokerAccountId=****** - необязательный параметр, указываем конкретный брокерский счет, если у вас их несколько
brokerAccountId можно получить командой:
curl -X 'GET' \
'https://api-invest.tinkoff.ru/openapi/user/accounts' \
-H 'accept: application/json' \
-H 'Authorization: Bearer t.TOKEN' # -- УКАЗЫВАЕМ СВОЙ ТОКЕН
Json не содержит API токен и прочую личную информацию. Исключить передачу токена было главной целью.
Пример json
Некоторые операции имеют вложенный элемент "trades"
{
"trackingId": "9e46ad76c68c9a37",
"payload": {
"operations": [
{
"operationType": "Dividend",
"date": "2021-12-13T06:00:00+03:00",
"isMarginCall": false,
"instrumentType": "Stock",
"figi": "BBG000BR2B91",
"payment": 1.37,
"currency": "USD",
"status": "Done",
"id": "2825259975"
},
{
"operationType": "BrokerCommission",
"date": "2021-12-10T19:18:32.273+03:00",
"isMarginCall": false,
"instrumentType": "Stock",
"figi": "BBG006L8G4H1",
"quantity": 0,
"quantityExecuted": 0,
"payment": -5.63,
"currency": "RUB",
"status": "Done",
"id": "2826624962"
},
{
"operationType": "Buy",
"date": "2021-12-10T19:18:31.273+03:00",
"isMarginCall": false,
"instrumentType": "Stock",
"figi": "BBG006L8G4H1",
"quantity": 3,
"quantityExecuted": 3,
"price": 4690.8,
"payment": -14072.4,
"currency": "RUB",
"commission": {
"currency": "RUB",
"value": -5.63
},
"trades": [
{
"tradeId": "498456613",
"date": "2021-12-10T19:42:09.441+03:00",
"quantity": 3,
"price": 4690.8
}
],
"status": "Done",
"id": "29072082626"
}
]
},
"status": "Ok"
}
Далее эти данные загружаются на сервер, в json ответе возвращается sha1 hash ваших операций (именуемый id).
Получение и импорт сделок можно поместить в одну команду:
#Загружаем операции одной командой через pipeline, не забыв указать токен в первом curl
curl -X GET "https://api-invest.tinkoff.ru/openapi/operations?from=2015-01-01T00%3A00%3A00%2B03%3A00&to=2025-01-01T00%3A00%3A00%2B03%3A00" -H "accept: application/json" -H "Authorization: Bearer t.TOKEN" | curl -H "Content-Type: application/json" -X POST --data-binary @- https://tstocks.ru/api/operations/upload
![](https://habrastorage.org/getpro/habr/upload_files/eae/56b/8c4/eae56b8c4a9aacb8cacb7884abb00ce2.png)
повторный импорт
При повторном импорте, если данные по сделкам не изменились, то будет выдан тот же id, а загрузка пропущена.
![](https://habrastorage.org/getpro/habr/upload_files/35f/35f/515/35f35f515ccf1b484073331d31b1a655.png)
*Nginx имеет небольшие лимиты на повторный импорт
Пример для Windows:
Windows PowerShell
Сохраняем историю сделок в файл
Дополнительные параметры
Можно изменить параметры запроса в url к api-invest.tinkoff.ru/openapi/operations:
from=2015-01-01 - период выгрузки ОТ
to=2025-01-01 - период выгрузки ДО* лучше указывать максимальный период, для консистентности данных
&figi=******* - необязательный параметр, выгрузка операций по конкретному FIGI
&brokerAccountId=****** - необязательный параметр, указываем конкретный брокерский счет, если у вас их несколько
brokerAccountId можно получить командой:
(Invoke-WebRequest -Uri "https://api-invest.tinkoff.ru/openapi/user/accounts" -Headers @{ "method" = "GET" "accept"="application/json" "authorization"="Bearer t.TOKEN" # -- УКАЗЫВАЕМ СВОЙ ТОКЕН }).Content
(Invoke-WebRequest -Uri "https://api-invest.tinkoff.ru/openapi/operations?from=2015-01-01T00%3A00%3A00%2B03%3A00&to=2025-01-01T00%3A00%3A00%2B03%3A00" -Headers @{
"method" = "GET"
"accept"="application/json"
"authorization"="Bearer t.TOKEN" # -- УКАЗЫВАЕМ СВОЙ ТОКЕН
}
).Content > _my_invest_operations.json # название файла в который сохранятся операции
Отправляем файл на сервер
Invoke-RestMethod -ContentType 'application/json' -uri https://tstocks.ru/api/operations/upload -method POST -InFile _my_invest_operations.json
Как пользоваться
После загрузки операций и получения id, вставляем его на сайт. Не путайте с токеном TinkoffApi. Имеется демонстрационный id, для тех, кому интересно посмотреть функционал, не загружая свои сделки.
Disclaimer
На сайте нет авторизации в привычном виде, т.к. цель максимально упростить процесс, избежать регистраций и сбора личной информации.
Id это sha1 хэш, который достаточно уникальный и длинный для перебора. Просмотреть сделки сможет любой, кто знает id, что может быть удобно для передачи его другу-инвестору.
Имеется кнопка удаления данных по id, а также в планах ввести время жизни загруженного портфеля.
Если у вас есть сомнения по поводу описываемых операций, уточните подробности у нас, если есть идеи как сделать лучше - сообщите.
![](https://habrastorage.org/getpro/habr/upload_files/98f/250/238/98f2502387ce9740e003ce7323a22a36.png)
При нажатии на кнопки открываются соответствующие таблицы, я покажу несколько кейсов их использования, чтобы было понятно, как с ними работать. Постараюсь воздержаться от комментариев самих сделок и результата.
Статистика по инструментам
Таблица отображает данные сгруппированные по FIGI. В наименованиях столбцов кратко описан смысл, по ходу статьи дополнительно уточню значения некоторых столбцов.
а) Смотрим доходность торговли по конкретной бумаге
Почти два года назад я наивно игрался с "шортами Tesla", и мне было интересно сколько дохода это приносит. С этого кейса родилась идея извлекать данные из API.
Итог сделок плачевный, хотя начиналось все неплохо. Опыт, сын ошибок трудных..
![](https://habrastorage.org/getpro/habr/upload_files/99e/c20/14e/99ec2014e50e35a59a6b5782421652ad.png)
Поясню значения столбцов:
Фикс разница - зафиксированный доход/убыток. Купоны/дивиденды/комиссии не включены, они отображаются в отдельных одноименных столбцах
Немного боли с расчетом
Оказывается, что это не так легко посчитать, если на руках не 0 бумаг.
Бумаги покупаются и продаются частями в разное время, требуется раскрывать и упорядочивать сделки, соблюдая правило FIFO, еще у некоторых акций огромные лоты (*в TGKB миллион шт.)
Все расчеты ведутся в БД, т.ч. пришлось повозиться с оптимизацией sql запросов и функций, чтобы это работало очень быстро. Для оптимизации использовал https://explain.dalibo.com/
Доход текущий - это примерно то, что мы видим в приложении по текущим позициям, купоны/дивиденды/комиссии не включены
Доход - это сумма двух предыдущих столбцов, купоны/дивиденды/комиссии не включены
Общий доход - это предыдущий столбец + налоги(див/купон)/купоны/дивиденды/комиссии
Figi содержит ссылку, по которой открывается вся история по бумаге:
![Пример истории по FIGI Пример истории по FIGI](https://habrastorage.org/getpro/habr/upload_files/a6f/c23/41f/a6fc2341f5206f8450fca3f25fd301fb.png)
*для демонстрационного портфеля некоторые подробности недоступны
**комиссия за маржинальную торговлю не привязана к конкретному figi, ее можно посмотреть на вкладке "Прочие платежи"
б) Смотрим то, что не видно в приложении при фиксации убытков, или активной торговле
Скоро конец года, и для снижения налога на доход я зафиксировал убыток по FEES, и снова выкупил акции. Открыв приложение брокера, я даже увижу прибыль (столбец "Доход текущий"). А если так зафиксировать все убытки, то можно увидеть "зеленый" портфель в приложении.
![](https://habrastorage.org/getpro/habr/upload_files/8e5/fc6/8e3/8e5fc68e3162f5cb341e16070ad059c9.png)
Однако, мне интересно видеть и не забывать про реальный итог торговли по тикеру.
в) Ищем бумаги, которые принесли наибольшую прибыль за все время
Столбцы таблицы поддерживают фильтрацию, сортировку и группировку по нескольким столбцам. Сортировка осуществляется кликом по нескольким столбцам через SHIFT, группировка осуществляется через меню-ПКМ в требуемой последовательности. При группировке некоторые числовые столбцы показывают итог с суммой, минимальным и максимальным значением
Группируем или фильтруем по валюте и сортируем по "Общему доходу"
![](https://habrastorage.org/getpro/habr/upload_files/a31/b12/412/a31b12412b0d80cb7f2e09b977c8369f.png)
Наиболее прибыльной стратегией для меня было - купить несколько голубых фишек, и забыть про них:)
г) Считаем дивиденды
Некоторые компании торгуются в рублях, но платят дивиденды в валюте (например "Полиметалл"). Поэтому для группировки введен отдельный столбец - "валюта дивидендов". Не буду повторяться и показывать, как группировать и сортировать.
В примере покажу некий парадокс, у меня приложение Тинькофф не отображает дивиденды по своим же акциям.
Обратил внимание, что TCS($) принес большие дивиденды, и огромную доходность (* считаю как отношение всего оборота доходов/расходов).
Понимаю, что этот доход скорее всего относится к рублевой акции, т.к. сумма достаточно большая. Почти все, кто использовал Тинькофф API знают, что TCS и TCSG раньше висели на одном FIGI, и создавали головную боль. Пришлось ввести простой костыль, который меняет FIGI в зависимости от валюты.
Но особенность в том, что даже в терминале по этим тикерам не видно информации по данным выплатам:
![](https://habrastorage.org/getpro/habr/upload_files/cc4/012/0d3/cc40120d3b0593e140580b79d9d1efeb.png)
История в терминале
В ленте приложения эти событие отображается, и при клике переводит в TCS ($)
Но и в истории тикеров данной информации нет:
![TCS TCS](https://habrastorage.org/getpro/habr/upload_files/d6e/91c/d0d/d6e91cd0d0db5a312b3a6118345c58cc.png)
![TCSG TCSG](https://habrastorage.org/getpro/habr/upload_files/215/c7e/3d5/215c7e3d5ae79eef741c23731e41d1b5.png)
е) Еще один необычный пример. По STX статистика показывает отрицательное количество акций.
![](https://habrastorage.org/getpro/habr/upload_files/6e9/363/300/6e9363300989a32066be482f85bb4c3a.png)
*в данном случае эмулируется шорт-позиция. Доход рассчитывается, словно я продал по 98, а выкупить сейчас можно по 104
Видимо у Seagate когда-то сменился figi. Такая же история в официальном терминале, т.е. я словно из воздуха получил и продал эти акции, никакого наследования не видно. Техподдержка отправила в брокерский отчет смотреть сумму покупки по старому isin (IE00B58JVZ52):
![Вся история по STX в терминале Вся история по STX в терминале](https://habrastorage.org/getpro/habr/upload_files/2a9/a1c/9e2/2a9a1c9e2980fb16c2e5a900610a0fe6.png)
Есть еще минусы анализа данных из API, которые опишу в конце статьи.
е) Ищем "залежавшиеся" акции через столбец "дней с последней сделки"
![](https://habrastorage.org/getpro/habr/upload_files/fa7/c0c/43c/fa7c0c43cc96acf42e4deccc512cc619.png)
Это была одна из первых покупок, оказавшаяся падающим ножом, которую я почему-то наивно храню. Акция не приносит дивидендов, и лежит в долгосроке почти 3 года. Возможно пора зафиксировать убыток..
Отклоненные операции
Таблица может быть полезна для обнаружения несработавших тейк-профитов/стоп-лосс, попыток купить/продать акцию.
Например, у меня стоял тейпрофит на TGKN, выставивший заявку, которая не исполнилась.
Несработавший тейк/стоп придется переставлять вручную.
![](https://habrastorage.org/getpro/habr/upload_files/a06/7c9/8d7/a067c98d77253ef133b4532cedf07b65.png)
Еще можно вспомнить, какие акции вы хотели купить/продать, и как повела себя акция по отношению к текущей цене.
В примере ниже видны мои попытки купить ISKJ, который взлетел в 3.5 раза за короткий промежуток времени.
![](https://habrastorage.org/getpro/habr/upload_files/14a/f50/78d/14af5078d8e5f3b20d85a65704fbbc2f.png)
Есть и обратные примеры, куда к счастью не удалось войти. Мне такой анализ позволяет вспомнить, чем я руководствовался и немного порефлексировать:)
Прочие операции
![](https://habrastorage.org/getpro/habr/upload_files/4dd/484/cb9/4dd484cb9837afead00b232d94f14617.png)
Данные таблицы содержат операции, не связанные напрямую с инструментами, например, ввод/вывод средств, комиссию за маржинальную торговлю, плату за тариф и т.п.
Дополнительные столбцы с датами позволяют удобнее фильтровать/группировать данные по периодам, а одна из таблиц уже сгруппирована по месяцам, валюте и типу.
Анализируя траты на оплату тарифа "Трейдер", я заметил, что в августе 2021 год плата списалась с меня 2 раза. Я даже подумал, что это глюк API:
![](https://habrastorage.org/getpro/habr/upload_files/e6e/844/d12/e6e844d1228e04cbada15e0ea270fd7a.png)
Пример ручной группировки
![](https://habrastorage.org/getpro/habr/upload_files/ecf/558/46e/ecf55846e3eabb4d82315cb468279fd8.png)
Ответ тех. поддержки я не очень понял. Судя по всему, я с каких-то пор стал привязан к расчетному периоду и дате платежа (22-е). Хотя мне казалось, что если я заплатил 05.08.2021, то могу торговать до 04.09.2021.
UPD. В комментариях представители банка написали, что двойное списание осуществлено из-за технических проблем https://habr.com/ru/post/589865/comments/#comment_23875149
Этот пример показывает, что необходимо всегда сверять ожидание с реальностью.
Проблемы анализа через API
API не возвращает историю по бумагам, которые больше не обращаются на бирже. Некоторых погашенных облигаций я тоже не нашел в ответе API.
Видимо поэтому, чтобы узнать сколько я потратил на упомянутый выше Seagate, мне нужно скачивать отчет брокера.
По этой же причине не берусь считать суммарный итог портфеля.
При сплите/консолидации бумаги непонятен коэффициент, и я не нашел способа получить его от брокера. Видимо надо мониторить какие-то ресурсы/новости. Или пытаться высчитывать самому по разнице дневных свечей, но не уверен, что это надежно.
На данный момент бумаги, прошедшие сплит/консолидацию могут неправильно отображать доход в таблице. Если кто знает, как это решить - напишите.
Пока что не учитываю налоги, т.к. цель показать общую картину без тонкостей: учета ИИС; W-8BEN; сроков владения и т.д.
Итог
За последние годы приложение Тинькофф стало лучше, появились скринеры, группы, заметки. Не знаю есть ли такое у других брокеров. Но я до сих пор не нашел способа фильтровать/сортировать инструменты своего портфеля. Не раз писал предложения по улучшению, в том числе на Хабре. Как раз статья @softandiron вдохновила меня оживить забытый инструмент.
Я показал лишь часть ярких примеров использования. В будущем планируется расширить функционал сайта https://tstocks.ru/. Не откажемся от помощи грамотных инвесторов и программистов.
Как вам в целом такой формат загрузки, преобразования и отображения данных. Пользуйтесь ли вы сторонними инструментами, и помогают ли они пролить свет на портфель? Хватает ли вам штатного функционала брокера?
Таблицы несложно расширить, пишите, чего не хватает, сообщайте о недочетах и делитесь общим впечатлением.
Благодарю за внимание!