Tinkoff / invest-openapi

Документация для Тинькофф Инвестиции OpenApi
https://tinkoff.github.io/invest-openapi/
456 stars 52 forks source link

Выставление лимитной не работает как надо. #345

Closed Kirill-Znamenskiy closed 4 years ago

Kirill-Znamenskiy commented 4 years ago

выставляю заявку на продажу:

POST /openapi/orders/limit-order?figi=BBG000BBJQV0 HTTP/1.1
Content-Length: 44
User-Agent: GuzzleHttp/6.5.5 curl/7.64.0 PHP/7.3.19-1~deb10u1
Host: api-invest.tinkoff.ru
Date: Fri, 04 Sep 2020 07:14:59 GMT
Authorization: Bearer t.xxx
Content-Type: application/json;charset=UTF-8
Accept: application/json

{"operation":"Sell","lots":2,"price":499.45}
HTTP/1.1 500 Internal Server Error
Server: nginx
Date: Fri, 04 Sep 2020 07:15:19 GMT
Transfer-Encoding: chunked
Cache-Control: no-store, no-cache, must-revalidate

500я ошибка - значит заявка не выставилась, но проверяю что там в заявках:

GET /openapi/orders HTTP/1.1
User-Agent: GuzzleHttp/6.5.5 curl/7.64.0 PHP/7.3.19-1~deb10u1
Host: api-invest.tinkoff.ru
Date: Fri, 04 Sep 2020 07:15:19 GMT
Authorization: Bearer t.xxx
Content-Type: application/json;charset=UTF-8
Accept: application/json
HTTP/1.1 200 OK
Server: nginx
Date: Fri, 04 Sep 2020 07:15:29 GMT
Content-Type: application/json
Content-Length: 947
Vary: Accept-Encoding, Accept-Encoding
Cache-Control: no-store, no-cache, must-revalidate
access-control-allow-methods: GET,HEAD,POST,DELETE,OPTIONS,PUT,PATCH
access-control-allow-headers: accept, content-type, authorization, access-control-allow-headers, x-requested-with
access-control-allow-origin: *

{"trackingId":"afc00db09de9bff7","payload":[{"orderId":"21138982598","figi":"BBG00178PGX3","operation":"Sell","status":"New","requestedLots":10,"executedLots":0,"price":2283.8,"type":"Limit"},{"orderId":"157680256620","figi":"BBG000BJF1Z8","operation":"Sell","status":"New","requestedLots":4,"executedLots":0,"price":220.54,"type":"Limit"},{"orderId":"157679612100","figi":"BBG000R7Z112","operation":"Sell","status":"New","requestedLots":25,"executedLots":0,"price":31.04,"type":"Limit"},{"orderId":"157679377790","figi":"BBG000BBQCY0","operation":"Sell","status":"New","requestedLots":10,"executedLots":0,"price":80.26,"type":"Limit"},{"orderId":"21137733303","figi":"BBG00K53FX22","operation":"Buy","status":"New","requestedLots":30,"executedLots":0,"price":1051.41,"type":"Limit"},{"orderId":"21137732847","figi":"BBG00K53FX22","operation":"Buy","status":"New","requestedLots":10,"executedLots":0,"price":1073.09,"type":"Limit"}],"status":"Ok"}

там этой заявки нет, там вообще ничего по этому figi нет, соответственно логично предполагаю что заявка не выставилась, выставляю повторно:

POST /openapi/orders/limit-order?figi=BBG000BBJQV0 HTTP/1.1
Content-Length: 44
User-Agent: GuzzleHttp/6.5.5 curl/7.64.0 PHP/7.3.19-1~deb10u1
Host: api-invest.tinkoff.ru
Date: Fri, 04 Sep 2020 07:15:29 GMT
Authorization: Bearer t.xxx
Content-Type: application/json;charset=UTF-8
Accept: application/json

{"operation":"Sell","lots":2,"price":499.45}
HTTP/1.1 500 Internal Server Error
Server: nginx
Date: Fri, 04 Sep 2020 07:15:49 GMT
Transfer-Encoding: chunked
Cache-Control: no-store, no-cache, must-revalidate

и снова 500я ошибка - значит наверно система у вас сломалась, так что не буду торопиться, снова посмотрю что там в заявках:

GET /openapi/orders HTTP/1.1
User-Agent: GuzzleHttp/6.5.5 curl/7.64.0 PHP/7.3.19-1~deb10u1
Host: api-invest.tinkoff.ru
Date: Fri, 04 Sep 2020 07:15:49 GMT
Authorization: Bearer t.xxx
Content-Type: application/json;charset=UTF-8
Accept: application/json
HTTP/1.1 200 OK
Server: nginx
Date: Fri, 04 Sep 2020 07:15:58 GMT
Content-Type: application/json
Content-Length: 947
Vary: Accept-Encoding, Accept-Encoding
Cache-Control: no-store, no-cache, must-revalidate
access-control-allow-methods: GET,HEAD,POST,DELETE,OPTIONS,PUT,PATCH
access-control-allow-headers: accept, content-type, authorization, access-control-allow-headers, x-requested-with
access-control-allow-origin: *

{"trackingId":"8fdee511026eef6a","payload":[{"orderId":"21138982598","figi":"BBG00178PGX3","operation":"Sell","status":"New","requestedLots":10,"executedLots":0,"price":2283.8,"type":"Limit"},{"orderId":"157680256620","figi":"BBG000BJF1Z8","operation":"Sell","status":"New","requestedLots":4,"executedLots":0,"price":220.54,"type":"Limit"},{"orderId":"157679612100","figi":"BBG000R7Z112","operation":"Sell","status":"New","requestedLots":25,"executedLots":0,"price":31.04,"type":"Limit"},{"orderId":"157679377790","figi":"BBG000BBQCY0","operation":"Sell","status":"New","requestedLots":10,"executedLots":0,"price":80.26,"type":"Limit"},{"orderId":"21137733303","figi":"BBG00K53FX22","operation":"Buy","status":"New","requestedLots":30,"executedLots":0,"price":1051.41,"type":"Limit"},{"orderId":"21137732847","figi":"BBG00K53FX22","operation":"Buy","status":"New","requestedLots":10,"executedLots":0,"price":1073.09,"type":"Limit"}],"status":"Ok"}

снова ничего нет, а продать то нужно! - снова выставляю заявку:

POST /openapi/orders/limit-order?figi=BBG000BBJQV0 HTTP/1.1
Content-Length: 44
User-Agent: GuzzleHttp/6.5.5 curl/7.64.0 PHP/7.3.19-1~deb10u1
Host: api-invest.tinkoff.ru
Date: Fri, 04 Sep 2020 07:15:59 GMT
Authorization: Bearer t.xxx
Content-Type: application/json;charset=UTF-8
Accept: application/json

{"operation":"Sell","lots":2,"price":499.45}
HTTP/1.1 200 OK
Server: nginx
Date: Fri, 04 Sep 2020 07:16:17 GMT
Content-Type: application/json
Content-Length: 195
Cache-Control: no-store, no-cache, must-revalidate
access-control-allow-methods: GET,HEAD,POST,DELETE,OPTIONS,PUT,PATCH
access-control-allow-headers: accept, content-type, authorization, access-control-allow-headers, x-requested-with
access-control-allow-origin: *

{"trackingId":"d218eae9fd2049dd","payload":{"orderId":"157682571540","operation":"Sell","status":"New","requestedLots":2,"executedLots":0,"commission":{"currency":"USD","value":0}},"status":"Ok"}

юхуу! есть ответ! заявка успешно выставилась!

а теперь самое интересное! что же в операциях:

GET /openapi/operations?from=2020-09-04T07%3A10%3A00Z&to=2020-09-04T09%3A00%3A00Z&figi=BBG000BBJQV0 HTTP/1.1
User-Agent: GuzzleHttp/6.5.5 curl/7.64.0 PHP/7.3.14-1~deb10u1
Host: api-invest.tinkoff.ru
Date: Fri, 04 Sep 2020 11:32:27 GMT
Authorization: Bearer t.xxx
Content-Type: application/json;charset=UTF-8
Accept: application/json
HTTP/1.1 200 OK
Server: nginx
Date: Fri, 04 Sep 2020 11:32:31 GMT
Content-Type: application/json
Content-Length: 32369
Vary: Accept-Encoding, Accept-Encoding
Cache-Control: no-store, no-cache, must-revalidate
access-control-allow-methods: GET,HEAD,POST,DELETE,OPTIONS,PUT,PATCH
access-control-allow-headers: accept, content-type, authorization, access-control-allow-headers, x-requested-with
access-control-allow-origin: *

{
  "trackingId": "fa86d0a3bd92146b",
  "payload": {
    "operations": [
      {
        "operationType": "Buy",
        "date": "2020-09-04T10:37:04.997868+03:00",
        "isMarginCall": false,
        "instrumentType": "Stock",
        "figi": "BBG000BBJQV0",
        "quantity": 4,
        "quantityExecuted": 4,
        "price": 517.09,
        "payment": -2068.36,
        "currency": "USD",
        "trades": [
          {
            "tradeId": "1423194870",
            "date": "2020-09-04T10:37:08.028995+03:00",
            "quantity": 4,
            "price": 517.09
          }
        ],
        "status": "Done",
        "id": "157705911750"
      },
      {
        "operationType": "Buy",
        "date": "2020-09-04T10:18:39.270707+03:00",
        "isMarginCall": false,
        "instrumentType": "Stock",
        "figi": "BBG000BBJQV0",
        "quantity": 4,
        "quantityExecuted": 0,
        "price": 485.31,
        "payment": 0,
        "currency": "USD",
        "status": "Decline",
        "id": "157685132050"
      },
      {
        "operationType": "Sell",
        "date": "2020-09-04T10:16:18.980663+03:00",
        "isMarginCall": false,
        "instrumentType": "Stock",
        "figi": "BBG000BBJQV0",
        "quantity": 2,
        "quantityExecuted": 2,
        "price": 502,
        "payment": 1004,
        "currency": "USD",
        "trades": [
          {
            "tradeId": "1422687420",
            "date": "2020-09-04T10:16:18.980663+03:00",
            "quantity": 1,
            "price": 502
          },
          {
            "tradeId": "1422687430",
            "date": "2020-09-04T10:16:18.980663+03:00",
            "quantity": 1,
            "price": 502
          }
        ],
        "status": "Done",
        "id": "157682577300"
      },
      {
        "operationType": "Sell",
        "date": "2020-09-04T10:16:18.015954+03:00",
        "isMarginCall": false,
        "instrumentType": "Stock",
        "figi": "BBG000BBJQV0",
        "quantity": 2,
        "quantityExecuted": 2,
        "price": 502.05,
        "payment": 1004.1,
        "currency": "USD",
        "trades": [
          {
            "tradeId": "1422683840",
            "date": "2020-09-04T10:16:18.015954+03:00",
            "quantity": 1,
            "price": 502
          },
          {
            "tradeId": "1422683830",
            "date": "2020-09-04T10:16:18.015954+03:00",
            "quantity": 1,
            "price": 502.1
          }
        ],
        "status": "Done",
        "id": "157682571540"
      },
      {
        "operationType": "Sell",
        "date": "2020-09-04T10:15:24.586336+03:00",
        "isMarginCall": false,
        "instrumentType": "Stock",
        "figi": "BBG000BBJQV0",
        "quantity": 2,
        "quantityExecuted": 2,
        "price": 501.11,
        "payment": 1002.22,
        "currency": "USD",
        "trades": [
          {
            "tradeId": "1422655430",
            "date": "2020-09-04T10:15:24.586336+03:00",
            "quantity": 2,
            "price": 501.11
          }
        ],
        "status": "Done",
        "id": "157681894990"
      }
    ]
  },
  "status": "Ok"
}

если коротко - все 3 заявки были выставлены и все 3 были исполены! в итоге в портфеле появилось -4шт. позиции, которая мне совершенно была не нужна! пришлось закрыть эту позицию в минус по стоп-лосу, потерял на этом $60.26

По-сути получается не работает самый основной, базовых механизм - выставление лимитной заявки. Впервые я оформил тикет по этой проблеме еще 5 июня (https://github.com/TinkoffCreditSystems/invest-openapi/issues/239) и там же мы с вами обсудили варианты решения. С тех пор ничего не поменялось...

В связи с этим вопрос: когда уже наконец-то произойдут хоть какие-то изменения в сторону стабильности и предсказуемости работы api?

P.S. Начиная с этого раза буду создавать тикет по каждому случаю и требовать компенсацию через поддержку. Считаю что тут такая же проблема вашей системы как и при недавних открытиях позиций по AAPL и TSLA. Надеюсь вопрос о компенсациях простимулирует положительные изменения.

Fatal1ty commented 4 years ago

если коротко - все 3 заявки были выставлены и все 3 были исполены!

Хуже будет, когда запрос на лимитную продажу сработает, апи вернет ошибку, а операции новые появятся не сразу, а через несколько минут 😁 Тут, как вариант, можно смотреть на изменение портфеля, но я не уверен, сразу ли там изменения отражаются после продажи или могут запаздывать.

Kirill-Znamenskiy commented 4 years ago

Хуже будет, когда запрос на лимитную продажу сработает, апи вернет ошибку, а операции новые появятся не сразу, а через несколько минут

В смысле будет хуже) ровно так и произошло)

В тикете https://github.com/TinkoffCreditSystems/invest-openapi/issues/239 там подробно уже разобрали мы все эти проблемы и ситуации, еще в июне. Коротко итог - без изменений со стороны апи ничего невозможно сделать, к сожалению :((

Fatal1ty commented 4 years ago

В смысле будет хуже) ровно так и произошло)

Я просто из описания понял, что за операциями пошли уже после успешного выполнения запроса на создание лимитной заявки, а туда желательно ходить почаще :)

Kirill-Znamenskiy commented 4 years ago

Ну там такая ситуация что именно на операции совершенно точно нельзя полагаться в реальном времени, они прям очень часто с задержками. Еще в июне это выяснилось вот)

NikitaMelnikov commented 4 years ago

Добрый день, мы работаем над улучшением скорости отображения заявок в операциях, так же как и над летенси выставления лимитных заявок, но, к сожалению, не всегда все зависит от нас. Ключ идемпотентности возможно поможет, но так же не спасет, от случая таймаута от биржи, когда непонятно для нас выставилась заявка или нет

Kirill-Znamenskiy commented 4 years ago

@NikitaMelnikov, возможность получить все заявки, в том числи и исполненные, эту ситуацию предотвратило бы. Уверен у вас есть возможность получать их от биржи, но нам вы их никак не отдаете, и вот это уже именно ваше решение, а значит и ваша ответственность. Если бы вы транслировали все все данные которые от биржи получаете - было бы идеально.

Fatal1ty commented 4 years ago

Нужны всего лишь два статуса: "создано в Тинькофф и ожидает создания на бирже" и "создано в бирже". По первому статусу уже можно будет определить, что запрос на создание лимитной заявки через API был и повторно делать не надо.

Кажется, что для этого как раз и предназначены существующие статусы PendingNew и New. Осталось только отдавать заявки с этими статусами.

ddmrtc commented 4 years ago

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

@NikitaMelnikov улучшение скорости появление заявок в операциях уже довольно заметно, теперь get /portfolio не успевает за этим, т.е. путь:

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

NikitaMelnikov commented 4 years ago

@Fatal1ty вы правы, но не всегда техническая реализация интеграции позволяет так сделать, поэтому данные по PendingNew могут быть не консистентны в определенных случаях.

NikitaMelnikov commented 4 years ago

@ddmrtc биржа по-умолчанию работает асинхронно, мы прорабатываем вопрос стрима событий по вашему счету, тогда получение события из него ответит на вопрос, что данные в портфеле изменились