invest-openapi icon indicating copy to clipboard operation
invest-openapi copied to clipboard

Максимальное количество данных в ответе GET /market/candles/

Open konstunn opened this issue 4 years ago • 30 comments

Добрый день.

Например, я хочу получить большой массив данных исторических свечей с высокой гранулярностью. За 1 год и интервалом в час. Получаю ответ 500 типа

HTTP response body: {"trackingId":"9984e02119807c7f","payload":{"message":"[to]: Bad candle interval: from=2019-03-06T16:00:00Z to=2020-03-05T16:00:00Z expected from 1 hour to 7 days","code":"VALIDATION_ERROR"},"status":"Error"}

Указал я интервал 1 час. В ответе говорится expected from 1 hour to 7 days. Но я и так ведь указал 1 час. В чем проблема?

Гранулярность данных слишком высокая, да, но вопрос более в другом. Как определить максимальный объем выборки, которую я могу получить за один запрос? - Чтобы я смог отмерить и получить необходимые мне данные в несколько запросов.

Спасибо.

konstunn avatar Mar 05 '20 15:03 konstunn

curl -s https://tinkoffcreditsystems.github.io/invest-openapi/swagger-ui/swagger.yaml | yq -r '.components.schemas.CandleResolution.description'

Интервал свечи и допустимый промежуток запроса:
- 1min [1 minute, 1 day]
- 2min [2 minutes, 1 day]
- 3min [3 minutes, 1 day]
- 5min [5 minutes, 1 day]
- 10min [10 minutes, 1 day]
- 15min [15 minutes, 1 day]
- 30min [30 minutes, 1 day]
- hour [1 hour, 7 days]
- day [1 day, 1 year]
- week [7 days, 2 years]
- month [1 month, 10 years]

triamazikamno avatar Mar 05 '20 15:03 triamazikamno

curl -s https://tinkoffcreditsystems.github.io/invest-openapi/swagger-ui/swagger.yaml | yq -r '.components.schemas.CandleResolution.description'

Интервал свечи и допустимый промежуток запроса:
- 1min [1 minute, 1 day]
- 2min [2 minutes, 1 day]
- 3min [3 minutes, 1 day]
- 5min [5 minutes, 1 day]
- 10min [10 minutes, 1 day]
- 15min [15 minutes, 1 day]
- 30min [30 minutes, 1 day]
- hour [1 hour, 7 days]
- day [1 day, 1 year]
- week [7 days, 2 years]
- month [1 month, 10 years]

Я правильно понимаю, что не смогу загрузить минутный график глубиной больше, чем сутки? Что делать, если мне нужны минуты за несколько последних лет?

felixrap avatar Mar 05 '20 15:03 felixrap

Это можно сделать слепив 365 запросов :)

triamazikamno avatar Mar 05 '20 16:03 triamazikamno

Тогда еще очень в тему будет вопрос про rate-limit: 120 запросов в 60 секунд. А как это время распределено? - Значит ли это, что между запросами должно быть не менее 0.5 секунд?

К сути: как организовывать таймауты и повторы? Например, поток выполняет запрос, получает ответ 429 (Too Many Requets) - сколько ему ждать до того как попробовать снова? И инкрементирует ли счетчик запросов rate-limit тот запрос, на который был получен ответ 429?

konstunn avatar Mar 05 '20 16:03 konstunn

Лимиты считаются внутри минуты, т.е. если первый запрос был в 10:01:10, то новая минута будет отсчитываться с 10:02:10. Временной промежуток между запросами не нужно соблюдать, т.е. можно все 120 запросов отправить за 1 секунду, просто потом подождать минуту чтобы сбросились лимиты

NikitaMelnikov avatar Mar 06 '20 07:03 NikitaMelnikov

И инкрементирует ли счетчик запросов rate-limit тот запрос, на который был получен ответ 429?

Нет, но если сильно нагружать сервис, то может сработать защита и ваш IP будет заблокирован для работы с OpenApi на некоторое время

NikitaMelnikov avatar Mar 06 '20 07:03 NikitaMelnikov

Тогда еще очень в тему будет вопрос про rate-limit: 120 запросов в 60 секунд. А как это время распределено? - Значит ли это, что между запросами должно быть не менее 0.5 секунд?

К сути: как организовывать таймауты и повторы? Например, поток выполняет запрос, получает ответ 429 (Too Many Requets) - сколько ему ждать до того как попробовать снова? И инкрементирует ли счетчик запросов rate-limit тот запрос, на который был получен ответ 429?

Про организацию таймаутов: для тех, кто (как я) пишет на NodeJS+axios есть пакет axios-rate-limit. Уверен, для вашего окружения тоже найдется неплохое готовое решение.

nshaikhinurov avatar Mar 09 '20 11:03 nshaikhinurov

Это можно сделать слепив 365 запросов :)

Попробовал в цикле вызывать Optional<HistoricalCandles> candsHist = ca.createApi().getMarketContext().getMarketCandles(fig, past, now, CandleInterval.ONE_MIN).join(); за последний месяц и, похоже, получаю блок от сервера: Exception in thread "main" java.util.concurrent.CompletionException: java.net.SocketTimeoutException: Connect timed out

Отпускает только примерно через час, на дает с api работать.

felixrap avatar Mar 16 '20 08:03 felixrap

@felixrap так и есть, можно упереться в жесткие лимиты, по ним происходит блокировка IP

NikitaMelnikov avatar Mar 16 '20 13:03 NikitaMelnikov

@felixrap так и есть, можно упереться в жесткие лимиты, по ним происходит блокировка IP

Как тогда можно получить минутный график например за год? Если ли какое-то описание лимитов?

felixrap avatar Mar 16 '20 13:03 felixrap

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

Можно считать число вызовов функции за минуту и если это число стало 120, след. вызов блочить, задерживать до конца минуты.

Можно при получении ответа с кодом 429 брать таймаут, с каждым ответом 429 увеличивая этот таймаут вдвое или втрое (до какого-то лимита, в 60 или 120 секунд, например), потом пробовать снова.

konstunn avatar Mar 16 '20 14:03 konstunn

@felixrap запросить 120 дней, подождать минуту, запросить следующие 120 дней

https://tinkoffcreditsystems.github.io/invest-openapi/rest/

NikitaMelnikov avatar Mar 18 '20 13:03 NikitaMelnikov

@felixrap запросить 120 дней, подождать минуту, запросить следующие 120 дней

https://tinkoffcreditsystems.github.io/invest-openapi/rest/

А если я работаю с 30 бумагами? Это полчаса только чтобы собрать данные. А если бумаг больше, то дополнять по ним данные из стриминга не получится из-за ограничения в 6 потоков - просто не будет успевать оббегать всё.

felixrap avatar Mar 22 '20 11:03 felixrap

@felixrap кешируйте данные. В итоге у вас будет всего 30 запросов на 30 бумаг на текущий день

mvkasatkin avatar Mar 23 '20 15:03 mvkasatkin

@NikitaMelnikov Возможно баг. На week указано 2 года:

  • week [7 days, 2 years]

Но при dateFrom = subYears(new Date(), 2) - выдает 500 ошибку (превышен диапазон). Вероятно из-за високосного года? Если отнимать от текущей даты не годы а дни (~700+), то всё ок.

mvkasatkin avatar Mar 25 '20 05:03 mvkasatkin

Свой вопрос переношу сюда.

По спецификации увидел ограничения на получение исторических данных:

Ограничение на временной диапазон (1 день для 1-30 минуток) Ограничение на кол-во запросов в минуту (120)

Если мне изначально нужно получить, например, 40 ликвидных тикеров ММВБ на 15-и минутках, то их получить можно только частями.

Изначально мы не знаем, с какой даты брать тикеры. Обычно, берут с начала эпохи UNIX 01.01.1970. Получается, что для каждого тикера нужно сделать 18000+ запросов. Если в минуту можно посылать не более 120 запросов, то начальное получение исторических данных на каждый тикер будет занимать более 2.5 часов.

Непонятно, как работать скринерами. На акциях США скринер может просматривать тысячи тикеров раз в период. Т.е. ему нужно, например, раз в 15 минут получить 1 новую свечку для 1000 тикеров. Также будет ошибка.

Может, как-то изменить ограничения?

cia76 avatar Mar 25 '20 16:03 cia76

@cia76 исторические данные раньше 2013 года мы не предоставляем, если я правильно помню, поэтому с 1970 смысла нет искать.

Рекомендую на своей стороне просто ставить ограничение на количество запросов и ждать минуту после 120 запросов

NikitaMelnikov avatar Mar 26 '20 09:03 NikitaMelnikov

Как уже говорил, есть 2 ситуации, когда ограничения становятся узким местом:

  1. Начальное получение истории
  2. Массовое получение последнего бара для 120+ тикеров

Минутки Сбербанка с 2013 года. 7.25 года. В каждом годе около 200 торговых дней. Минимум, 12 минут на получение тикера. Если таких тикеров взять 30, то получим более 6-и часов, чтобы получить исходные данные.

На тех же минутках получаем только последний бар для 1000+ тикеров акций США. За минуту мы можем получить только 120 обновлений. Как насчет остальных? Для автоторговли нам нужна последняя минутка по всем тикерам.

Далее мои мысли.

Если ничего в ограничениях не менять, то смысла в разработке и поддержке получения исторических данных нет. Например, Алор в Atentis так и сделали. Берите исторические данные где хотите, но не у нас. Мы не будем заморачиваться с нагрузкой, обработкой и хранением.

Без ограничений все исторические данные подтягиваются в TRANSAQ (Финам) и Квик (все брокеры). Раз другие системы позволяют получать всю историю без ограничений и работают стабильно, то, может, и вы сможете?

Все ограничения API описал здесь: https://chechet.org/355 Провайдер автоторговли для Wealth-Lab Тинькофф Инвестиции уже выдаю трейдерам. Но, не думаю, что с такими ограничениями трейдеры будут переходить от связки с Квиком на вас. Хотя ваша разработка на голову выше того же Квика.

cia76 avatar Mar 27 '20 03:03 cia76

Поддерживаю @cia76. Если получение исторических данных еще можно (и нужно) решить локальным кешированием, то получение текущей цены по >120 тикерам - это уже проблема. Было бы хорошо иметь возможность массового получения текущего OHLCV по многим тикерам. А в идеале весь intraday по определенному набору тикеров. Помимо удобства, это разгрузит ваш апи от большого количества запросов.

mvkasatkin avatar Mar 27 '20 04:03 mvkasatkin

@NikitaMelnikov можете ли вы подтвердить, что в качестве альтернативы ежеминутного получения последней цены >120 акций - это подписаться через ws на 100-200-300 тикеров - это нормально и не будет ограничено какими-либо лимитами?

mvkasatkin avatar Mar 29 '20 07:03 mvkasatkin

В разработке новые инструменты для скринеров, пока что не могу назвать даты

NikitaMelnikov avatar Mar 30 '20 10:03 NikitaMelnikov

mvkasatkin

можете ли вы подтвердить, ...

да, в стриминге можно подписываться на неограниченное число инструментов, но лучше распределить общее число по 6 соединениям

lightning95 avatar May 25 '20 05:05 lightning95

@konstunn остались ли у вас какие-то вопросы?

lightning95 avatar May 25 '20 06:05 lightning95

но лучше распределить общее число по 6 соединениям

Можете, пожалуйста, пояснить, чем лучше распределение по 6 соединениям вместо одного?

olsh avatar May 25 '20 07:05 olsh

Я не разработчик API, но могу предположить, что когда ты установишь 6 Websocket соединений, то они с большой вероятностью будут подключены к разным backend серверам и так нагрузка на них будет распределяться более равномерно.

Представь, если ты через один коннект подпишешься на 1000 стоков. Потом приду я и тоже подпишусь на 1000 стоков в одном конннекте. Если оба этих коннекта попадут на один и тот же сервер, то на нём будет нагрузка в 2000 подписок, а на остальные N серверов – нулевая.

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

svetlyak40wt avatar May 25 '20 07:05 svetlyak40wt

Если оба этих коннекта попадут на один и тот же сервер, то на нём будет нагрузка в 2000 подписок, а на остальные N серверов – нулевая.

Ну наши 2 подключения никак не связаны, это как раз задача балансера раскидать подключения по остальным серверам чтобы не было нулевой нагрузки. Что серверу раскидывать 2 подключения что 12 разницы особо нет. К тому же соединение, даже без трафика, тоже не бесплатное. 12 соединений, дороже чем 2, могу предположить, что лимит в 6 соединений на токен раз из-за этого.

Ну и меня, в целом больше инетересует вопрос с точки зрения пользователя API, инфраструктура, не мое дело.

olsh avatar May 25 '20 08:05 olsh

@cia76 исторические данные раньше 2013 года мы не предоставляем, если я правильно помню, поэтому с 1970 смысла нет искать.

Хотелось бы всё-таки узнать конкретную дату начала котировок. Точно не 2013-й год. Например по тикеру "Т" получил с 2001 г. совпадает с данными яхо финанса.

kitMP avatar Jul 23 '20 15:07 kitMP

Через терминал выяснил, что для T дата - сентябрь 1988. В API выдаётся начиная с октября 1988. IPO AT&T случилось 19-го июля 1984-го года.
На мой взгляд, для инструментов стоит добавить поле - дату начала исторических данных.

kitMP avatar Jul 23 '20 15:07 kitMP

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

Хорошее предложение, рассмотрим

NikitaMelnikov avatar Jul 24 '20 08:07 NikitaMelnikov

Сейчас для многих бумаг торгующихся на SPB бирже (AAPL, MSFT например) история по минутным свечам ограничена до 2018-01-23. По MSK бирже последний день 2018-07-03, проверял на DSKY. Это баг или фича? Если фича, может быть стоит добавить в документацию?

olsh avatar Dec 16 '21 12:12 olsh