Практически с первых дней я стал клиентом Тиньков.Инвестиции.
И с этого же момента меня терзают смутные сомнения — отражает ли личный кабинет объективную реальность?
Дело в том, что я покупаю ценные бумаги, номинированные в долларах, но в ЛК цены всех активов отображаются в долларах, а итоговая стоимость портфеля в рублях.
И мне непонятно, это доллар вырос или я такой результативный инвестор?
А как же комиссии, налоги и прочие дивиденды?
Вот бы взять все мои сделки и расписать по ФИФО, как в складском учете… А сверху положить полученные дивиденды, а потом вычесть налоги.
Вот тогда я и увижу понятный мне результат.
Оказалось, у Тинькова есть API, которое позволяет писать торговых роботов (мне это совсем не интересно), а также загружать данные по своему портфелю и операциям.
У этого API есть официальное описание, но мне не все было понятно, пришлось разбираться.
Результаты этих разборок представляю вашему вниманию.
Полезные ссылки:
Описание API
Еще описание
Перед началом работы нужно установить библиотеку и получить токен.
Установка библиотеки:
Цитирую официальную инструкцию по получению токена:
На момент написания статью токен выдавался на странице www.tinkoff.ru/invest/settings, кнопка в нижней части страницы.

С токеном для песочницы у меня возникали ошибки, поэтому я начал экспериментировать с боевой версией. Чего и вам желаю (Осторожно: не купите-продайте случайно что-то лишнее).
Эти две строки делают все, что нам нужно.
Дальше работаем с переменной client.
Получим содержимоенашего вашего портфеля:
Посмотрим основные данные первого элемента:
В моем случае это:
value — Цена бумаги
balance — Кличество бумаг в портфеле, value и currency — их денежное выражение.
figi — Financial Instrument Global Identifier (Финансовый Глобальный Идентификатор инструмента)
ticker — Тикер актива.
По этим данным мы можем узнать человекочитаемое название актива.
Для данного запроса нам это не нужно (см. поле name), но в других случаях пригодится.
Получаем:
Эта API-функция у меня работает как надо. Видим, что 'BBG000BWPXQ8' -> 'British American Tobacco'.
А вот поиск названия актива по тикеру у меня не работает :(((
Разработчики предложили обновить библиотеку, но даже после этого не взлетело.
Впрочем, я решил этот вопрос кардинально. Скачал у Тинькова полный справочник торгуемых активов:
Как видим, figi и name там есть. Для моих целей — более чем достаточно.
А вот самое интересное — получить список моих операций. В операции (в моем случае) попадают следующие действия:
Код для выгрузки портфеля:
Нас интересуют поля:
Сразу возник вопрос — зачем нам какие-то trades, если есть price и quantity?
Как я понял, в quantity указано то количество бумаг, которые я хотел купить. А то, что фактически куплено, лежит в trades[i].quantity.
Т.е. если хотите обратится к фактическим сделкам, нужно перебрать то, что лежит в trades.
В ряде случаев, там None — например, для налогов или вводов/выводов средств.
Чтобы получить настоящие цифры, нужно смотреть и в сделки, и в биржевые операции:
И с этого же момента меня терзают смутные сомнения — отражает ли личный кабинет объективную реальность?
Дело в том, что я покупаю ценные бумаги, номинированные в долларах, но в ЛК цены всех активов отображаются в долларах, а итоговая стоимость портфеля в рублях.
И мне непонятно, это доллар вырос или я такой результативный инвестор?
А как же комиссии, налоги и прочие дивиденды?
Вот бы взять все мои сделки и расписать по ФИФО, как в складском учете… А сверху положить полученные дивиденды, а потом вычесть налоги.
Вот тогда я и увижу понятный мне результат.
Оказалось, у Тинькова есть API, которое позволяет писать торговых роботов (мне это совсем не интересно), а также загружать данные по своему портфелю и операциям.
У этого API есть официальное описание, но мне не все было понятно, пришлось разбираться.
Результаты этих разборок представляю вашему вниманию.
Полезные ссылки:
Описание API
Еще описание
Получение токена и установка библиотеки
Перед началом работы нужно установить библиотеку и получить токен.
Установка библиотеки:
pip install -i https://test.pypi.org/simple/ --extra-index-url=https://pypi.org/simple/ tinkoff-invest-openapi-client
Цитирую официальную инструкцию по получению токена:
- Зайдите в свой аккаунт на tinkoff.ru
- Перейдите в раздел инвестиций
- Перейдите в настройки
- Функция «Подтверждение сделок кодом» должна быть отключена
- Выпустите токен OpenApi для биржи и Sandbox. Возможно система попросит вас авторизоваться еще раз, не беспокойтесь, это необходимо для подключения робота к торговой платформе.
- Скопируйте токен и сохраните, токен отображается только один раз, просмотреть его позже не получится, тем не менее вы можете выпускать неограниченное количество токенов.
На момент написания статью токен выдавался на странице www.tinkoff.ru/invest/settings, кнопка в нижней части страницы.

С токеном для песочницы у меня возникали ошибки, поэтому я начал экспериментировать с боевой версией. Чего и вам желаю (Осторожно: не купите-продайте случайно что-то лишнее).
Авторизация
from openapi_client import openapi token = 'тут нужно вставить ваш токен' client = openapi.api_client(token)
Эти две строки делают все, что нам нужно.
Дальше работаем с переменной client.
Что у нас в портфеле
Получим содержимое
pf = client.portfolio.portfolio_get()
Посмотрим основные данные первого элемента:
print('value:', pf.payload.positions[0].average_position_price.value) print('currency:', pf.payload.positions[0].average_position_price.currency) print('balance:', pf.payload.positions[0].balance) print('figi:', pf.payload.positions[0].figi) print('ticker:', pf.payload.positions[0].ticker) print('name:', pf.payload.positions[0].name)
В моем случае это:
value: 45.98 currency: USD balance: 21.0 figi: BBG000BWPXQ8 ticker: BTI name: British American Tobacco
value — Цена бумаги
balance — Кличество бумаг в портфеле, value и currency — их денежное выражение.
figi — Financial Instrument Global Identifier (Финансовый Глобальный Идентификатор инструмента)
ticker — Тикер актива.
По этим данным мы можем узнать человекочитаемое название актива.
Для данного запроса нам это не нужно (см. поле name), но в других случаях пригодится.
Получаем название бумаги по FIGI и тикету
# Получение инструмента по FIGI instr = client.market.market_search_by_figi_get('BBG000BWPXQ8') instr
Получаем:
{'payload': {'currency': 'USD', 'figi': 'BBG000BWPXQ8', 'isin': 'US1104481072', 'lot': 1, 'min_price_increment': 0.01, 'name': 'British American Tobacco', 'ticker': 'BTI', 'type': 'Stock'}, 'status': 'Ok', 'tracking_id': 'a1979917d2141916'}
Эта API-функция у меня работает как надо. Видим, что 'BBG000BWPXQ8' -> 'British American Tobacco'.
А вот поиск названия актива по тикеру у меня не работает :(((
instr = client.market.market_search_by_ticker_get('BTI' ) print(instr)
Разработчики предложили обновить библиотеку, но даже после этого не взлетело.
Качаем справочник ценных бумаг
Впрочем, я решил этот вопрос кардинально. Скачал у Тинькова полный справочник торгуемых активов:
получил# Получение списка облигаций bonds = client.market.market_bonds_get() # Получение списка ETF etfs = client.market.market_etfs_get() # Получение списка акций stocks = client.market.market_stocks_get() instr_list = bonds.payload.instruments + etfs.payload.instruments + stocks.payload.instruments instr_list[:3]
[{'currency': 'RUB', 'figi': 'BBG00844BD08', 'isin': 'RU000A0JU898', 'lot': 1, 'min_price_increment': 0.1, 'name': 'МКБ выпуск 9', 'ticker': 'RU000A0JU898'}, {'currency': 'RUB', 'figi': 'BBG00R05JT04', 'isin': 'RU000A1013Y3', 'lot': 1, 'min_price_increment': 0.1, 'name': 'Черкизово выпуск\xa02', 'ticker': 'RU000A1013Y3'}, {'currency': 'RUB', 'figi': 'BBG00PNLY692', 'isin': 'RU000A100DC4', 'lot': 1, 'min_price_increment': 0.1, 'name': 'МСБ-Лизинг 002P выпуск 2', 'ticker': 'RU000A100DC4'}]
Как видим, figi и name там есть. Для моих целей — более чем достаточно.
Получаем список операций
А вот самое интересное — получить список моих операций. В операции (в моем случае) попадают следующие действия:
- PayIn — Пополнение брокерского счета
- PayOut — Вывод денег
- BuyCard — Покупка с карты
- Sell — Продажа
- BrokerCommission — Комиссия брокера
- Dividend — Выплата дивидендов
- Tax — Налоги
- TaxDividend- Налоги c дивидендов
- ServiceCommission — Комиссия за обслуживание
Код для выгрузки портфеля:
Посмотрим, что получилось. В моем случае, представляет интерес этот элементfrom datetime import datetime from pytz import timezone # Качаем все операции с 30 сентября 2016 (я один из первых клиентов Тиньков Инвестиции) d1 = datetime(2016, 9, 30, 0, 0, 0, tzinfo=timezone('Europe/Moscow')) # timezone нужно указывать. Иначе - ошибка d2 = datetime.now(tz=timezone('Europe/Moscow')) # По настоящее время ops = client.operations.operations_get(_from=d1.isoformat(), to=d2.isoformat())
Вот что он собой являетops.payload.operations[217]
{'commission': {'currency': 'USD', 'value': -0.42}, 'currency': 'USD', 'date': datetime.datetime(2018, 11, 7, 10, 55, 53, 648913, tzinfo=tzoffset(None, 10800)), 'figi': 'BBG000PSKYX7', 'id': '42281525510', 'instrument_type': 'Stock', 'is_margin_call': False, 'operation_type': 'BuyCard', 'payment': -141.05, 'price': 141.05, 'quantity': 4, 'status': 'Done', 'trades': [{'date': datetime.datetime(2018, 11, 7, 10, 55, 53, 648913, tzinfo=tzoffset(None, 10800)), 'price': 141.05, 'quantity': 1, 'trade_id': '42636800'}]}
Нас интересуют поля:
- date — дата сделки
- figi — код актива
- operation_type — тип операции
- payment — сумма операции. У налогов или комиссий указана именно она. price при этом None
- price — цена одной бумаги
- quantity — плановое количество бумаг
- trades — реальные биржевые сделки
Сразу возник вопрос — зачем нам какие-то trades, если есть price и quantity?
Все не так просто (план и факт)
Как я понял, в quantity указано то количество бумаг, которые я хотел купить. А то, что фактически куплено, лежит в trades[i].quantity.
Т.е. если хотите обратится к фактическим сделкам, нужно перебрать то, что лежит в trades.
В ряде случаев, там None — например, для налогов или вводов/выводов средств.
Чтобы получить настоящие цифры, нужно смотреть и в сделки, и в биржевые операции:
for op in ops.payload.operations: # Перебираем операции print(op.figi) # figi всегда берем из операции print(op.operation_type) # и тип операции тоже if op.trades == None: # Если биржевых сделок нет print('price:', op.price) # Берем из операции цену бумаги print('payment:', op.payment) # Сумму платежа print('quantity:', op.quantity) # И количество бумаг else: for t in op.trades: # А если есть сделки - то перебираем их print('price:', t.price) # И берем данные из них print('quantity:', t.quantity) print('--------------')
