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

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

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

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

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

АЛОР Брокер

Крейты: brokapi-alor-protocol (клиент HTTP и WebSocket: все методы описания API брокера и оба канала WebSocket) и brokapi-alor (коннекторы).

Вход

ЧтоКак
Токенrefresh-токен с портала разработчика (ALOR_REFRESH_TOKEN). Из него коннектор получает токен доступа (POST /refresh сервера авторизации). Refresh-токен живет год в боевом контуре и месяц в тестовом, токен доступа - 30 минут
Портфель и биржаALOR_PORTFOLIO (например D12345) и ALOR_EXCHANGE (MOEX по умолчанию или SPBX). Если портфель не назван, коннектор берет единственный портфель из токена, а если их несколько, не стартует и просит назвать. Один коннектор работает с одной биржей: заявка по бумаге другой биржи это Config без сети
Контурыбоевой (api.alor.ru) и тестовый (apidev.alor.ru, нужен тестовый счет, который выдает брокер). Тестовый включается ALOR_ENV=test (в коде AlorConfig::with_env(AlorEnv::Test)), в Python и Gateway - ALOR_TEST=true (test=True в connect). Контуры изолированы, токен одного не годится для другого. Песочницы в смысле Т-Банка нет: тестовый контур это отдельный контур со своими данными
Обновлениетокен доступа берется заново через 20 минут (или раньше, если его собственный срок короче) и после ответа 401 на чтение (чтение повторяется один раз). Команда после 401 не повторяется. По WebSocket токен идет в каждом сообщении, при переподключении подписки восстанавливаются со свежим токеном
Лимитыbrokapi::alor::limits::default_limits(): встроенный файл limits.toml крейта. Свой файл: limits_from_toml_str и limits_from_toml_path. Подробно ниже
РынкиМосковская биржа (фондовый, срочный и валютный рынки) и СПБ Биржа. Какие рынки открыты вашему счету, определяет брокер: смотрите в кабинете

Где взять токен и портфель

Токен выпускает человек, чей это счет (правило 0). Права у refresh-токена АЛОР не выбираются: по документации брокера он равносилен логину и паролю торгового аккаунта, то есть дает и чтение, и торговлю. Токена «только для чтения» в документации нет, поэтому для первого запуска безопаснее тестовый контур, а на боевом контуре токен хранят как пароль. Шаги по документации АЛОР:

Боевой контур (нужен брокерский счет в АЛОР Брокер):

  1. Зарегистрировать учетную запись разработчика на портале alor.dev (кнопка «Зарегистрироваться» на странице входа, подтвердить почту).
  2. Открыть страницу «Токены для доступа к API» (alor.dev/open-api-tokens), ввести логин и пароль торгового аккаунта и нажать «Привязать». К одной учетной записи разработчика привязывается один торговый аккаунт.
  3. Нажать «Выписать токен», затем «Показать» у нового токена в списке. Он действует год. Токены общие для всех разработчиков, у которых привязан этот аккаунт: отзыв одним отзывает для всех.

Тестовый контур (ALOR_TEST=true):

  1. Учетная запись разработчика та же, что выше.
  2. Тестовый торговый аккаунт выдает брокер: заявка на support@alor.ru или через личный кабинет lk.alor.ru. К учетной записи разработчика он не привязывается.
  3. Refresh-токен тестового контура выписывается со страницы alor.dev/oauth-authorization по ссылке «Begin OAuth authorization flow», вход логином и паролем тестового аккаунта. Одновременно существует один такой токен, он действует месяц.

Портфель. ALOR_PORTFOLIO - номер портфеля вида D12345 (по примерам в документации). Если у токена один портфель, переменную можно не задавать. Если портфелей несколько, коннектор не запустится и просит назвать нужный. Где в кабинете АЛОР смотреть номера портфелей, мы документацией не подтверждаем: ищите в личном кабинете брокера.

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

NativeId::TickerClass { ticker, class_code }, например SBER и TQBR: класс это режим торгов (борд). Ключ библиотеки - SBER@TQBR. Биржа берется из режима торгов: SPBX это биржа SPBX, любой другой режим это MOEX. Любой другой вид идентификатора даст ошибку настройки (Config): справочник для АЛОРа не нужен, идентификатор собирается сам без сети.

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

ЧтоКак
Числацены, количества и суммы читаются из JSON в Decimal по тексту ответа, 244.30 остается 244.30. Формат ответов всегда Simple (оригинальные имена полей)
Количествов библиотеке штуки. Брокер считает заявку в лотах: коннектор один раз читает размер лота из справочника (lotsize), переводит штуки в лоты и обратно. Количество не кратное лоту это Rejected { invalid_qty } до отправки, ничего не округляется. Заявки, исполнения и позиции брокер отдает и в лотах, и в штуках, коннектор читает штуки
Стакандо 50 уровней с каждой стороны (больший запрос режется), всегда полный снимок: брокер присылает стакан целиком, incremental_order_book = false. Объем уровня отдается как пришел
Котировкиотдельный поток. Объем лучших цены покупки и продажи брокер дает в лотах, коннектор переводит в штуки по размеру лота из той же котировки
Свечивсе таймфреймы, в том числе 10 минут. Брокер принимает любое число секунд, коннектор шлет 60, 300, 600, 900, 1800, 3600, 14400, D, W, M. Закрытие свечи считается как открытие плюс длина таймфрейма
Поток свечейтолько текущая свеча и следующие: история не приходит, ее читает candles
Максимум на запрос свечейв описании API не назван, candles_max_span не знает предела, и длинная история читается одним запросом, если не задать окно
Лента сделокlast_trades отдает сделки текущего дня, новейшие limit. Поток ленты не повторяет сделки, пришедшие с историей подписки
Статус торговиз кода tradingStatus инструмента: 17 и торговые периоды и аукционы это Open, 2 это Break, 18 это Closed

Как устроены команды

Команды идут по HTTP, по одному запросу, без повтора: заявка, замена и отмена. У брокера есть те же команды по WebSocket (канал /cws), но выигрыш в скорости по его словам до 5 мс, а HTTP проще и надежнее разбирается при обрыве. Канал /cws доступен через raw().connect_cws(...).

  • Отказ известен сразу: Rejected с кодом http_<статус> и текстом брокера.
  • В OrderAck приходит номер заявки брокера (orderNumber).
  • Нет ответа, обрыв, таймаут, 5xx и ответ без номера заявки это Unknown: повторов нет, выход из неизвестности - order_state и reconcile (Круг команд).
  • Отмена (DELETE) успешна, когда брокер принял запрос. Брокер отвечает до того, как биржа подтвердила отмену: подтверждение приходит событием статуса Cancelled (подписка subscribe_order_state) или чтением order_state.

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

Дважды: в заголовке X-REQID команды и в поле comment заявки, как UUID с дефисами (36 знаков, комментарий вмещает 100). Обратимо. Комментарий возвращается в списке заявок, в потоке заявок и в сделках, так cid находится в ответах.

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

Документация брокера говорит, что повторный X-REQID получает копию первого ответа и второй заявки не создает. Библиотека на это не опирается: place_idempotency = LabelOnly, а повтор того же cid она сама не отправляет (duplicate_place).

Порядок как у остальных брокеров: шлюз команд, проверка входа, размер лота (чтение справочника, если лот еще неизвестен), квота, очередь по бумаге, шлюз еще раз и только потом cid помечается использованным. После RateLimited и после ошибки входа тот же cid годен. Общее правило: Круг команд.

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

Есть: PUT лимитной заявки по номеру. Брокер снимает исходную заявку и ставит новую, ответ несет номер новой, под новым cid в комментарии. Количество и цена, которых вы не указали, берутся от исходной (одно чтение). Если заявка исполнена частично, количество нужно указать явно, иначе Rejected { qty_required }. Рыночную заявку заменить нельзя: Rejected { not_replaceable }.

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

ЧтоКак
Поток исполненийподписка на сделки портфеля: каждая сделка один раз (повторы по номеру отбрасываются), с cid заявки, если он известен. Комиссия берется из сделки (у срочного рынка брокер ее не отдает: 0)
ИсторияGET .../history/trades с даты начала диапазона и сделки сегодняшнего дня. Один ответ брокера вмещает до 1000 сделок: если диапазон заполняет страницу, это Rejected { range_too_long }, а не список, который выглядит полным
Портфельпозиции одним запросом. Деньги это позиции валют (isCurrency), коннектор отдает их балансами. Позиция брокера не называет режим торгов, коннектор один раз на бумагу читает основной режим из справочника. Закрытые позиции (нуль) не показываются. Средняя цена нуль это None
Поток портфеляподписка на позиции: сначала текущие позиции, потом изменения. События Positions и Balances
Список активных заявокзаявки дня со статусом «на исполнении»

Стоп-заявки

У брокера два вида: стоп-заявка (при срабатывании выставляется рыночная) и стоп-лимит (лимитная со своей ценой).

ЗапросУ АЛОРа
StopLoss, TakeProfit без limit_priceстоп-заявка. Условие срабатывания по стороне и виду: стоп-лосс на продажу ждет падения до цены, тейк-профит на продажу ждет роста
StopLoss, TakeProfit с limit_price, StopLimitстоп-лимит (StopLimit без limit_price это Rejected { missing_price })

Срок: «до отмены» уходит как год вперед (брокер требует время окончания), «до конца дня» это конец дня по Москве, «до даты» это дата. При чтении стоп-заявка получает вид StopLoss или TakeProfit (по стороне и условию), а стоп-лимит всегда StopLimit: брокер не хранит, какой из видов имел в виду бот. Потока стоп-заявок нет (subscribe_stop_orders отвечает Unsupported), список читает active_stop_orders. Подробно: Стоп-заявки.

Чего АЛОР не поддерживает или делает иначе

ЧтоКак
Расписание торговUnsupported("schedule"): у брокера есть только состояние рынка сейчас и код статуса инструмента, расписания сессий нет
Справочник по ISINUnsupported("find_by_isin")
Справочник по виду: OtherUnsupported. Остальные виды работают, список читается целиком: страницами по 100, пока страница полная. Каждая страница тратит квоту, а список длиннее 200 страниц это ошибка, не обрезок
Поток стоп-заявокUnsupported
Замена рыночной заявкиRejected { not_replaceable }
Айсберг-заявки, группы заявок, оценка заявки, остальные подписки (риски, сводка, инструменты)через raw()
История своих сделок длиннее 1000Rejected { range_too_long }: читайте короче
Обрыв сокета подписоквиден боту: Event::Reconnected на подписки заявок и исполнений и закрытый шлюз до reconcile, Resync на стаканы (Круг событий)

Подписки

Все подписки идут по одному WebSocket (/ws), у каждой свой guid, и ответные кадры несут тот же guid, поэтому кадр всегда относится к своей подписке. subscribe_* возвращается, когда брокер подтвердил подписку: события заявки, поставленной сразу после возврата, не потеряются. Отказ брокера внутри subscribe_ack_timeout (3 секунды по умолчанию) возвращается как Rejected { subscription_refused }, а если подтверждения нет за это время - Transport, подписка снята и вызов можно повторить. Пауза перед переподключением от 0,5 с до 30 с. Брокер разрешает до 10 соединений на пользователя и до 5000 подписок на соединение.

Лимиты

crates/alor/limits.toml: брокер называет 100 HTTP-запросов в секунду на пользователя, 10 соединений WebSocket, 5000 подписок на соединение и 5000 необработанных сообщений в буфере соединения. Библиотека держит ведро на 100 запросов в секунду для всех методов и меньшее ведро place (60 в секунду, всплеск 30) для постановки, замены и стоп-заявки: это не лимит брокера, а запас, чтобы поток заявок не занял весь бюджет и отмене осталось место. У брокера есть и непубликуемая защита («социальный рейтинг» с блокировкой логина на 2 часа, например за запрос несуществующей заявки или некорректный JSON): ее порогов в документации нет и коннектор их не считает. Не слать лишнего: чтение заявки по cid идет через список заявок дня, а не через запрос несуществующего номера. Лимит общий на логин, поэтому все коннекторы одного логина берут один BrokerLimiter.

Что учесть

  1. Единицы объема в стакане, ленте и свечах документация АЛОРа не называет (у котировок - лоты). Количество в этих данных берите как пришло.
  2. Повтор X-REQID: что сделает брокер, в документации не сказано. Коннектор команды не повторяет.
  3. Срок стоп-заявки без времени окончания и регистр значений (condition, side, timeInForce) брокер описывает неоднозначно. Задавайте срок явно.

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

brokapi by RunInfra