Pull to refresh

Что не показывает аналитика в Тинькофф Инвестициях. Подробно разбираем свой портфель

Reading time10 min
Views17K

У меня, как у пользователя Тинькофф Инвестиций, часто возникали вопросы: какие акции за весь период торговли принесли мне наибольший доход; сколько всего я заплатил за обслуживание тарифа и прочие комиссии; какие акции в портфеле давно лежат и не приносят мне доход; как отсортировать акции в своем портфеле по какому-либо критерию.

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

К примеру, покупаем 1 акцию по 1000, после падения до 900 усредняем еще одной акцией. Затем при отскоке до 950 продаем 1 акцию. В итоге оставшаяся акция в портфеле "горит зеленым" (образуется плюс +50 по правилу fifo), хотя фактический результат бумаги на данный момент будет 0 (без учета комиссий). Такое отображение бумаг в приложении может сбить с толку, и привести к неправильным решениям и большим потерям, при совершении множества сделок.

Идея вести дневник сделок в excel, или периодически копаться в налоговом/брокерском отчете, мне не понравилась. Зато приглянулась мысль - обрабатывать данные полученные из официального API.

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

В статье я продемонстрирую, как пользоваться созданным инструментом, и какие задачи решаются. Подсвечу некоторые особенности данных полученных из API.

Web-интерфейс
Web-интерфейс

Об инструменте, немного лирики

Мои первые шаги по анализу истории были сделаны года два назад. Результатом были таблицы, которые помогали мне закрыть любые вопросы:

Скрин статистики 2020 года
Скрин статистики 2020 года

Я даже периодически делал разного роды выгрузки друзьям и знакомым. Передавать VM/doсker образ со скриптами людям без навыков в IT было сложно, поэтому делалось все мною вручную. Зародилась мысль автоматизировать и вывести процесс в онлайн.

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

Позже к разработке подключился друг. И вот мы больше года держим сервер, где крутятся наши наработки на python (Telegram-боты, скринеры и прочее). К примеру, боты уведомляют о различных событиях по акциям наших портфелей.

Разработка велась нерегулярно, в свободное время. Различных скриптов со временем стало много, для этого мы создали единый модуль с веб-интерфейсом для управления всеми наработками, заодно изучили React. Начали с отображения табличных данных.

Результатом полуторамесячной работы по выходным стал сайт https://tstocks.ru/, который использует:

  • Front: ReactJS (Nginx)

  • Backend: Python Flask

  • СУБД: Postgres

Немного внутренностей

Все запросы и параметры хранятся в БД. Получился достаточно удобный конструктор таблиц и прочих методов

Управление таблицами в БД
Управление таблицами в БД
Меню
Меню

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

Ближе к делу, как загрузить данные для анализа

Для анализа требуется история сделок, которую можно забрать в формате 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
повторный импорт

При повторном импорте, если данные по сделкам не изменились, то будет выдан тот же id, а загрузка пропущена.

*Nginx имеет небольшие лимиты на повторный импорт

Пример для Windows:

Windows PowerShell
  1. Сохраняем историю сделок в файл

    Дополнительные параметры

    Можно изменить параметры запроса в 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 # название файла в который сохранятся операции
  1. Отправляем файл на сервер

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, а также в планах ввести время жизни загруженного портфеля.

Если у вас есть сомнения по поводу описываемых операций, уточните подробности у нас, если есть идеи как сделать лучше - сообщите.

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

Статистика по инструментам

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

а) Смотрим доходность торговли по конкретной бумаге

Почти два года назад я наивно игрался с "шортами Tesla", и мне было интересно сколько дохода это приносит. С этого кейса родилась идея извлекать данные из API.

Итог сделок плачевный, хотя начиналось все неплохо. Опыт, сын ошибок трудных..

Поясню значения столбцов:

  • Фикс разница - зафиксированный доход/убыток. Купоны/дивиденды/комиссии не включены, они отображаются в отдельных одноименных столбцах

Немного боли с расчетом

Оказывается, что это не так легко посчитать, если на руках не 0 бумаг.

Бумаги покупаются и продаются частями в разное время, требуется раскрывать и упорядочивать сделки, соблюдая правило FIFO, еще у некоторых акций огромные лоты (*в TGKB миллион шт.)

Все расчеты ведутся в БД, т.ч. пришлось повозиться с оптимизацией sql запросов и функций, чтобы это работало очень быстро. Для оптимизации использовал https://explain.dalibo.com/

  • Доход текущий - это примерно то, что мы видим в приложении по текущим позициям, купоны/дивиденды/комиссии не включены

  • Доход - это сумма двух предыдущих столбцов, купоны/дивиденды/комиссии не включены

  • Общий доход - это предыдущий столбец + налоги(див/купон)/купоны/дивиденды/комиссии

  • Figi содержит ссылку, по которой открывается вся история по бумаге:

Пример истории по FIGI
Пример истории по FIGI

*для демонстрационного портфеля некоторые подробности недоступны

**комиссия за маржинальную торговлю не привязана к конкретному figi, ее можно посмотреть на вкладке "Прочие платежи"

б) Смотрим то, что не видно в приложении при фиксации убытков, или активной торговле

Скоро конец года, и для снижения налога на доход я зафиксировал убыток по FEES, и снова выкупил акции. Открыв приложение брокера, я даже увижу прибыль (столбец "Доход текущий"). А если так зафиксировать все убытки, то можно увидеть "зеленый" портфель в приложении.

Однако, мне интересно видеть и не забывать про реальный итог торговли по тикеру.

в) Ищем бумаги, которые принесли наибольшую прибыль за все время

Столбцы таблицы поддерживают фильтрацию, сортировку и группировку по нескольким столбцам. Сортировка осуществляется кликом по нескольким столбцам через SHIFT, группировка осуществляется через меню-ПКМ в требуемой последовательности. При группировке некоторые числовые столбцы показывают итог с суммой, минимальным и максимальным значением

Группируем или фильтруем по валюте и сортируем по "Общему доходу"

Наиболее прибыльной стратегией для меня было - купить несколько голубых фишек, и забыть про них:)

г) Считаем дивиденды

Некоторые компании торгуются в рублях, но платят дивиденды в валюте (например "Полиметалл"). Поэтому для группировки введен отдельный столбец - "валюта дивидендов". Не буду повторяться и показывать, как группировать и сортировать.

В примере покажу некий парадокс, у меня приложение Тинькофф не отображает дивиденды по своим же акциям.

Обратил внимание, что TCS($) принес большие дивиденды, и огромную доходность (* считаю как отношение всего оборота доходов/расходов).

Понимаю, что этот доход скорее всего относится к рублевой акции, т.к. сумма достаточно большая. Почти все, кто использовал Тинькофф API знают, что TCS и TCSG раньше висели на одном FIGI, и создавали головную боль. Пришлось ввести простой костыль, который меняет FIGI в зависимости от валюты.

Но особенность в том, что даже в терминале по этим тикерам не видно информации по данным выплатам:

История в терминале

В ленте приложения эти событие отображается, и при клике переводит в TCS ($)

Но и в истории тикеров данной информации нет:

TCS
TCS
TCSG
TCSG

е) Еще один необычный пример. По STX статистика показывает отрицательное количество акций.

*в данном случае эмулируется шорт-позиция. Доход рассчитывается, словно я продал по 98, а выкупить сейчас можно по 104

Видимо у Seagate когда-то сменился figi. Такая же история в официальном терминале, т.е. я словно из воздуха получил и продал эти акции, никакого наследования не видно. Техподдержка отправила в брокерский отчет смотреть сумму покупки по старому isin (IE00B58JVZ52):

Вся история по STX в терминале
Вся история по STX в терминале

Есть еще минусы анализа данных из API, которые опишу в конце статьи.

е) Ищем "залежавшиеся" акции через столбец "дней с последней сделки"

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

Отклоненные операции

Таблица может быть полезна для обнаружения несработавших тейк-профитов/стоп-лосс, попыток купить/продать акцию.

Например, у меня стоял тейпрофит на TGKN, выставивший заявку, которая не исполнилась.

Несработавший тейк/стоп придется переставлять вручную.

Еще можно вспомнить, какие акции вы хотели купить/продать, и как повела себя акция по отношению к текущей цене.

В примере ниже видны мои попытки купить ISKJ, который взлетел в 3.5 раза за короткий промежуток времени.

Есть и обратные примеры, куда к счастью не удалось войти. Мне такой анализ позволяет вспомнить, чем я руководствовался и немного порефлексировать:)

Прочие операции

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

Дополнительные столбцы с датами позволяют удобнее фильтровать/группировать данные по периодам, а одна из таблиц уже сгруппирована по месяцам, валюте и типу.

Анализируя траты на оплату тарифа "Трейдер", я заметил, что в августе 2021 год плата списалась с меня 2 раза. Я даже подумал, что это глюк API:

Пример ручной группировки

Ответ тех. поддержки я не очень понял. Судя по всему, я с каких-то пор стал привязан к расчетному периоду и дате платежа (22-е). Хотя мне казалось, что если я заплатил 05.08.2021, то могу торговать до 04.09.2021.

UPD. В комментариях представители банка написали, что двойное списание осуществлено из-за технических проблем https://habr.com/ru/post/589865/comments/#comment_23875149

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

Проблемы анализа через API

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

    Видимо поэтому, чтобы узнать сколько я потратил на упомянутый выше Seagate, мне нужно скачивать отчет брокера.

    По этой же причине не берусь считать суммарный итог портфеля.

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

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

  3. Пока что не учитываю налоги, т.к. цель показать общую картину без тонкостей: учета ИИС; W-8BEN; сроков владения и т.д.

Итог

За последние годы приложение Тинькофф стало лучше, появились скринеры, группы, заметки. Не знаю есть ли такое у других брокеров. Но я до сих пор не нашел способа фильтровать/сортировать инструменты своего портфеля. Не раз писал предложения по улучшению, в том числе на Хабре. Как раз статья @softandiron вдохновила меня оживить забытый инструмент.

Я показал лишь часть ярких примеров использования. В будущем планируется расширить функционал сайта https://tstocks.ru/. Не откажемся от помощи грамотных инвесторов и программистов.

Как вам в целом такой формат загрузки, преобразования и отображения данных. Пользуйтесь ли вы сторонними инструментами, и помогают ли они пролить свет на портфель? Хватает ли вам штатного функционала брокера?

Таблицы несложно расширить, пишите, чего не хватает, сообщайте о недочетах и делитесь общим впечатлением.

Благодарю за внимание!

Only registered users can participate in poll. Log in, please.
Хватает ли вам аналитики, предоставляемой брокером?
13.33% Да14
71.43% Нет75
15.24% Не знаю16
105 users voted. 25 users abstained.
Only registered users can participate in poll. Log in, please.
Используете ли вы сторонние средства для анализа портфеля?
25.27% Использую бесплатные инструменты23
8.79% Использую платные инструменты8
43.96% Не использую40
43.96% Использую свои способы / Веду дневник сделок / Прочее40
91 users voted. 27 users abstained.
Tags:
Hubs:
If this publication inspired you and you want to support the author, do not hesitate to click on the button
Total votes 31: ↑31 and ↓0+31
Comments53

Articles