Горячие клавиши

← и →: предыдущая и следующая глава

S или /: поиск по книге

?: показать эту подсказку

Esc: закрыть подсказку или поиск

Т-Банк

Крейты: brokapi-tbank-protocol (gRPC клиент, собранный из официальных .proto) и brokapi-tbank (коннекторы). С песочницы Т-Банка рекомендуется начинать: Перед боевым счетом.

Вход

ЧтоКак
Токенодин статичный токен (TBANK_TOKEN). Обновлять нечего. Отвергнутый токен - ошибка настройки (Config). По документации Т-Банка новый токен нужно начать использовать в течение 7 дней после выпуска, иначе его отзовут. Выпускается только на сайте tbank.ru
Счетaccount_id в настройке (TBANK_ACCOUNT_ID). Не задан: берется единственный открытый счет токена, а при нескольких счетах коннектор не запустится
Песочницада. TBANK_SANDBOX=true выбирает адрес песочницы, caps().sandbox показывает это
Адресбоевой и песочницы заданы, можно подменить TBANK_ENDPOINT (только https://, адрес имитации задается в коде). Свой корневой сертификат (например, национальный) добавляется TbankConfig::with_root_certificate_pem, встроенные корни остаются. HTTP/2 keep-alive идет раз в 5 минут и только пока открыт вызов или поток
Имя приложенияTBANK_APP_NAME (заголовок x-app-name, по соглашению Т-Банка <ник>.<репозиторий>)
Лимитыbrokapi::tbank::limits::default_limits(), один счетчик на пользователя

Где взять токен и счет

Токен выпускает человек, чей это счет (правило 0). Шаги по документации Т-Банка:

  1. Открыть настройки профиля Т-Инвестиции на компьютере (с телефона страница может переадресовать в приложение, где раздела токенов нет) и войти. Выпустить токен можно только на сайте tbank.ru. Если страница не открывается, нужны сертификаты НУЦ Минцифры или Яндекс Браузер.
  2. Убедиться, что «Подтверждение сделок кодом» выключено: по документации Т-Банка оно должно быть отключено. Сделки на сумму больше 30 000 000 рублей требуют подтверждения и через API недоступны.
  3. Выпустить токен T-Invest API для биржи и/или для песочницы. Система может попросить войти еще раз.
  4. Скопировать токен сразу: его показывают один раз, позже получить его нельзя.

Какой токен выбрать. Виды: только чтение, полный доступ, токен для переводов между счетами (его не берите), токен с доступом к одному счету (права чтения или полного доступа настраиваются) и токен песочницы. Для первого запуска возьмите токен песочницы (быстрый старт на Python). Для чтения боевого счета берите токен «только чтение». Токен с полным доступом нужен, когда человек решил поставить первую боевую заявку, и лучше с доступом к одному счету. Токен песочницы к боевому адресу не подойдет.

Номер счета. Если токен выпущен для одного счета, TBANK_ACCOUNT_ID задавать не нужно: берется его единственный открытый счет. Если токен на все счета и счетов несколько, коннектор не запустится и просит указать счет. Для Инвесткопилки, Счета под ключ и Смарт-счета токен «на один счет» выпустить нельзя, у них только токен на все счета. Где в кабинете смотреть номер счета, документация Т-Банка не говорит: в Rust список счетов дает TbankClient::list_accounts.

Счет песочницы. Токен песочницы сам счета не открывает. Счет создает вызов OpenSandboxAccount, пополняет SandboxPayIn (только рубли, до 30 000 000 рублей), счета живут 3 месяца с последнего использования. В Rust это методы sandbox()-клиента (crates/tbank/tests/live_sandbox.rs), в Python и Gateway готовых команд нет, остается raw или любой другой клиент T-Invest API.

Срок. Новый токен надо начать использовать в течение 7 дней после выпуска, иначе его отзовут. Токен живет три месяца с даты последнего использования. Ответ 40003 значит, что токен неактуален. Посмотреть и отозвать токены: настройки безопасности, блок «Приложения, у которых есть доступ к данным для входа».

Идентификатор инструмента

Коннектор принимает любую из трех форм:

ФормаКогда использовать
NativeId::Uidосновная. Ее отдает справочник, и в событиях брокер сам называет инструмент так
NativeId::Figiесли есть figi
NativeId::TickerClassтикер и класс (SBER, TQBR), уходит брокеру как SBER_TQBR

Ключ библиотеки - SBER@TQBR. Найти инструмент и его uid: md.find(InstrumentQuery::ByTicker { .. }). Событие потока несет тот InstrumentId, который вы указали при подписке.

Единицы и стакан

ЧтоКак
Количествов библиотеке штуки (единицы инструмента), в API Т-Банка лоты для заявок, стакана, сделок рынка и свечей. Коннектор переводит в обе стороны: заявку делит на лот, стакан, сделки, свечи, статусы заявок и стоп-заявки умножает. Своих сделок (OrderTrade.quantity, история операций) и позиций это не касается: брокер отдает их штуками, они идут как есть. Лот инструмента (Instrument.lot, он же lot_size сообщения потока заявок) коннектор узнает одним запросом GetInstrumentBy при первой заявке, подписке или чтении по инструменту и запоминает. Заявка, не кратная лоту, дробная, нулевая или отрицательная - Rejected { invalid_qty } до отправки. Если лот прочитать нельзя, чтение дает Transport, а событие потока заявок с неизвестным лотом считается потерянным: придет Overflow и шлюз закроется до reconcile
Ценаза одну бумагу. Quotation и MoneyValue (units и nano) переводятся в Decimal и обратно точно. Цена с больше чем 9 знаками - Rejected { invalid_price } до отправки
Глубина стакана1, 10, 20, 30, 40, 50. Запрошенная глубина округляется вверх до допустимой, события режутся до нужной. Больше 50 - 50
Стаканполный снимок. Если брокер пометил стакан несогласованным (is_consistent = false), он не публикуется, вместо него Resync { SequenceGap }
Котировкиотдельного потока нет: котировка - лучший уровень стакана. Стакан и котировки одного инструмента идут одной подпиской брокера
Сделки рынкасделка без направления в MarketTrade не помещается (сторона обязательна) и пропускается
Свечивсе таймфреймы. close_ts = открытие + длина таймфрейма (месяц считается как 30 дней)
last_tradesсделки за последний час, новейшие limit штук

Как cid уходит к брокеру

В поле order_id запроса PostOrder. По документации Т-Банка это ключ идемпотентности «в формате UID, до 36 символов». UUID с дефисами занимает ровно 36, поэтому влезает без потерь. Тот же ключ брокер возвращает как order_request_id в ответе и потоке, а CancelOrder и GetOrderState принимают его с типом идентификатора «запрос».

Идемпотентность не используется: что сервер делает с повторным ключом, никто не измерял (LabelOnly, вопрос 1 ниже). Библиотека place сама не повторяет в любом случае.

Заявка, поставленная не вами (с телефона, другим роботом), приходит без order_request_id. Чтобы она могла попасть в foreign, коннектор выдает ей подставной стабильный cid, вычисленный из номера заявки на бирже.

Ответы брокера

Номер ошибки Т-Банка (пятизначный, из таблицы ошибок) коннектор читает из текста статуса, а если там пусто, из начала заголовка message. Статус RESOURCE_EXHAUSTED у Т-Банка не всегда означает лимит запросов: так же отвечает про лимит стоп-заявок по инструменту. Поэтому его различают по номеру. Номер, которого нет в таблице, остается лимитом запросов.

ОтветРезультат
RESOURCE_EXHAUSTED с кодом 80002, 80003, 80006 или без известного кодаRateLimited. Время ожидания берется из заголовка x-ratelimit-reset, иначе 1 секунда (для 80003 и 80006, которые брокер считает в минуту, 60 секунд)
RESOURCE_EXHAUSTED с кодом 80007Rejected { code: "stop_orders_limit" }: по инструменту набрано максимум стоп-заявок. Повтор не поможет, снимите одну из них
RESOURCE_EXHAUSTED с кодом 80001 (открыто максимум потоков)Rejected { code: "streams_limit" }
RESOURCE_EXHAUSTED с кодом 80004 или 80005 (потоки)Rejected с кодом no_subscriptions или stream_lifetime
INVALID_ARGUMENT с кодом 30261 (слишком много стоп-заявок в одном ответе)Rejected { code: "stop_orders_response_limit" }, см. «Стоп-заявки» ниже
NOT_FOUNDRejected с кодом not_found (как у остальных брокеров)
INVALID_ARGUMENT, PERMISSION_DENIED, FAILED_PRECONDITION, ALREADY_EXISTS и подобныеRejected с кодом статуса
UNAUTHENTICATEDConfig (токен не подошел)
Таймаут, UNAVAILABLE, INTERNAL и все остальное на командеUnknown (брокер мог выполнить)
Внутри обычного ответа статус «отклонено»Rejected { code: "REJECTED" }

Изменение заявки

ReplaceOrder. Нужны биржевой номер и количество исходной заявки: берутся из того, что коннектор уже знает, иначе один запрос GetOrderState. Цена не указана - берется цена исходной. Новый cid становится ключом идемпотентности. Биржевой номер после замены может измениться, ориентируйтесь на cid.

Свои сделки, портфель

ЧтоКак
Поток исполненийTradesStream. Комиссии в нем нет (0), cid определяется по номеру заявки. Сделка может прийти раньше ответа на PostOrder: пока заявка в пути, такая сделка ждет ответа и уходит с cid (или без него, если ее заявку никто не заявил)
ИсторияGetOperationsByCursor: исполненные покупки и продажи, в том числе маржинальные (margin-call) и оплаченные картой, по сделке на Execution. Комиссия операции делится на количество, broker_order_id - номер операции, cid нет. Читается не более 20 страниц по 1000 операций: период, в котором их больше, дает ошибку Rejected с кодом range_too_long, а не обрезанный список
Портфельдва запроса: деньги из GetPositions, позиции из GetPortfolio. Поток из двух потоков (PortfolioStream, PositionsStream) под одним номером подписки
Заявки после обрыва потокабот получает Event::Reconnected на подписки заявок и исполнений, шлюз закрывается до reconcile. Коннектор перечитывает активные заявки и присылает изменившиеся. Закрытые за время обрыва находите через order_state и executions

Справочник

  • find по тикеру и ISIN: быстрый поиск (запись короткая, поле currency пустое, нужную валюту берите через get).
  • find(ByKind): списки акций, облигаций, ETF, фьючерсов, опционов, валют (базовый список, торгуемое через API). Запросы тяжелые, у них свое ведро лимитов (15 в минуту), кеша нет. Для опционов используется метод, помеченный как устаревший: если Т-Банк его уберет, станет Unsupported.
  • MutualFund и Other: Unsupported.
  • price_step_value равен шагу цены. Для фьючерсов стоимость шага в деньгах не вычисляется.

Стоп-заявки

Отдельный сервис стоп-заявок: PostStopOrder, GetStopOrders, CancelStopOrder. Срок: «до отмены» и «до даты». «До конца дня» нет. Количество в штуках, как у заявок (брокеру уходят лоты). Брокер не возвращает cid стоп-заявки. Связь с номером хранится в памяти процесса, после рестарта в списке cid пустой и снимать стоп нужно по номеру брокера. Потока статусов в API нет. Длинный список. Брокер не отдает слишком много стоп-заявок в одном ответе: ошибка 30261 «ограничьте запрос параметрами from и to». active_stop_orders сначала просит весь список, а на 30261 делит период от 1970 до 2099 года пополам, пока каждый кусок не поместится, и склеивает ответы (повтор заявки на стыке отбрасывается по номеру). Это тратит запросы GetStopOrders (60 в минуту, всплеск 10 в crates/tbank/limits.toml): если квота кончилась посреди чтения, будет RateLimited, а читать придется заново. При длинном списке поднимите burst ведра stop_orders_get. Не больше 40 запросов за чтение, дальше Rejected { code: "stop_orders_response_limit" }: снимите лишние стоп-заявки. По какому времени заявки (создания, срока) брокер отбирает период и сколько заявок помещается в один ответ, документация не говорит. Потерянный ответ. Если place_stop кончился Unknown, а стоп у брокера есть, cid в списке не вернется сам: брокер его не отдает. Коннектор запоминает, что просили (бумага, сторона, вид, лоты, цена активации, цена заявки) и когда отправил, и при следующем active_stop_orders дает стопу этот cid, если подходит ровно один стоп без cid и создан он, пока запрос был в пути (плюс-минус 10 секунд на расхождение часов). Два одинаковых ожидания или два подходящих стопа (один может быть чужой) - cid не назначается. Это опирается на create_date стопа в списке брокера: как Т-Банк его пишет, вживую не проверено. Если cid не вернулся, стоп с cid: None на той же бумаге и в ту же сторону не считайте отсутствующим. Повтор запроса с тем же order_id библиотека не использует: ключ ли это идемпотентности для стопов, неизвестно. Подробно: Стоп-заявки.

Чего Т-Банк не поддерживает или делает иначе

ЧтоКак
Поток статусов стоп-заявокв API нет, Unsupported
Справочник MutualFund, OtherUnsupported
Серверный стрим рыночных данных, торговые статусы в потоке, остальное APIобщего трейта нет, доступно через raw()
Подтверждение отписки в потоках заявоку серверных потоков нет сообщения отписки, закрывается сам вызов

Лимиты

Т-Банк считает лимиты на пользователя: на все счета и все токены вместе. Поэтому счетчик один на программу. В crates/tbank/limits.toml значения из документации брокера, отмена вынесена в отдельное ведро. Реальные значения отдает GetUserTariff и заголовки x-ratelimit-*: их можно проверить через raw(). До 11 одновременных соединений, до 300 подписок в одном потоке рыночных данных.

Что учесть

  1. Повтор order_id: что сделает Т-Банк (вернет прежний отчет, ошибку или примет вторую заявку), в документации не сказано. Коннектор повторов не делает, поэтому на вас это не влияет, но свой код на повтор order_id не закладывайте.
  2. Единицы количества в потоке своих сделок - штуки (по описанию протокола).
  3. Номер биржевой заявки после ReplaceOrder может измениться. Ориентируйтесь на cid.

Листать можно клавишами Влево и Вправо.

brokapi by RunInfra