Git Product home page Git Product logo

Comments (29)

slavonnet avatar slavonnet commented on August 14, 2024 4

Ок. У меня в БКС сейчас роботом торгуется более 250 акций. Я вот пытаюсь переписать на ваше апи.
Мне как минимум надо получить по каждой из них статус и стакан :) И вообще как можно роботу ставить ограничения по получению данных? :) Вы же понимаете, что ограничения должны идти в рамках инструмента (или другого объекта), а не в целом по API Call :)

Очень рекомендую поставить лимиты на 120 API CALL по инструменту, а не по рынку в целом :)

from invest-openapi-java-sdk.

slavonnet avatar slavonnet commented on August 14, 2024 2

Ну и как минимум 429 статус надо в обработке ContextImpl::handleResponse добавить

from invest-openapi-java-sdk.

slavonnet avatar slavonnet commented on August 14, 2024 1

Псевдо пример хороший. Только из стрима до этого уровня прослойки не хватает в SDK. Надо Executor курочить)
И очень не хватает стрима по Orders и Portfolio для полной картины :)

from invest-openapi-java-sdk.

zlumyo avatar zlumyo commented on August 14, 2024

Интересный кейс. Попробуем для начала воспроизвести.

from invest-openapi-java-sdk.

slavonnet avatar slavonnet commented on August 14, 2024

Кейс легко воспроизводится запуском получения стакана по списку акций context.getMarketOrderbook(i.getFigi(),1).join(); более 150 раз (разных акций) в цикле (как на примере)

from invest-openapi-java-sdk.

slavonnet avatar slavonnet commented on August 14, 2024
java.util.concurrent.CompletionException: com.fasterxml.jackson.databind.exc.MismatchedInputException: No content to map due to end-of-input
 at [Source: (String)""; line: 1, column: 0]
	at java.base/java.util.concurrent.CompletableFuture.encodeRelay(CompletableFuture.java:367)
	at java.base/java.util.concurrent.CompletableFuture.completeRelay(CompletableFuture.java:376)
	at java.base/java.util.concurrent.CompletableFuture$UniCompose.tryFire(CompletableFuture.java:1074)
	at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:506)
	at java.base/java.util.concurrent.CompletableFuture.postFire(CompletableFuture.java:610)
	at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:840)
	at java.base/java.util.concurrent.CompletableFuture$Completion.exec(CompletableFuture.java:479)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
	at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
	at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
	at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:177)
Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: No content to map due to end-of-input
 at [Source: (String)""; line: 1, column: 0]
	at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)
	at com.fasterxml.jackson.databind.ObjectMapper._initForReading(ObjectMapper.java:4145)
	at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4000)
	at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3023)
	at ru.tinkoff.invest.openapi.wrapper.impl.ContextImpl.handleResponse(ContextImpl.java:326)
	at ru.tinkoff.invest.openapi.wrapper.impl.ContextImpl.lambda$sendGetRequest$17(ContextImpl.java:288)
	at java.base/java.util.concurrent.CompletableFuture$UniCompose.tryFire(CompletableFuture.java:1072)
	... 9 more

from invest-openapi-java-sdk.

NikitaMelnikov avatar NikitaMelnikov commented on August 14, 2024

В openapi добавлен rate limiting: https://tinkoffcreditsystems.github.io/invest-openapi/rest/
На весь market сейчас 120 запросов в минуту

from invest-openapi-java-sdk.

NikitaMelnikov avatar NikitaMelnikov commented on August 14, 2024

@slavonnet

Мне как минимум надо получить по каждой из них статус и стакан :)

Как часто вы обновляете данные и какой у вас кейс?

Вы же понимаете, что ограничения должны идти в рамках инструмента (или другого объекта), а не в целом по API Call

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

У нас в планах разделить лимиты по market/candles, market/orderbook и остальные, но вряд ли мы будем ставить рейты по каждому инструменту отдельно.

Как временное решение поднимем рейт-лимиты до 400 RPM

from invest-openapi-java-sdk.

slavonnet avatar slavonnet commented on August 14, 2024

Так как у вас стратегии сейчас не работают логика работы в цикле у робота такая

  1. взять портфель (200+ инструментов). For each{
  • получить стакан (для статуса и last price)
  • если статус боевой - получить Orders
  • Если Order есть - проверит не пора ли снимать и снять
  • Если Order нет - проверит пора ли ставить и выставить
    }
  1. Найти все акции которые не в портфеле и на которые нет Orders (да да, опять API Calls). Произвести закупку если есть свободные средства (API Call пересчитанных средств с учетом блокировок после каждого выставленного Order).

  2. По кругу раз в минуту.

Как видно тут много API Call. QUIK + lua без вопросов с такой задачей справляется :)

from invest-openapi-java-sdk.

NikitaMelnikov avatar NikitaMelnikov commented on August 14, 2024

Так как у вас стратегии сейчас не работают логика работы в цикле

Это пример стратегии, его не нужно использовать для запуска :)

на которые нет Orders (да да, опять API Calls).

Это будут разные лимиты https://tinkoffcreditsystems.github.io/invest-openapi/rest/

from invest-openapi-java-sdk.

slavonnet avatar slavonnet commented on August 14, 2024

Это будут разные лимиты https://tinkoffcreditsystems.github.io/invest-openapi/rest/

И все же мне по каждому инструменту в портфеле или в маркете надо получить "есть ли заявки", а потом произвести снятие заявки и/или выставление. Это в максимуме получается по 3 API CALL на инструмент.

from invest-openapi-java-sdk.

NikitaMelnikov avatar NikitaMelnikov commented on August 14, 2024

И все же мне по каждому инструменту в портфеле или в маркете надо получить "есть ли заявки",

val orders = getOrders() // limits.orders == 1
val portfolio = getPortfolio() // limits.portfolio == 1

orders.foreach { order =>
  if (...) {
    cancelAndPlaceORder() // limits.orders += 2
  }
}

Итого в максимуме мы получаем:
1 лимит в портфелях
portfolio.positions.count * 3 лимитов в ордерах, если по каждой позиции есть заявка

При этом у биржи так же есть ограничение на количество операций на клиента

from invest-openapi-java-sdk.

NikitaMelnikov avatar NikitaMelnikov commented on August 14, 2024

Опять же, в маркет ходить не обязательно, так как есть стриминг-протокол :)

from invest-openapi-java-sdk.

slavonnet avatar slavonnet commented on August 14, 2024
  1. В данном примере нет влияния результатов выполнения ордеров.
    Пока выполняется прогнока по одним инструментам, то могут быть изменения по портфелю или исполнения по ордерам. Получится не корректная работа робота. Робот должен принимать решение на основании фактических текущих данных. Для этого перед принятием решения об изменениях он должен получить актуальные данные.
    Реализовывать кеш на клиенте самостоятельно это ад :) У вас есть события по изменениям. Кешируйте на беке ответ пока событие по ордеру или инструменту об обновлении не прилетело, в чем проблема?

portfolio.positions.count * 3 лимитов в ордерах, если по каждой позиции есть заявка

плюс ордера по маркету которые еще не попали в портфель, т.к. ордер не исполнился.

from invest-openapi-java-sdk.

slavonnet avatar slavonnet commented on August 14, 2024

Опять же, в маркет ходить не обязательно, так как есть стриминг-протокол :)

Отлично было бы пример его использования в основном коде без использования стратегии.
По сути если бы по простому можно было подписаться по инструменту типа:

context.newSubscirbe(Intrument, new () {
@override onChangeOrder (Order o){
}
@override onChangePortfolio (BlaBla o){
}

})

В StrategyExecuter как пример использовать сложно, там логики "сверху" много.

from invest-openapi-java-sdk.

NikitaMelnikov avatar NikitaMelnikov commented on August 14, 2024

Я с вами полностью согласен,

Робот должен принимать решение на основании фактических текущих данных.

И этим данные есть в стриминге

Кешируйте на беке ответ пока событие по ордеру или инструменту об обновлении не прилетело, в чем проблема?

Проблемы в этом нет, есть проблема в неконтролируемом потоке запросов к REST для случаев, когда существует streaming.

from invest-openapi-java-sdk.

NikitaMelnikov avatar NikitaMelnikov commented on August 14, 2024

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

Возможно дело не в рейт-лимитах, а в неполноте документации как правильно использовать openapi и для каких случаев нужен REST?

Давайте попробуем описать ваш алгоритм словами, а я попробую сформулировать как это ложится на наш протокол? И посчитаем, хватает ли лимитов

from invest-openapi-java-sdk.

slavonnet avatar slavonnet commented on August 14, 2024

По протоколу все понятно. Вопросы больше к SDK. Сейчас streaming реализован в StrategyExecutor. А он не работает как пример с множеством инструментов. Как без него подписаться в SDK на поток не понятно, примеров нет. Если работать в лоб без потоков - упираешся в лимиты.

from invest-openapi-java-sdk.

slavonnet avatar slavonnet commented on August 14, 2024

Давайте попробуем описать ваш алгоритм словами, а я попробую сформулировать как это ложится на наш протокол? И посчитаем, хватает ли лимитов

Давайте. По сути мне при каждом изменении по инструментам из портфеля для принятия решения робота надо понимать:

  1. Есть ли активные ордера
  2. Текущие позиции по этому инструменту в портфеле
  3. Стакан, цена и статус
  4. Что общим балансом и свободными средствами на данный момент

Плюс по инструментам не в портфеле в случае наличия свободных средств:

  1. Есть ли активные ордера
  2. Стакан, цена и статус
  3. Что общим балансом и свободными средствами на данный момент

from invest-openapi-java-sdk.

NikitaMelnikov avatar NikitaMelnikov commented on August 14, 2024

А как вы выбираете инструмент, которого нет в портфеле, для торгов?

from invest-openapi-java-sdk.

slavonnet avatar slavonnet commented on August 14, 2024

Беру список акции (простые не привилегированные) ММВБ. Сортирую по Level ASC + Price DESC. Закупаю пока есть средства Рыночным ордером на количество примерно на Х рублей.

Если на рынке ММВБ все купил (а сейчас именно так), то иду в акции СПБ. Алгоритм тот же.

from invest-openapi-java-sdk.

zlumyo avatar zlumyo commented on August 14, 2024

В StrategyExecuter как пример использовать сложно, там логики "сверху" много.

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

context.newSubscirbe(Intrument, new () {
@override onChangeOrder (Order o){
}
@override onChangePortfolio (BlaBla o){
}

})

очень приглянулся. Допускаю, что это станет ориентиром при переработке StrategyExecutor.

from invest-openapi-java-sdk.

NikitaMelnikov avatar NikitaMelnikov commented on August 14, 2024

@zlumyo а откуда ты получаешь onChangePortfolio? У нас нет клиентских стримов, только общие по рынку

from invest-openapi-java-sdk.

NikitaMelnikov avatar NikitaMelnikov commented on August 14, 2024

Накидал псевдокод как работать с rest + stream в варианте работы с портфелем

class Strategy(api: OpenApi, stream: OpenApiStreaming) {
    val portfolio = new AtomicReference[Portfolio]()
    val orderbook = new ConcurrentHashMap[Figi, Prices]
    val investumentInfo = new ConcurrentHashMap[Figi, Info]
    val orders = new AtomicReference[Orders]

    def initialize() = {
        val portfolio = api.getPortfolio()
        val balance = api.getBalance()
        val orders = api.getOrders()

        stream.subscribe("orderbook", portfolio.positions.figies) { event => 
            orderbook.update(event.figi, event.prices)

            onPrice(orderbook.get(figi), event)
        }

        stream.subscribe("instrument_info", portfolio.positions.figies) { event => 
            investumentInfo.update(event.figi, event.info)

            onInstrumentInfo(investumentInfo.get(figi), event)
        }
    }

    def update() = {
        val portfolio = api.getPortfolio()
        val balance = api.getBalance()
        val orders = api.getOrders()
    }

    
    def onPrice(old: Prices, new: Prices) = {
        // Тут можно реагировать на цены инструментов в портфеле
    }

    def onInstrumentInfo(old: Info, new: Info) = {
        // Тут можно реагировать на изменение статуса инструмента
    }

    def placeOrder() = {
        // Тут можно обработать действия с портфелем

        update() // А после обновить информацию
    }
}

from invest-openapi-java-sdk.

NikitaMelnikov avatar NikitaMelnikov commented on August 14, 2024

По мониторингу рынка сегодня сделали тикет: https://github.com/TinkoffCreditSystems/invest-openapi/issues/41

Попробуем реализовать

from invest-openapi-java-sdk.

zlumyo avatar zlumyo commented on August 14, 2024

@NikitaMelnikov если мы хотим минимизировать количество запросов по Portfolio (при отсутствии стрима по нему), то придётся локально следить за изменениями в портфеле.

from invest-openapi-java-sdk.

slavonnet avatar slavonnet commented on August 14, 2024

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

new Order(Instrument, type, operation, q, price).Post(
onSuceesPost-> {}
onFailedPost-> {}
onComplited-> {}
onPartComplited-> {}
onDeleted-> {}

from invest-openapi-java-sdk.

NikitaMelnikov avatar NikitaMelnikov commented on August 14, 2024

И очень не хватает стрима по Orders и Portfolio для полной картины :)

Согласен, https://github.com/TinkoffCreditSystems/invest-openapi/issues/43

from invest-openapi-java-sdk.

zlumyo avatar zlumyo commented on August 14, 2024

Изначальная суть вопроса потеряла актуальность. Предложения по архитектуре представлены в других issues.

from invest-openapi-java-sdk.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.