From e5d9f6e35fdc370be6e5e9f572d015fd217a6a20 Mon Sep 17 00:00:00 2001 From: python-invest Date: Thu, 10 Oct 2024 23:10:04 +0300 Subject: [PATCH] feat: auto generating contracts --- __init__.py | 0 base_service.py | 6 + examples/stream_client.py | 7 +- poetry.lock | 59 +- pyproject.toml | 1 + scripts/generate_models.py | 16 + tinkoff/invest/grpc/common.py | 100 ++ .../invest/grpc/google/api/field_behavior.py | 12 + tinkoff/invest/grpc/instruments.py | 1477 +++++++++++++++++ tinkoff/invest/grpc/marketdata.py | 644 +++++++ tinkoff/invest/grpc/operations.py | 615 +++++++ tinkoff/invest/grpc/orders.py | 441 +++++ tinkoff/invest/grpc/sandbox.py | 192 +++ tinkoff/invest/grpc/stoporders.py | 188 +++ tinkoff/invest/grpc/users.py | 145 ++ tinkoff/invest/services.py | 6 +- 16 files changed, 3903 insertions(+), 6 deletions(-) create mode 100644 __init__.py create mode 100644 base_service.py create mode 100644 scripts/generate_models.py create mode 100644 tinkoff/invest/grpc/common.py create mode 100644 tinkoff/invest/grpc/google/api/field_behavior.py create mode 100644 tinkoff/invest/grpc/instruments.py create mode 100644 tinkoff/invest/grpc/marketdata.py create mode 100644 tinkoff/invest/grpc/operations.py create mode 100644 tinkoff/invest/grpc/orders.py create mode 100644 tinkoff/invest/grpc/sandbox.py create mode 100644 tinkoff/invest/grpc/stoporders.py create mode 100644 tinkoff/invest/grpc/users.py diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/base_service.py b/base_service.py new file mode 100644 index 0000000..bbc5b1f --- /dev/null +++ b/base_service.py @@ -0,0 +1,6 @@ +class BaseService: + _protobuf_stub = None + + def __init__(self, channel, metadata): + self._stub = self._protobuf_stub(channel) + self._metadata = metadata diff --git a/examples/stream_client.py b/examples/stream_client.py index 0008f79..ef00fad 100644 --- a/examples/stream_client.py +++ b/examples/stream_client.py @@ -1,9 +1,9 @@ import os import time -from tinkoff.invest import ( +from tinkoff.invest import Client +from tinkoff.invest.grpc.marketdata import ( CandleInstrument, - Client, MarketDataRequest, SubscribeCandlesRequest, SubscriptionAction, @@ -23,6 +23,7 @@ def request_iterator(): CandleInstrument( figi="BBG004730N88", interval=SubscriptionInterval.SUBSCRIPTION_INTERVAL_ONE_MINUTE, + instrument_id="BBG004730N88", ) ], ) @@ -31,7 +32,7 @@ def request_iterator(): time.sleep(1) with Client(TOKEN) as client: - for marketdata in client.market_data_stream.market_data_stream( + for marketdata in client.market_data_stream.MarketDataStream( request_iterator() ): print(marketdata) diff --git a/poetry.lock b/poetry.lock index 64d1724..3e1f301 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,15 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. + +[[package]] +name = "antlr4-python3-runtime" +version = "4.13.2" +description = "ANTLR 4.13.2 runtime for Python 3" +optional = false +python-versions = "*" +files = [ + {file = "antlr4_python3_runtime-4.13.2-py3-none-any.whl", hash = "sha256:fe3835eb8d33daece0e799090eda89719dbccee7aa39ef94eed3818cafa5a7e8"}, + {file = "antlr4_python3_runtime-4.13.2.tar.gz", hash = "sha256:909b647e1d2fc2b70180ac586df3933e38919c85f98ccc656a96cd3f25ef3916"}, +] [[package]] name = "appnope" @@ -11,6 +22,17 @@ files = [ {file = "appnope-0.1.3.tar.gz", hash = "sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24"}, ] +[[package]] +name = "astor" +version = "0.8.1" +description = "Read/rewrite/write Python ASTs" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +files = [ + {file = "astor-0.8.1-py2.py3-none-any.whl", hash = "sha256:070a54e890cefb5b3739d19f30f5a5ec840ffc9c50ffa7d23cc9fc1a38ebbfc5"}, + {file = "astor-0.8.1.tar.gz", hash = "sha256:6a6effda93f4e1ce9f618779b2dd1d9d84f1e32812c23a29b3fff6fd7f63fa5e"}, +] + [[package]] name = "asttokens" version = "2.4.1" @@ -845,6 +867,24 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] +[[package]] +name = "iprotopy" +version = "0.3.0" +description = "" +optional = false +python-versions = "<4.0.0,>=3.8" +files = [ + {file = "iprotopy-0.3.0-py3-none-any.whl", hash = "sha256:bd7baa564e40ad583e10ab439f6eae631a3fa6f45390d1a1a6f4bce957d0cdd7"}, + {file = "iprotopy-0.3.0.tar.gz", hash = "sha256:006db16dada95db965e845437b2001ea5ad28ea8fe94188819cab60838db1239"}, +] + +[package.dependencies] +astor = "*" +grpcio = "*" +grpcio-tools = "*" +mypy-protobuf = "*" +proto-schema-parser = "*" + [[package]] name = "ipython" version = "8.12.3" @@ -1753,6 +1793,20 @@ files = [ [package.dependencies] wcwidth = "*" +[[package]] +name = "proto-schema-parser" +version = "1.3.10" +description = "A Pure Python Protobuf .proto Parser" +optional = false +python-versions = ">=3.8" +files = [ + {file = "proto_schema_parser-1.3.10-py3-none-any.whl", hash = "sha256:e922ab2cca1538295c90f0c0fc53b496bf4ddbf88838b9acb03223adc9e84480"}, + {file = "proto_schema_parser-1.3.10.tar.gz", hash = "sha256:9cfca77f2866073e960866ba580990dcfea864670eb8c34d4debae3bfe42cecd"}, +] + +[package.dependencies] +antlr4-python3-runtime = ">=4.13.0" + [[package]] name = "protobuf" version = "4.25.1" @@ -1999,6 +2053,7 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -2494,4 +2549,4 @@ all = ["matplotlib", "mplfinance", "numpy", "pandas"] [metadata] lock-version = "2.0" python-versions = "^3.8.1" -content-hash = "d46ba8bccbf9c81ce7d23b4f73ed3ab8d078f625c9a438193e8702d89229a3c3" +content-hash = "510c4739c49f950fd5423b2d47b4d86eb55ee6ac990cfc6be8c755e371d68d50" diff --git a/pyproject.toml b/pyproject.toml index c666213..6f2e845 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,6 +57,7 @@ types-protobuf = "^4.23.0.4" types-python-dateutil = "^2.8.12" types-PyYAML = "^6.0.7" types-requests = "^2.27.7" +iprotopy = "^0.3.0" [tool.poetry.group.docs.dependencies] mkdocs = "^1.5" diff --git a/scripts/generate_models.py b/scripts/generate_models.py new file mode 100644 index 0000000..764b18f --- /dev/null +++ b/scripts/generate_models.py @@ -0,0 +1,16 @@ +import logging +from pathlib import Path + +from iprotopy import PackageGenerator + +logging.basicConfig(level=logging.DEBUG) + + +if __name__ == "__main__": + generator = PackageGenerator() + base_dir = Path().absolute().parent + + generator.generate_sources( + proto_dir=base_dir / "protos", + out_dir=base_dir, + ) diff --git a/tinkoff/invest/grpc/common.py b/tinkoff/invest/grpc/common.py new file mode 100644 index 0000000..9b1c26b --- /dev/null +++ b/tinkoff/invest/grpc/common.py @@ -0,0 +1,100 @@ +from dataclasses import dataclass +from datetime import datetime +from enum import IntEnum + + +class InstrumentType(IntEnum): + INSTRUMENT_TYPE_UNSPECIFIED = 0 + INSTRUMENT_TYPE_BOND = 1 + INSTRUMENT_TYPE_SHARE = 2 + INSTRUMENT_TYPE_CURRENCY = 3 + INSTRUMENT_TYPE_ETF = 4 + INSTRUMENT_TYPE_FUTURES = 5 + INSTRUMENT_TYPE_SP = 6 + INSTRUMENT_TYPE_OPTION = 7 + INSTRUMENT_TYPE_CLEARING_CERTIFICATE = 8 + INSTRUMENT_TYPE_INDEX = 9 + INSTRUMENT_TYPE_COMMODITY = 10 + + +@dataclass +class MoneyValue: + currency: str + units: int + nano: int + + +@dataclass +class Quotation: + units: int + nano: int + + +class SecurityTradingStatus(IntEnum): + SECURITY_TRADING_STATUS_UNSPECIFIED = 0 + SECURITY_TRADING_STATUS_NOT_AVAILABLE_FOR_TRADING = 1 + SECURITY_TRADING_STATUS_OPENING_PERIOD = 2 + SECURITY_TRADING_STATUS_CLOSING_PERIOD = 3 + SECURITY_TRADING_STATUS_BREAK_IN_TRADING = 4 + SECURITY_TRADING_STATUS_NORMAL_TRADING = 5 + SECURITY_TRADING_STATUS_CLOSING_AUCTION = 6 + SECURITY_TRADING_STATUS_DARK_POOL_AUCTION = 7 + SECURITY_TRADING_STATUS_DISCRETE_AUCTION = 8 + SECURITY_TRADING_STATUS_OPENING_AUCTION_PERIOD = 9 + SECURITY_TRADING_STATUS_TRADING_AT_CLOSING_AUCTION_PRICE = 10 + SECURITY_TRADING_STATUS_SESSION_ASSIGNED = 11 + SECURITY_TRADING_STATUS_SESSION_CLOSE = 12 + SECURITY_TRADING_STATUS_SESSION_OPEN = 13 + SECURITY_TRADING_STATUS_DEALER_NORMAL_TRADING = 14 + SECURITY_TRADING_STATUS_DEALER_BREAK_IN_TRADING = 15 + SECURITY_TRADING_STATUS_DEALER_NOT_AVAILABLE_FOR_TRADING = 16 + + +@dataclass +class Ping: + time: datetime + stream_id: str + + +class PriceType(IntEnum): + PRICE_TYPE_UNSPECIFIED = 0 + PRICE_TYPE_POINT = 1 + PRICE_TYPE_CURRENCY = 2 + + +@dataclass +class Page: + limit: int + page_number: int + + +@dataclass +class PageResponse: + limit: int + page_number: int + total_count: int + + +@dataclass +class ResponseMetadata: + tracking_id: str + server_time: datetime + + +@dataclass +class BrandData: + logo_name: str + logo_base_color: str + text_color: str + + +class ResultSubscriptionStatus(IntEnum): + RESULT_SUBSCRIPTION_STATUS_UNSPECIFIED = 0 + RESULT_SUBSCRIPTION_STATUS_OK = 1 + RESULT_SUBSCRIPTION_STATUS_ERROR = 13 + + +@dataclass +class ErrorDetail: + code: str + message: str diff --git a/tinkoff/invest/grpc/google/api/field_behavior.py b/tinkoff/invest/grpc/google/api/field_behavior.py new file mode 100644 index 0000000..bb719a4 --- /dev/null +++ b/tinkoff/invest/grpc/google/api/field_behavior.py @@ -0,0 +1,12 @@ +from enum import IntEnum + + +class FieldBehavior(IntEnum): + FIELD_BEHAVIOR_UNSPECIFIED = 0 + OPTIONAL = 1 + REQUIRED = 2 + OUTPUT_ONLY = 3 + INPUT_ONLY = 4 + IMMUTABLE = 5 + UNORDERED_LIST = 6 + NON_EMPTY_DEFAULT = 7 diff --git a/tinkoff/invest/grpc/instruments.py b/tinkoff/invest/grpc/instruments.py new file mode 100644 index 0000000..deda64a --- /dev/null +++ b/tinkoff/invest/grpc/instruments.py @@ -0,0 +1,1477 @@ +from dataclasses import dataclass +from datetime import datetime +from enum import IntEnum +from typing import List, Optional + +from iprotopy import dataclass_to_protobuf, protobuf_to_dataclass + +from base_service import BaseService +from tinkoff.invest.grpc import instruments_pb2, instruments_pb2_grpc +from tinkoff.invest.grpc.common import ( + BrandData, + InstrumentType, + MoneyValue, + Page, + PageResponse, + Quotation, + SecurityTradingStatus, +) + + +class InstrumentsService(BaseService): + """/*Методы сервиса предназначены для получения:
1. Информации об инструментах.
2. + Расписания торговых сессий.
3. Календаря выплат купонов по облигациям.
4. + Размера гарантийного обеспечения по фьючерсам.
5. Дивидендов по ценной бумаге.*/""" + _protobuf = instruments_pb2 + _protobuf_grpc = instruments_pb2_grpc + _protobuf_stub = _protobuf_grpc.InstrumentsServiceStub + + def TradingSchedules(self, request: 'TradingSchedulesRequest' + ) ->'TradingSchedulesResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + TradingSchedulesRequest()) + response, call = self._stub.TradingSchedules.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, TradingSchedulesResponse) + + def BondBy(self, request: 'InstrumentRequest') ->'BondResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + InstrumentRequest()) + response, call = self._stub.BondBy.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, BondResponse) + + def Bonds(self, request: 'InstrumentsRequest') ->'BondsResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + InstrumentsRequest()) + response, call = self._stub.Bonds.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, BondsResponse) + + def GetBondCoupons(self, request: 'GetBondCouponsRequest' + ) ->'GetBondCouponsResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetBondCouponsRequest()) + response, call = self._stub.GetBondCoupons.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, GetBondCouponsResponse) + + def GetBondEvents(self, request: 'GetBondEventsRequest' + ) ->'GetBondEventsResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetBondEventsRequest()) + response, call = self._stub.GetBondEvents.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, GetBondEventsResponse) + + def CurrencyBy(self, request: 'InstrumentRequest') ->'CurrencyResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + InstrumentRequest()) + response, call = self._stub.CurrencyBy.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, CurrencyResponse) + + def Currencies(self, request: 'InstrumentsRequest') ->'CurrenciesResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + InstrumentsRequest()) + response, call = self._stub.Currencies.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, CurrenciesResponse) + + def EtfBy(self, request: 'InstrumentRequest') ->'EtfResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + InstrumentRequest()) + response, call = self._stub.EtfBy.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, EtfResponse) + + def Etfs(self, request: 'InstrumentsRequest') ->'EtfsResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + InstrumentsRequest()) + response, call = self._stub.Etfs.with_call(request=protobuf_request, + metadata=self._metadata) + return protobuf_to_dataclass(response, EtfsResponse) + + def FutureBy(self, request: 'InstrumentRequest') ->'FutureResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + InstrumentRequest()) + response, call = self._stub.FutureBy.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, FutureResponse) + + def Futures(self, request: 'InstrumentsRequest') ->'FuturesResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + InstrumentsRequest()) + response, call = self._stub.Futures.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, FuturesResponse) + + def OptionBy(self, request: 'InstrumentRequest') ->'OptionResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + InstrumentRequest()) + response, call = self._stub.OptionBy.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, OptionResponse) + + def Options(self, request: 'InstrumentsRequest') ->'OptionsResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + InstrumentsRequest()) + response, call = self._stub.Options.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, OptionsResponse) + + def OptionsBy(self, request: 'FilterOptionsRequest') ->'OptionsResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + FilterOptionsRequest()) + response, call = self._stub.OptionsBy.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, OptionsResponse) + + def ShareBy(self, request: 'InstrumentRequest') ->'ShareResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + InstrumentRequest()) + response, call = self._stub.ShareBy.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, ShareResponse) + + def Shares(self, request: 'InstrumentsRequest') ->'SharesResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + InstrumentsRequest()) + response, call = self._stub.Shares.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, SharesResponse) + + def Indicatives(self, request: 'IndicativesRequest' + ) ->'IndicativesResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + IndicativesRequest()) + response, call = self._stub.Indicatives.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, IndicativesResponse) + + def GetAccruedInterests(self, request: 'GetAccruedInterestsRequest' + ) ->'GetAccruedInterestsResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetAccruedInterestsRequest()) + response, call = self._stub.GetAccruedInterests.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, GetAccruedInterestsResponse) + + def GetFuturesMargin(self, request: 'GetFuturesMarginRequest' + ) ->'GetFuturesMarginResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetFuturesMarginRequest()) + response, call = self._stub.GetFuturesMargin.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, GetFuturesMarginResponse) + + def GetInstrumentBy(self, request: 'InstrumentRequest' + ) ->'InstrumentResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + InstrumentRequest()) + response, call = self._stub.GetInstrumentBy.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, InstrumentResponse) + + def GetDividends(self, request: 'GetDividendsRequest' + ) ->'GetDividendsResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetDividendsRequest()) + response, call = self._stub.GetDividends.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, GetDividendsResponse) + + def GetAssetBy(self, request: 'AssetRequest') ->'AssetResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + AssetRequest()) + response, call = self._stub.GetAssetBy.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, AssetResponse) + + def GetAssets(self, request: 'AssetsRequest') ->'AssetsResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + AssetsRequest()) + response, call = self._stub.GetAssets.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, AssetsResponse) + + def GetFavorites(self, request: 'GetFavoritesRequest' + ) ->'GetFavoritesResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetFavoritesRequest()) + response, call = self._stub.GetFavorites.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, GetFavoritesResponse) + + def EditFavorites(self, request: 'EditFavoritesRequest' + ) ->'EditFavoritesResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + EditFavoritesRequest()) + response, call = self._stub.EditFavorites.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, EditFavoritesResponse) + + def GetCountries(self, request: 'GetCountriesRequest' + ) ->'GetCountriesResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetCountriesRequest()) + response, call = self._stub.GetCountries.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, GetCountriesResponse) + + def FindInstrument(self, request: 'FindInstrumentRequest' + ) ->'FindInstrumentResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + FindInstrumentRequest()) + response, call = self._stub.FindInstrument.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, FindInstrumentResponse) + + def GetBrands(self, request: 'GetBrandsRequest') ->'GetBrandsResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetBrandsRequest()) + response, call = self._stub.GetBrands.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, GetBrandsResponse) + + def GetBrandBy(self, request: 'GetBrandRequest') ->'Brand': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetBrandRequest()) + response, call = self._stub.GetBrandBy.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, Brand) + + def GetAssetFundamentals(self, request: 'GetAssetFundamentalsRequest' + ) ->'GetAssetFundamentalsResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetAssetFundamentalsRequest()) + response, call = self._stub.GetAssetFundamentals.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, GetAssetFundamentalsResponse) + + def GetAssetReports(self, request: 'GetAssetReportsRequest' + ) ->'GetAssetReportsResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetAssetReportsRequest()) + response, call = self._stub.GetAssetReports.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, GetAssetReportsResponse) + + def GetConsensusForecasts(self, request: 'GetConsensusForecastsRequest' + ) ->'GetConsensusForecastsResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetConsensusForecastsRequest()) + response, call = self._stub.GetConsensusForecasts.with_call(request + =protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, GetConsensusForecastsResponse) + + def GetForecastBy(self, request: 'GetForecastRequest' + ) ->'GetForecastResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetForecastRequest()) + response, call = self._stub.GetForecastBy.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, GetForecastResponse) + + +@dataclass +class TradingSchedulesRequest: + exchange: Optional[str] = None + from_: Optional[datetime] = None + to: Optional[datetime] = None + + +@dataclass +class TradingSchedulesResponse: + exchanges: List['TradingSchedule'] + + +@dataclass +class TradingSchedule: + exchange: str + days: List['TradingDay'] + + +@dataclass +class TradingDay: + date: datetime + is_trading_day: bool + start_time: datetime + end_time: datetime + opening_auction_start_time: datetime + closing_auction_end_time: datetime + evening_opening_auction_start_time: datetime + evening_start_time: datetime + evening_end_time: datetime + clearing_start_time: datetime + clearing_end_time: datetime + premarket_start_time: datetime + premarket_end_time: datetime + closing_auction_start_time: datetime + opening_auction_end_time: datetime + intervals: List['TradingInterval'] + + +@dataclass +class InstrumentRequest: + id_type: 'InstrumentIdType' + id: str + class_code: Optional[str] = None + + +@dataclass +class InstrumentsRequest: + instrument_status: Optional['InstrumentStatus'] = None + instrument_exchange: Optional['InstrumentExchangeType'] = None + + +@dataclass +class FilterOptionsRequest: + basic_asset_uid: Optional[str] = None + basic_asset_position_uid: Optional[str] = None + + +@dataclass +class BondResponse: + instrument: 'Bond' + + +@dataclass +class BondsResponse: + instruments: List['Bond'] + + +@dataclass +class GetBondCouponsRequest: + figi: str + instrument_id: str + from_: Optional[datetime] = None + to: Optional[datetime] = None + + +@dataclass +class GetBondCouponsResponse: + events: List['Coupon'] + + +@dataclass +class GetBondEventsRequest: + instrument_id: str + type: 'EventType' + from_: Optional[datetime] = None + to: Optional[datetime] = None + + + class EventType(IntEnum): + EVENT_TYPE_UNSPECIFIED = 0 + EVENT_TYPE_CPN = 1 + EVENT_TYPE_CALL = 2 + EVENT_TYPE_MTY = 3 + EVENT_TYPE_CONV = 4 + + +@dataclass +class GetBondEventsResponse: + events: List['BondEvent'] + + + @dataclass + class BondEvent: + instrument_id: str + event_number: int + event_date: datetime + event_type: 'GetBondEventsRequest.EventType' + event_total_vol: 'Quotation' + fix_date: datetime + rate_date: datetime + default_date: datetime + real_pay_date: datetime + pay_date: datetime + pay_one_bond: 'MoneyValue' + money_flow_val: 'MoneyValue' + execution: str + operation_type: str + value: 'Quotation' + note: str + convert_to_fin_tool_id: str + coupon_start_date: datetime + coupon_end_date: datetime + coupon_period: int + coupon_interest_rate: 'Quotation' + + +@dataclass +class Coupon: + figi: str + coupon_date: datetime + coupon_number: int + fix_date: datetime + pay_one_bond: 'MoneyValue' + coupon_type: 'CouponType' + coupon_start_date: datetime + coupon_end_date: datetime + coupon_period: int + + +class CouponType(IntEnum): + COUPON_TYPE_UNSPECIFIED = 0 + COUPON_TYPE_CONSTANT = 1 + COUPON_TYPE_FLOATING = 2 + COUPON_TYPE_DISCOUNT = 3 + COUPON_TYPE_MORTGAGE = 4 + COUPON_TYPE_FIX = 5 + COUPON_TYPE_VARIABLE = 6 + COUPON_TYPE_OTHER = 7 + + +@dataclass +class CurrencyResponse: + instrument: 'Currency' + + +@dataclass +class CurrenciesResponse: + instruments: List['Currency'] + + +@dataclass +class EtfResponse: + instrument: 'Etf' + + +@dataclass +class EtfsResponse: + instruments: List['Etf'] + + +@dataclass +class FutureResponse: + instrument: 'Future' + + +@dataclass +class FuturesResponse: + instruments: List['Future'] + + +@dataclass +class OptionResponse: + instrument: 'Option' + + +@dataclass +class OptionsResponse: + instruments: List['Option'] + + +@dataclass +class Option: + uid: str + position_uid: str + ticker: str + class_code: str + basic_asset_position_uid: str + trading_status: 'SecurityTradingStatus' + real_exchange: 'RealExchange' + direction: 'OptionDirection' + payment_type: 'OptionPaymentType' + style: 'OptionStyle' + settlement_type: 'OptionSettlementType' + name: str + currency: str + settlement_currency: str + asset_type: str + basic_asset: str + exchange: str + country_of_risk: str + country_of_risk_name: str + sector: str + brand: 'BrandData' + lot: int + basic_asset_size: 'Quotation' + klong: 'Quotation' + kshort: 'Quotation' + dlong: 'Quotation' + dshort: 'Quotation' + dlong_min: 'Quotation' + dshort_min: 'Quotation' + min_price_increment: 'Quotation' + strike_price: 'MoneyValue' + expiration_date: datetime + first_trade_date: datetime + last_trade_date: datetime + first_1min_candle_date: datetime + first_1day_candle_date: datetime + short_enabled_flag: bool + for_iis_flag: bool + otc_flag: bool + buy_available_flag: bool + sell_available_flag: bool + for_qual_investor_flag: bool + weekend_flag: bool + blocked_tca_flag: bool + api_trade_available_flag: bool + + +class OptionDirection(IntEnum): + OPTION_DIRECTION_UNSPECIFIED = 0 + OPTION_DIRECTION_PUT = 1 + OPTION_DIRECTION_CALL = 2 + + +class OptionPaymentType(IntEnum): + OPTION_PAYMENT_TYPE_UNSPECIFIED = 0 + OPTION_PAYMENT_TYPE_PREMIUM = 1 + OPTION_PAYMENT_TYPE_MARGINAL = 2 + + +class OptionStyle(IntEnum): + OPTION_STYLE_UNSPECIFIED = 0 + OPTION_STYLE_AMERICAN = 1 + OPTION_STYLE_EUROPEAN = 2 + + +class OptionSettlementType(IntEnum): + OPTION_EXECUTION_TYPE_UNSPECIFIED = 0 + OPTION_EXECUTION_TYPE_PHYSICAL_DELIVERY = 1 + OPTION_EXECUTION_TYPE_CASH_SETTLEMENT = 2 + + +@dataclass +class ShareResponse: + instrument: 'Share' + + +@dataclass +class SharesResponse: + instruments: List['Share'] + + +@dataclass +class Bond: + figi: str + ticker: str + class_code: str + isin: str + lot: int + currency: str + klong: 'Quotation' + kshort: 'Quotation' + dlong: 'Quotation' + dshort: 'Quotation' + dlong_min: 'Quotation' + dshort_min: 'Quotation' + short_enabled_flag: bool + name: str + exchange: str + coupon_quantity_per_year: int + maturity_date: datetime + nominal: 'MoneyValue' + initial_nominal: 'MoneyValue' + state_reg_date: datetime + placement_date: datetime + placement_price: 'MoneyValue' + aci_value: 'MoneyValue' + country_of_risk: str + country_of_risk_name: str + sector: str + issue_kind: str + issue_size: int + issue_size_plan: int + trading_status: 'SecurityTradingStatus' + otc_flag: bool + buy_available_flag: bool + sell_available_flag: bool + floating_coupon_flag: bool + perpetual_flag: bool + amortization_flag: bool + min_price_increment: 'Quotation' + api_trade_available_flag: bool + uid: str + real_exchange: 'RealExchange' + position_uid: str + asset_uid: str + for_iis_flag: bool + for_qual_investor_flag: bool + weekend_flag: bool + blocked_tca_flag: bool + subordinated_flag: bool + liquidity_flag: bool + first_1min_candle_date: datetime + first_1day_candle_date: datetime + risk_level: 'RiskLevel' + brand: 'BrandData' + bond_type: 'BondType' + + +@dataclass +class Currency: + figi: str + ticker: str + class_code: str + isin: str + lot: int + currency: str + klong: 'Quotation' + kshort: 'Quotation' + dlong: 'Quotation' + dshort: 'Quotation' + dlong_min: 'Quotation' + dshort_min: 'Quotation' + short_enabled_flag: bool + name: str + exchange: str + nominal: 'MoneyValue' + country_of_risk: str + country_of_risk_name: str + trading_status: 'SecurityTradingStatus' + otc_flag: bool + buy_available_flag: bool + sell_available_flag: bool + iso_currency_name: str + min_price_increment: 'Quotation' + api_trade_available_flag: bool + uid: str + real_exchange: 'RealExchange' + position_uid: str + for_iis_flag: bool + for_qual_investor_flag: bool + weekend_flag: bool + blocked_tca_flag: bool + first_1min_candle_date: datetime + first_1day_candle_date: datetime + brand: 'BrandData' + + +@dataclass +class Etf: + figi: str + ticker: str + class_code: str + isin: str + lot: int + currency: str + klong: 'Quotation' + kshort: 'Quotation' + dlong: 'Quotation' + dshort: 'Quotation' + dlong_min: 'Quotation' + dshort_min: 'Quotation' + short_enabled_flag: bool + name: str + exchange: str + fixed_commission: 'Quotation' + focus_type: str + released_date: datetime + num_shares: 'Quotation' + country_of_risk: str + country_of_risk_name: str + sector: str + rebalancing_freq: str + trading_status: 'SecurityTradingStatus' + otc_flag: bool + buy_available_flag: bool + sell_available_flag: bool + min_price_increment: 'Quotation' + api_trade_available_flag: bool + uid: str + real_exchange: 'RealExchange' + position_uid: str + asset_uid: str + instrument_exchange: 'InstrumentExchangeType' + for_iis_flag: bool + for_qual_investor_flag: bool + weekend_flag: bool + blocked_tca_flag: bool + liquidity_flag: bool + first_1min_candle_date: datetime + first_1day_candle_date: datetime + brand: 'BrandData' + + +@dataclass +class Future: + figi: str + ticker: str + class_code: str + lot: int + currency: str + klong: 'Quotation' + kshort: 'Quotation' + dlong: 'Quotation' + dshort: 'Quotation' + dlong_min: 'Quotation' + dshort_min: 'Quotation' + short_enabled_flag: bool + name: str + exchange: str + first_trade_date: datetime + last_trade_date: datetime + futures_type: str + asset_type: str + basic_asset: str + basic_asset_size: 'Quotation' + country_of_risk: str + country_of_risk_name: str + sector: str + expiration_date: datetime + trading_status: 'SecurityTradingStatus' + otc_flag: bool + buy_available_flag: bool + sell_available_flag: bool + min_price_increment: 'Quotation' + api_trade_available_flag: bool + uid: str + real_exchange: 'RealExchange' + position_uid: str + basic_asset_position_uid: str + for_iis_flag: bool + for_qual_investor_flag: bool + weekend_flag: bool + blocked_tca_flag: bool + first_1min_candle_date: datetime + first_1day_candle_date: datetime + initial_margin_on_buy: 'MoneyValue' + initial_margin_on_sell: 'MoneyValue' + min_price_increment_amount: 'Quotation' + brand: 'BrandData' + + +@dataclass +class Share: + figi: str + ticker: str + class_code: str + isin: str + lot: int + currency: str + klong: 'Quotation' + kshort: 'Quotation' + dlong: 'Quotation' + dshort: 'Quotation' + dlong_min: 'Quotation' + dshort_min: 'Quotation' + short_enabled_flag: bool + name: str + exchange: str + ipo_date: datetime + issue_size: int + country_of_risk: str + country_of_risk_name: str + sector: str + issue_size_plan: int + nominal: 'MoneyValue' + trading_status: 'SecurityTradingStatus' + otc_flag: bool + buy_available_flag: bool + sell_available_flag: bool + div_yield_flag: bool + share_type: 'ShareType' + min_price_increment: 'Quotation' + api_trade_available_flag: bool + uid: str + real_exchange: 'RealExchange' + position_uid: str + asset_uid: str + instrument_exchange: 'InstrumentExchangeType' + for_iis_flag: bool + for_qual_investor_flag: bool + weekend_flag: bool + blocked_tca_flag: bool + liquidity_flag: bool + first_1min_candle_date: datetime + first_1day_candle_date: datetime + brand: 'BrandData' + + +@dataclass +class GetAccruedInterestsRequest: + figi: str + from_: datetime + to: datetime + instrument_id: str + + +@dataclass +class GetAccruedInterestsResponse: + accrued_interests: List['AccruedInterest'] + + +@dataclass +class AccruedInterest: + date: datetime + value: 'Quotation' + value_percent: 'Quotation' + nominal: 'Quotation' + + +@dataclass +class GetFuturesMarginRequest: + figi: str + instrument_id: str + + +@dataclass +class GetFuturesMarginResponse: + initial_margin_on_buy: 'MoneyValue' + initial_margin_on_sell: 'MoneyValue' + min_price_increment: 'Quotation' + min_price_increment_amount: 'Quotation' + + +class InstrumentIdType(IntEnum): + INSTRUMENT_ID_UNSPECIFIED = 0 + INSTRUMENT_ID_TYPE_FIGI = 1 + INSTRUMENT_ID_TYPE_TICKER = 2 + INSTRUMENT_ID_TYPE_UID = 3 + INSTRUMENT_ID_TYPE_POSITION_UID = 4 + + +class InstrumentStatus(IntEnum): + INSTRUMENT_STATUS_UNSPECIFIED = 0 + INSTRUMENT_STATUS_BASE = 1 + INSTRUMENT_STATUS_ALL = 2 + + +@dataclass +class InstrumentResponse: + instrument: 'Instrument' + + +@dataclass +class Instrument: + figi: str + ticker: str + class_code: str + isin: str + lot: int + currency: str + klong: 'Quotation' + kshort: 'Quotation' + dlong: 'Quotation' + dshort: 'Quotation' + dlong_min: 'Quotation' + dshort_min: 'Quotation' + short_enabled_flag: bool + name: str + exchange: str + country_of_risk: str + country_of_risk_name: str + instrument_type: str + trading_status: 'SecurityTradingStatus' + otc_flag: bool + buy_available_flag: bool + sell_available_flag: bool + min_price_increment: 'Quotation' + api_trade_available_flag: bool + uid: str + real_exchange: 'RealExchange' + position_uid: str + asset_uid: str + for_iis_flag: bool + for_qual_investor_flag: bool + weekend_flag: bool + blocked_tca_flag: bool + instrument_kind: 'InstrumentType' + first_1min_candle_date: datetime + first_1day_candle_date: datetime + brand: 'BrandData' + + +@dataclass +class GetDividendsRequest: + figi: str + instrument_id: str + from_: Optional[datetime] = None + to: Optional[datetime] = None + + +@dataclass +class GetDividendsResponse: + dividends: List['Dividend'] + + +@dataclass +class Dividend: + dividend_net: 'MoneyValue' + payment_date: datetime + declared_date: datetime + last_buy_date: datetime + dividend_type: str + record_date: datetime + regularity: str + close_price: 'MoneyValue' + yield_value: 'Quotation' + created_at: datetime + + +class ShareType(IntEnum): + SHARE_TYPE_UNSPECIFIED = 0 + SHARE_TYPE_COMMON = 1 + SHARE_TYPE_PREFERRED = 2 + SHARE_TYPE_ADR = 3 + SHARE_TYPE_GDR = 4 + SHARE_TYPE_MLP = 5 + SHARE_TYPE_NY_REG_SHRS = 6 + SHARE_TYPE_CLOSED_END_FUND = 7 + SHARE_TYPE_REIT = 8 + + +@dataclass +class AssetRequest: + id: str + + +@dataclass +class AssetResponse: + asset: 'AssetFull' + + +@dataclass +class AssetsRequest: + instrument_type: Optional['InstrumentType'] = None + + +@dataclass +class AssetsResponse: + assets: List['Asset'] + + +@dataclass +class AssetFull: + uid: str + type: 'AssetType' + name: str + name_brief: str + description: str + deleted_at: datetime + required_tests: List[str] + gos_reg_code: str + cfi: str + code_nsd: str + status: str + brand: 'Brand' + updated_at: datetime + br_code: str + br_code_name: str + instruments: List['AssetInstrument'] + currency: Optional['AssetCurrency'] = None + security: Optional['AssetSecurity'] = None + + +@dataclass +class Asset: + uid: str + type: 'AssetType' + name: str + instruments: List['AssetInstrument'] + + +class AssetType(IntEnum): + ASSET_TYPE_UNSPECIFIED = 0 + ASSET_TYPE_CURRENCY = 1 + ASSET_TYPE_COMMODITY = 2 + ASSET_TYPE_INDEX = 3 + ASSET_TYPE_SECURITY = 4 + + +@dataclass +class AssetCurrency: + base_currency: str + + +@dataclass +class AssetSecurity: + isin: str + type: str + instrument_kind: 'InstrumentType' + share: Optional['AssetShare'] = None + bond: Optional['AssetBond'] = None + sp: Optional['AssetStructuredProduct'] = None + etf: Optional['AssetEtf'] = None + clearing_certificate: Optional['AssetClearingCertificate'] = None + + +@dataclass +class AssetShare: + type: 'ShareType' + issue_size: 'Quotation' + nominal: 'Quotation' + nominal_currency: str + primary_index: str + dividend_rate: 'Quotation' + preferred_share_type: str + ipo_date: datetime + registry_date: datetime + div_yield_flag: bool + issue_kind: str + placement_date: datetime + repres_isin: str + issue_size_plan: 'Quotation' + total_float: 'Quotation' + + +@dataclass +class AssetBond: + current_nominal: 'Quotation' + borrow_name: str + issue_size: 'Quotation' + nominal: 'Quotation' + nominal_currency: str + issue_kind: str + interest_kind: str + coupon_quantity_per_year: int + indexed_nominal_flag: bool + subordinated_flag: bool + collateral_flag: bool + tax_free_flag: bool + amortization_flag: bool + floating_coupon_flag: bool + perpetual_flag: bool + maturity_date: datetime + return_condition: str + state_reg_date: datetime + placement_date: datetime + placement_price: 'Quotation' + issue_size_plan: 'Quotation' + + +@dataclass +class AssetStructuredProduct: + borrow_name: str + nominal: 'Quotation' + nominal_currency: str + type: 'StructuredProductType' + logic_portfolio: str + asset_type: 'AssetType' + basic_asset: str + safety_barrier: 'Quotation' + maturity_date: datetime + issue_size_plan: 'Quotation' + issue_size: 'Quotation' + placement_date: datetime + issue_kind: str + + +class StructuredProductType(IntEnum): + SP_TYPE_UNSPECIFIED = 0 + SP_TYPE_DELIVERABLE = 1 + SP_TYPE_NON_DELIVERABLE = 2 + + +@dataclass +class AssetEtf: + total_expense: 'Quotation' + hurdle_rate: 'Quotation' + performance_fee: 'Quotation' + fixed_commission: 'Quotation' + payment_type: str + watermark_flag: bool + buy_premium: 'Quotation' + sell_discount: 'Quotation' + rebalancing_flag: bool + rebalancing_freq: str + management_type: str + primary_index: str + focus_type: str + leveraged_flag: bool + num_share: 'Quotation' + ucits_flag: bool + released_date: datetime + description: str + primary_index_description: str + primary_index_company: str + index_recovery_period: 'Quotation' + inav_code: str + div_yield_flag: bool + expense_commission: 'Quotation' + primary_index_tracking_error: 'Quotation' + rebalancing_plan: str + tax_rate: str + rebalancing_dates: List[datetime] + issue_kind: str + nominal: 'Quotation' + nominal_currency: str + + +@dataclass +class AssetClearingCertificate: + nominal: 'Quotation' + nominal_currency: str + + +@dataclass +class Brand: + uid: str + name: str + description: str + info: str + company: str + sector: str + country_of_risk: str + country_of_risk_name: str + + +@dataclass +class AssetInstrument: + uid: str + figi: str + instrument_type: str + ticker: str + class_code: str + links: List['InstrumentLink'] + instrument_kind: 'InstrumentType' + position_uid: str + + +@dataclass +class InstrumentLink: + type: str + instrument_uid: str + + +@dataclass +class GetFavoritesRequest: + pass + + +@dataclass +class GetFavoritesResponse: + favorite_instruments: List['FavoriteInstrument'] + + +@dataclass +class FavoriteInstrument: + figi: str + ticker: str + class_code: str + isin: str + instrument_type: str + name: str + uid: str + otc_flag: bool + api_trade_available_flag: bool + instrument_kind: 'InstrumentType' + + +@dataclass +class EditFavoritesRequest: + instruments: List['EditFavoritesRequestInstrument'] + action_type: 'EditFavoritesActionType' + + +@dataclass +class EditFavoritesRequestInstrument: + instrument_id: str + figi: Optional[str] = None + + +class EditFavoritesActionType(IntEnum): + EDIT_FAVORITES_ACTION_TYPE_UNSPECIFIED = 0 + EDIT_FAVORITES_ACTION_TYPE_ADD = 1 + EDIT_FAVORITES_ACTION_TYPE_DEL = 2 + + +@dataclass +class EditFavoritesResponse: + favorite_instruments: List['FavoriteInstrument'] + + +class RealExchange(IntEnum): + REAL_EXCHANGE_UNSPECIFIED = 0 + REAL_EXCHANGE_MOEX = 1 + REAL_EXCHANGE_RTS = 2 + REAL_EXCHANGE_OTC = 3 + REAL_EXCHANGE_DEALER = 4 + + +@dataclass +class GetCountriesRequest: + pass + + +@dataclass +class GetCountriesResponse: + countries: List['CountryResponse'] + + +@dataclass +class IndicativesRequest: + pass + + +@dataclass +class IndicativesResponse: + instruments: List['IndicativeResponse'] + + +@dataclass +class IndicativeResponse: + figi: str + ticker: str + class_code: str + currency: str + instrument_kind: 'InstrumentType' + name: str + exchange: str + uid: str + buy_available_flag: bool + sell_available_flag: bool + + +@dataclass +class CountryResponse: + alfa_two: str + alfa_three: str + name: str + name_brief: str + + +@dataclass +class FindInstrumentRequest: + query: str + instrument_kind: Optional['InstrumentType'] = None + api_trade_available_flag: Optional[bool] = None + + +@dataclass +class FindInstrumentResponse: + instruments: List['InstrumentShort'] + + +@dataclass +class InstrumentShort: + isin: str + figi: str + ticker: str + class_code: str + instrument_type: str + name: str + uid: str + position_uid: str + instrument_kind: 'InstrumentType' + api_trade_available_flag: bool + for_iis_flag: bool + first_1min_candle_date: datetime + first_1day_candle_date: datetime + for_qual_investor_flag: bool + weekend_flag: bool + blocked_tca_flag: bool + + +@dataclass +class GetBrandsRequest: + paging: 'Page' + + +@dataclass +class GetBrandRequest: + id: str + + +@dataclass +class GetBrandsResponse: + brands: List['Brand'] + paging: 'PageResponse' + + +@dataclass +class GetAssetFundamentalsRequest: + assets: List[str] + + +@dataclass +class GetAssetFundamentalsResponse: + fundamentals: List['StatisticResponse'] + + + @dataclass + class StatisticResponse: + asset_uid: str + currency: str + market_capitalization: float + high_price_last_52_weeks: float + low_price_last_52_weeks: float + average_daily_volume_last_10_days: float + average_daily_volume_last_4_weeks: float + beta: float + free_float: float + forward_annual_dividend_yield: float + shares_outstanding: float + revenue_ttm: float + ebitda_ttm: float + net_income_ttm: float + eps_ttm: float + diluted_eps_ttm: float + free_cash_flow_ttm: float + five_year_annual_revenue_growth_rate: float + three_year_annual_revenue_growth_rate: float + pe_ratio_ttm: float + price_to_sales_ttm: float + price_to_book_ttm: float + price_to_free_cash_flow_ttm: float + total_enterprise_value_mrq: float + ev_to_ebitda_mrq: float + net_margin_mrq: float + net_interest_margin_mrq: float + roe: float + roa: float + roic: float + total_debt_mrq: float + total_debt_to_equity_mrq: float + total_debt_to_ebitda_mrq: float + free_cash_flow_to_price: float + net_debt_to_ebitda: float + current_ratio_mrq: float + fixed_charge_coverage_ratio_fy: float + dividend_yield_daily_ttm: float + dividend_rate_ttm: float + dividends_per_share: float + five_years_average_dividend_yield: float + five_year_annual_dividend_growth_rate: float + dividend_payout_ratio_fy: float + buy_back_ttm: float + one_year_annual_revenue_growth_rate: float + domicile_indicator_code: str + adr_to_common_share_ratio: float + number_of_employees: float + ex_dividend_date: datetime + fiscal_period_start_date: datetime + fiscal_period_end_date: datetime + revenue_change_five_years: float + eps_change_five_years: float + ebitda_change_five_years: float + total_debt_change_five_years: float + ev_to_sales: float + + +@dataclass +class GetAssetReportsRequest: + instrument_id: str + from_: Optional[datetime] = None + to: Optional[datetime] = None + + +@dataclass +class GetAssetReportsResponse: + events: List['GetAssetReportsEvent'] + + + @dataclass + class GetAssetReportsEvent: + instrument_id: str + report_date: datetime + period_year: int + period_num: int + period_type: 'AssetReportPeriodType' + created_at: datetime + + + class AssetReportPeriodType(IntEnum): + PERIOD_TYPE_UNSPECIFIED = 0 + PERIOD_TYPE_QUARTER = 1 + PERIOD_TYPE_SEMIANNUAL = 2 + PERIOD_TYPE_ANNUAL = 3 + + +@dataclass +class GetConsensusForecastsRequest: + paging: Optional['Page'] = None + + +@dataclass +class GetConsensusForecastsResponse: + items: List['ConsensusForecastsItem'] + page: 'PageResponse' + + + @dataclass + class ConsensusForecastsItem: + uid: str + asset_uid: str + created_at: datetime + best_target_price: 'Quotation' + best_target_low: 'Quotation' + best_target_high: 'Quotation' + total_buy_recommend: int + total_hold_recommend: int + total_sell_recommend: int + currency: str + consensus: 'Recommendation' + prognosis_date: datetime + + +class Recommendation(IntEnum): + RECOMMENDATION_UNSPECIFIED = 0 + RECOMMENDATION_BUY = 1 + RECOMMENDATION_HOLD = 2 + RECOMMENDATION_SELL = 3 + + +@dataclass +class GetForecastRequest: + instrument_id: str + + +@dataclass +class GetForecastResponse: + targets: List['TargetItem'] + consensus: 'ConsensusItem' + + + @dataclass + class TargetItem: + uid: str + ticker: str + company: str + recommendation: 'Recommendation' + recommendation_date: datetime + currency: str + current_price: 'Quotation' + target_price: 'Quotation' + price_change: 'Quotation' + price_change_rel: 'Quotation' + show_name: str + + + @dataclass + class ConsensusItem: + uid: str + ticker: str + recommendation: 'Recommendation' + currency: str + current_price: 'Quotation' + consensus: 'Quotation' + min_target: 'Quotation' + max_target: 'Quotation' + price_change: 'Quotation' + price_change_rel: 'Quotation' + + +@dataclass +class TradingInterval: + type: str + interval: 'TimeInterval' + + + @dataclass + class TimeInterval: + start_ts: datetime + end_ts: datetime + + +class RiskLevel(IntEnum): + RISK_LEVEL_UNSPECIFIED = 0 + RISK_LEVEL_LOW = 1 + RISK_LEVEL_MODERATE = 2 + RISK_LEVEL_HIGH = 3 + + +class BondType(IntEnum): + BOND_TYPE_UNSPECIFIED = 0 + BOND_TYPE_REPLACED = 1 + + +class InstrumentExchangeType(IntEnum): + INSTRUMENT_EXCHANGE_UNSPECIFIED = 0 + INSTRUMENT_EXCHANGE_DEALER = 1 diff --git a/tinkoff/invest/grpc/marketdata.py b/tinkoff/invest/grpc/marketdata.py new file mode 100644 index 0000000..620e1fa --- /dev/null +++ b/tinkoff/invest/grpc/marketdata.py @@ -0,0 +1,644 @@ +from dataclasses import dataclass +from datetime import datetime +from enum import IntEnum +from typing import Iterable, List, Optional + +from iprotopy import dataclass_to_protobuf, protobuf_to_dataclass + +from base_service import BaseService +from tinkoff.invest.grpc import marketdata_pb2, marketdata_pb2_grpc +from tinkoff.invest.grpc.common import Ping, Quotation, SecurityTradingStatus + + +class MarketDataService(BaseService): + """//Сервис для получения биржевой информации:
1. Свечи.
2. Стаканы.
3. Торговые статусы.
4. Лента сделок.""" + _protobuf = marketdata_pb2 + _protobuf_grpc = marketdata_pb2_grpc + _protobuf_stub = _protobuf_grpc.MarketDataServiceStub + + def GetCandles(self, request: 'GetCandlesRequest') ->'GetCandlesResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetCandlesRequest()) + response, call = self._stub.GetCandles.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, GetCandlesResponse) + + def GetLastPrices(self, request: 'GetLastPricesRequest' + ) ->'GetLastPricesResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetLastPricesRequest()) + response, call = self._stub.GetLastPrices.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, GetLastPricesResponse) + + def GetOrderBook(self, request: 'GetOrderBookRequest' + ) ->'GetOrderBookResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetOrderBookRequest()) + response, call = self._stub.GetOrderBook.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, GetOrderBookResponse) + + def GetTradingStatus(self, request: 'GetTradingStatusRequest' + ) ->'GetTradingStatusResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetTradingStatusRequest()) + response, call = self._stub.GetTradingStatus.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, GetTradingStatusResponse) + + def GetTradingStatuses(self, request: 'GetTradingStatusesRequest' + ) ->'GetTradingStatusesResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetTradingStatusesRequest()) + response, call = self._stub.GetTradingStatuses.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, GetTradingStatusesResponse) + + def GetLastTrades(self, request: 'GetLastTradesRequest' + ) ->'GetLastTradesResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetLastTradesRequest()) + response, call = self._stub.GetLastTrades.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, GetLastTradesResponse) + + def GetClosePrices(self, request: 'GetClosePricesRequest' + ) ->'GetClosePricesResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetClosePricesRequest()) + response, call = self._stub.GetClosePrices.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, GetClosePricesResponse) + + def GetTechAnalysis(self, request: 'GetTechAnalysisRequest' + ) ->'GetTechAnalysisResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetTechAnalysisRequest()) + response, call = self._stub.GetTechAnalysis.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, GetTechAnalysisResponse) + + +class MarketDataStreamService(BaseService): + """//Bidirectional-стрим предоставления биржевой информации.""" + _protobuf = marketdata_pb2 + _protobuf_grpc = marketdata_pb2_grpc + _protobuf_stub = _protobuf_grpc.MarketDataStreamServiceStub + + def MarketDataStream(self, requests: Iterable['MarketDataRequest'] + ) ->Iterable['MarketDataResponse']: + for response in self._stub.MarketDataStream(request_iterator=( + dataclass_to_protobuf(request, self._protobuf.MarketDataRequest + ()) for request in requests), metadata=self._metadata): + yield protobuf_to_dataclass(response, MarketDataResponse) + + def MarketDataServerSideStream(self, request: + 'MarketDataServerSideStreamRequest') ->Iterable['MarketDataResponse']: + for response in self._stub.MarketDataServerSideStream(request= + dataclass_to_protobuf(request, self._protobuf. + MarketDataServerSideStreamRequest()), metadata=self._metadata): + yield protobuf_to_dataclass(response, MarketDataResponse) + + +@dataclass +class MarketDataRequest: + subscribe_candles_request: Optional['SubscribeCandlesRequest'] = None + subscribe_order_book_request: Optional['SubscribeOrderBookRequest'] = None + subscribe_trades_request: Optional['SubscribeTradesRequest'] = None + subscribe_info_request: Optional['SubscribeInfoRequest'] = None + subscribe_last_price_request: Optional['SubscribeLastPriceRequest'] = None + get_my_subscriptions: Optional['GetMySubscriptions'] = None + + +@dataclass +class MarketDataServerSideStreamRequest: + subscribe_candles_request: 'SubscribeCandlesRequest' + subscribe_order_book_request: 'SubscribeOrderBookRequest' + subscribe_trades_request: 'SubscribeTradesRequest' + subscribe_info_request: 'SubscribeInfoRequest' + subscribe_last_price_request: 'SubscribeLastPriceRequest' + + +@dataclass +class MarketDataResponse: + subscribe_candles_response: Optional['SubscribeCandlesResponse'] = None + subscribe_order_book_response: Optional['SubscribeOrderBookResponse' + ] = None + subscribe_trades_response: Optional['SubscribeTradesResponse'] = None + subscribe_info_response: Optional['SubscribeInfoResponse'] = None + candle: Optional['Candle'] = None + trade: Optional['Trade'] = None + orderbook: Optional['OrderBook'] = None + trading_status: Optional['TradingStatus'] = None + ping: Optional['Ping'] = None + subscribe_last_price_response: Optional['SubscribeLastPriceResponse' + ] = None + last_price: Optional['LastPrice'] = None + + +@dataclass +class SubscribeCandlesRequest: + subscription_action: 'SubscriptionAction' + instruments: List['CandleInstrument'] + waiting_close: bool + + +class SubscriptionAction(IntEnum): + SUBSCRIPTION_ACTION_UNSPECIFIED = 0 + SUBSCRIPTION_ACTION_SUBSCRIBE = 1 + SUBSCRIPTION_ACTION_UNSUBSCRIBE = 2 + + +class SubscriptionInterval(IntEnum): + SUBSCRIPTION_INTERVAL_UNSPECIFIED = 0 + SUBSCRIPTION_INTERVAL_ONE_MINUTE = 1 + SUBSCRIPTION_INTERVAL_FIVE_MINUTES = 2 + SUBSCRIPTION_INTERVAL_FIFTEEN_MINUTES = 3 + SUBSCRIPTION_INTERVAL_ONE_HOUR = 4 + SUBSCRIPTION_INTERVAL_ONE_DAY = 5 + SUBSCRIPTION_INTERVAL_2_MIN = 6 + SUBSCRIPTION_INTERVAL_3_MIN = 7 + SUBSCRIPTION_INTERVAL_10_MIN = 8 + SUBSCRIPTION_INTERVAL_30_MIN = 9 + SUBSCRIPTION_INTERVAL_2_HOUR = 10 + SUBSCRIPTION_INTERVAL_4_HOUR = 11 + SUBSCRIPTION_INTERVAL_WEEK = 12 + SUBSCRIPTION_INTERVAL_MONTH = 13 + + +@dataclass +class CandleInstrument: + figi: str + interval: 'SubscriptionInterval' + instrument_id: str + + +@dataclass +class SubscribeCandlesResponse: + tracking_id: str + candles_subscriptions: List['CandleSubscription'] + + +@dataclass +class CandleSubscription: + figi: str + interval: 'SubscriptionInterval' + subscription_status: 'SubscriptionStatus' + instrument_uid: str + waiting_close: bool + stream_id: str + subscription_id: str + + +class SubscriptionStatus(IntEnum): + SUBSCRIPTION_STATUS_UNSPECIFIED = 0 + SUBSCRIPTION_STATUS_SUCCESS = 1 + SUBSCRIPTION_STATUS_INSTRUMENT_NOT_FOUND = 2 + SUBSCRIPTION_STATUS_SUBSCRIPTION_ACTION_IS_INVALID = 3 + SUBSCRIPTION_STATUS_DEPTH_IS_INVALID = 4 + SUBSCRIPTION_STATUS_INTERVAL_IS_INVALID = 5 + SUBSCRIPTION_STATUS_LIMIT_IS_EXCEEDED = 6 + SUBSCRIPTION_STATUS_INTERNAL_ERROR = 7 + SUBSCRIPTION_STATUS_TOO_MANY_REQUESTS = 8 + SUBSCRIPTION_STATUS_SUBSCRIPTION_NOT_FOUND = 9 + + +@dataclass +class SubscribeOrderBookRequest: + subscription_action: 'SubscriptionAction' + instruments: List['OrderBookInstrument'] + + +@dataclass +class OrderBookInstrument: + figi: str + depth: int + instrument_id: str + order_book_type: 'OrderBookType' + + +@dataclass +class SubscribeOrderBookResponse: + tracking_id: str + order_book_subscriptions: List['OrderBookSubscription'] + + +@dataclass +class OrderBookSubscription: + figi: str + depth: int + subscription_status: 'SubscriptionStatus' + instrument_uid: str + stream_id: str + subscription_id: str + order_book_type: 'OrderBookType' + + +class TradeSourceType(IntEnum): + TRADE_SOURCE_UNSPECIFIED = 0 + TRADE_SOURCE_EXCHANGE = 1 + TRADE_SOURCE_DEALER = 2 + TRADE_SOURCE_ALL = 3 + + +@dataclass +class SubscribeTradesRequest: + subscription_action: 'SubscriptionAction' + instruments: List['TradeInstrument'] + trade_type: 'TradeSourceType' + + +@dataclass +class TradeInstrument: + figi: str + instrument_id: str + + +@dataclass +class SubscribeTradesResponse: + tracking_id: str + trade_subscriptions: List['TradeSubscription'] + trade_type: 'TradeSourceType' + + +@dataclass +class TradeSubscription: + figi: str + subscription_status: 'SubscriptionStatus' + instrument_uid: str + stream_id: str + subscription_id: str + + +@dataclass +class SubscribeInfoRequest: + subscription_action: 'SubscriptionAction' + instruments: List['InfoInstrument'] + + +@dataclass +class InfoInstrument: + figi: str + instrument_id: str + + +@dataclass +class SubscribeInfoResponse: + tracking_id: str + info_subscriptions: List['InfoSubscription'] + + +@dataclass +class InfoSubscription: + figi: str + subscription_status: 'SubscriptionStatus' + instrument_uid: str + stream_id: str + subscription_id: str + + +@dataclass +class SubscribeLastPriceRequest: + subscription_action: 'SubscriptionAction' + instruments: List['LastPriceInstrument'] + + +@dataclass +class LastPriceInstrument: + figi: str + instrument_id: str + + +@dataclass +class SubscribeLastPriceResponse: + tracking_id: str + last_price_subscriptions: List['LastPriceSubscription'] + + +@dataclass +class LastPriceSubscription: + figi: str + subscription_status: 'SubscriptionStatus' + instrument_uid: str + stream_id: str + subscription_id: str + + +@dataclass +class Candle: + figi: str + interval: 'SubscriptionInterval' + open: 'Quotation' + high: 'Quotation' + low: 'Quotation' + close: 'Quotation' + volume: int + time: datetime + last_trade_ts: datetime + instrument_uid: str + + +@dataclass +class OrderBook: + figi: str + depth: int + is_consistent: bool + bids: List['Order'] + asks: List['Order'] + time: datetime + limit_up: 'Quotation' + limit_down: 'Quotation' + instrument_uid: str + order_book_type: 'OrderBookType' + + +@dataclass +class Order: + price: 'Quotation' + quantity: int + + +@dataclass +class Trade: + figi: str + direction: 'TradeDirection' + price: 'Quotation' + quantity: int + time: datetime + instrument_uid: str + tradeSource: 'TradeSourceType' + + +class TradeDirection(IntEnum): + TRADE_DIRECTION_UNSPECIFIED = 0 + TRADE_DIRECTION_BUY = 1 + TRADE_DIRECTION_SELL = 2 + + +@dataclass +class TradingStatus: + figi: str + trading_status: 'SecurityTradingStatus' + time: datetime + limit_order_available_flag: bool + market_order_available_flag: bool + instrument_uid: str + + +@dataclass +class GetCandlesRequest: + from_: datetime + to: datetime + interval: 'CandleInterval' + figi: Optional[str] = None + instrument_id: Optional[str] = None + candle_source_type: Optional['CandleSource'] = None + limit: Optional[int] = None + + + class CandleSource(IntEnum): + CANDLE_SOURCE_UNSPECIFIED = 0 + CANDLE_SOURCE_EXCHANGE = 1 + CANDLE_SOURCE_INCLUDE_WEEKEND = 3 + + +class CandleInterval(IntEnum): + CANDLE_INTERVAL_UNSPECIFIED = 0 + CANDLE_INTERVAL_1_MIN = 1 + CANDLE_INTERVAL_5_MIN = 2 + CANDLE_INTERVAL_15_MIN = 3 + CANDLE_INTERVAL_HOUR = 4 + CANDLE_INTERVAL_DAY = 5 + CANDLE_INTERVAL_2_MIN = 6 + CANDLE_INTERVAL_3_MIN = 7 + CANDLE_INTERVAL_10_MIN = 8 + CANDLE_INTERVAL_30_MIN = 9 + CANDLE_INTERVAL_2_HOUR = 10 + CANDLE_INTERVAL_4_HOUR = 11 + CANDLE_INTERVAL_WEEK = 12 + CANDLE_INTERVAL_MONTH = 13 + + +class CandleSource(IntEnum): + CANDLE_SOURCE_UNSPECIFIED = 0 + CANDLE_SOURCE_EXCHANGE = 1 + CANDLE_SOURCE_DEALER_WEEKEND = 2 + + +@dataclass +class GetCandlesResponse: + candles: List['HistoricCandle'] + + +@dataclass +class HistoricCandle: + open: 'Quotation' + high: 'Quotation' + low: 'Quotation' + close: 'Quotation' + volume: int + time: datetime + is_complete: bool + candle_source: 'CandleSource' + + +@dataclass +class GetLastPricesRequest: + figi: List[str] + instrument_id: List[str] + last_price_type: 'LastPriceType' + + +@dataclass +class GetLastPricesResponse: + last_prices: List['LastPrice'] + + +@dataclass +class LastPrice: + figi: str + price: 'Quotation' + time: datetime + instrument_uid: str + last_price_type: 'LastPriceType' + + +@dataclass +class GetOrderBookRequest: + depth: int + figi: Optional[str] = None + instrument_id: Optional[str] = None + + +@dataclass +class GetOrderBookResponse: + figi: str + depth: int + bids: List['Order'] + asks: List['Order'] + last_price: 'Quotation' + close_price: 'Quotation' + limit_up: 'Quotation' + limit_down: 'Quotation' + last_price_ts: datetime + close_price_ts: datetime + orderbook_ts: datetime + instrument_uid: str + + +@dataclass +class GetTradingStatusRequest: + figi: Optional[str] = None + instrument_id: Optional[str] = None + + +@dataclass +class GetTradingStatusesRequest: + instrument_id: List[str] + + +@dataclass +class GetTradingStatusesResponse: + trading_statuses: List['GetTradingStatusResponse'] + + +@dataclass +class GetTradingStatusResponse: + figi: str + trading_status: 'SecurityTradingStatus' + limit_order_available_flag: bool + market_order_available_flag: bool + api_trade_available_flag: bool + instrument_uid: str + bestprice_order_available_flag: bool + only_best_price: bool + + +@dataclass +class GetLastTradesRequest: + from_: datetime + to: datetime + figi: Optional[str] = None + instrument_id: Optional[str] = None + + +@dataclass +class GetLastTradesResponse: + trades: List['Trade'] + + +@dataclass +class GetMySubscriptions: + pass + + +@dataclass +class GetClosePricesRequest: + instruments: List['InstrumentClosePriceRequest'] + + +@dataclass +class InstrumentClosePriceRequest: + instrument_id: str + + +@dataclass +class GetClosePricesResponse: + close_prices: List['InstrumentClosePriceResponse'] + + +@dataclass +class InstrumentClosePriceResponse: + figi: str + instrument_uid: str + price: 'Quotation' + evening_session_price: 'Quotation' + time: datetime + + +@dataclass +class GetTechAnalysisRequest: + indicator_type: 'IndicatorType' + instrument_uid: str + from_: datetime + to: datetime + interval: 'IndicatorInterval' + type_of_price: 'TypeOfPrice' + length: int + deviation: 'Deviation' + smoothing: 'Smoothing' + + + @dataclass + class Smoothing: + fast_length: int + slow_length: int + signal_smoothing: int + + + @dataclass + class Deviation: + deviation_multiplier: 'Quotation' + + + class IndicatorInterval(IntEnum): + INDICATOR_INTERVAL_UNSPECIFIED = 0 + INDICATOR_INTERVAL_ONE_MINUTE = 1 + INDICATOR_INTERVAL_FIVE_MINUTES = 2 + INDICATOR_INTERVAL_FIFTEEN_MINUTES = 3 + INDICATOR_INTERVAL_ONE_HOUR = 4 + INDICATOR_INTERVAL_ONE_DAY = 5 + INDICATOR_INTERVAL_2_MIN = 6 + INDICATOR_INTERVAL_3_MIN = 7 + INDICATOR_INTERVAL_10_MIN = 8 + INDICATOR_INTERVAL_30_MIN = 9 + INDICATOR_INTERVAL_2_HOUR = 10 + INDICATOR_INTERVAL_4_HOUR = 11 + INDICATOR_INTERVAL_WEEK = 12 + INDICATOR_INTERVAL_MONTH = 13 + + + class TypeOfPrice(IntEnum): + TYPE_OF_PRICE_UNSPECIFIED = 0 + TYPE_OF_PRICE_CLOSE = 1 + TYPE_OF_PRICE_OPEN = 2 + TYPE_OF_PRICE_HIGH = 3 + TYPE_OF_PRICE_LOW = 4 + TYPE_OF_PRICE_AVG = 5 + + + class IndicatorType(IntEnum): + INDICATOR_TYPE_UNSPECIFIED = 0 + INDICATOR_TYPE_BB = 1 + INDICATOR_TYPE_EMA = 2 + INDICATOR_TYPE_RSI = 3 + INDICATOR_TYPE_MACD = 4 + INDICATOR_TYPE_SMA = 5 + + +@dataclass +class GetTechAnalysisResponse: + technical_indicators: List['TechAnalysisItem'] + + + @dataclass + class TechAnalysisItem: + timestamp: datetime + middle_band: Optional['Quotation'] = None + upper_band: Optional['Quotation'] = None + lower_band: Optional['Quotation'] = None + signal: Optional['Quotation'] = None + macd: Optional['Quotation'] = None + + +class OrderBookType(IntEnum): + ORDERBOOK_TYPE_UNSPECIFIED = 0 + ORDERBOOK_TYPE_EXCHANGE = 1 + ORDERBOOK_TYPE_DEALER = 2 + + +class LastPriceType(IntEnum): + LAST_PRICE_UNSPECIFIED = 0 + LAST_PRICE_EXCHANGE = 1 + LAST_PRICE_DEALER = 2 diff --git a/tinkoff/invest/grpc/operations.py b/tinkoff/invest/grpc/operations.py new file mode 100644 index 0000000..e7a4dd4 --- /dev/null +++ b/tinkoff/invest/grpc/operations.py @@ -0,0 +1,615 @@ +from dataclasses import dataclass +from datetime import datetime +from enum import IntEnum +from typing import Iterable, List, Optional + +from iprotopy import dataclass_to_protobuf, protobuf_to_dataclass + +from base_service import BaseService +from tinkoff.invest.grpc import operations_pb2, operations_pb2_grpc +from tinkoff.invest.grpc.common import InstrumentType, MoneyValue, Ping, Quotation + + +class OperationsService(BaseService): + """/*С помощью методов сервиса можно получить:

**1**. Список операций по счёту.
**2**. + Портфель по счёту.
**3**. Позиции ценных бумаг на счёте.
**4**. + Доступный остаток для вывода средств.
**5**. Различные отчёты.*/""" + _protobuf = operations_pb2 + _protobuf_grpc = operations_pb2_grpc + _protobuf_stub = _protobuf_grpc.OperationsServiceStub + + def GetOperations(self, request: 'OperationsRequest' + ) ->'OperationsResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + OperationsRequest()) + response, call = self._stub.GetOperations.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, OperationsResponse) + + def GetPortfolio(self, request: 'PortfolioRequest') ->'PortfolioResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + PortfolioRequest()) + response, call = self._stub.GetPortfolio.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, PortfolioResponse) + + def GetPositions(self, request: 'PositionsRequest') ->'PositionsResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + PositionsRequest()) + response, call = self._stub.GetPositions.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, PositionsResponse) + + def GetWithdrawLimits(self, request: 'WithdrawLimitsRequest' + ) ->'WithdrawLimitsResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + WithdrawLimitsRequest()) + response, call = self._stub.GetWithdrawLimits.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, WithdrawLimitsResponse) + + def GetBrokerReport(self, request: 'BrokerReportRequest' + ) ->'BrokerReportResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + BrokerReportRequest()) + response, call = self._stub.GetBrokerReport.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, BrokerReportResponse) + + def GetDividendsForeignIssuer(self, request: + 'GetDividendsForeignIssuerRequest' + ) ->'GetDividendsForeignIssuerResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetDividendsForeignIssuerRequest()) + response, call = self._stub.GetDividendsForeignIssuer.with_call(request + =protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, + GetDividendsForeignIssuerResponse) + + def GetOperationsByCursor(self, request: 'GetOperationsByCursorRequest' + ) ->'GetOperationsByCursorResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetOperationsByCursorRequest()) + response, call = self._stub.GetOperationsByCursor.with_call(request + =protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, GetOperationsByCursorResponse) + + +class OperationsStreamService(BaseService): + """//Server-side stream обновлений портфеля.""" + _protobuf = operations_pb2 + _protobuf_grpc = operations_pb2_grpc + _protobuf_stub = _protobuf_grpc.OperationsStreamServiceStub + + def PortfolioStream(self, request: 'PortfolioStreamRequest') ->Iterable[ + 'PortfolioStreamResponse']: + for response in self._stub.PortfolioStream(request= + dataclass_to_protobuf(request, self._protobuf. + PortfolioStreamRequest()), metadata=self._metadata): + yield protobuf_to_dataclass(response, PortfolioStreamResponse) + + def PositionsStream(self, request: 'PositionsStreamRequest') ->Iterable[ + 'PositionsStreamResponse']: + for response in self._stub.PositionsStream(request= + dataclass_to_protobuf(request, self._protobuf. + PositionsStreamRequest()), metadata=self._metadata): + yield protobuf_to_dataclass(response, PositionsStreamResponse) + + +@dataclass +class OperationsRequest: + account_id: str + from_: Optional[datetime] = None + to: Optional[datetime] = None + state: Optional['OperationState'] = None + figi: Optional[str] = None + + +@dataclass +class OperationsResponse: + operations: List['Operation'] + + +@dataclass +class Operation: + id: str + parent_operation_id: str + currency: str + payment: 'MoneyValue' + price: 'MoneyValue' + state: 'OperationState' + quantity: int + quantity_rest: int + figi: str + instrument_type: str + date: datetime + type: str + operation_type: 'OperationType' + trades: List['OperationTrade'] + asset_uid: str + position_uid: str + instrument_uid: str + child_operations: List['ChildOperationItem'] + + +@dataclass +class OperationTrade: + trade_id: str + date_time: datetime + quantity: int + price: 'MoneyValue' + + +@dataclass +class PortfolioRequest: + account_id: str + currency: Optional['CurrencyRequest'] = None + + + class CurrencyRequest(IntEnum): + RUB = 0 + USD = 1 + EUR = 2 + + +@dataclass +class PortfolioResponse: + total_amount_shares: 'MoneyValue' + total_amount_bonds: 'MoneyValue' + total_amount_etf: 'MoneyValue' + total_amount_currencies: 'MoneyValue' + total_amount_futures: 'MoneyValue' + expected_yield: 'Quotation' + positions: List['PortfolioPosition'] + account_id: str + total_amount_options: 'MoneyValue' + total_amount_sp: 'MoneyValue' + total_amount_portfolio: 'MoneyValue' + virtual_positions: List['VirtualPortfolioPosition'] + + +@dataclass +class PositionsRequest: + account_id: str + + +@dataclass +class PositionsResponse: + money: List['MoneyValue'] + blocked: List['MoneyValue'] + securities: List['PositionsSecurities'] + limits_loading_in_progress: bool + futures: List['PositionsFutures'] + options: List['PositionsOptions'] + + +@dataclass +class WithdrawLimitsRequest: + account_id: str + + +@dataclass +class WithdrawLimitsResponse: + money: List['MoneyValue'] + blocked: List['MoneyValue'] + blocked_guarantee: List['MoneyValue'] + + +@dataclass +class PortfolioPosition: + figi: str + instrument_type: str + quantity: 'Quotation' + average_position_price: 'MoneyValue' + expected_yield: 'Quotation' + current_nkd: 'MoneyValue' + average_position_price_pt: 'Quotation' + current_price: 'MoneyValue' + average_position_price_fifo: 'MoneyValue' + quantity_lots: 'Quotation' + blocked: bool + blocked_lots: 'Quotation' + position_uid: str + instrument_uid: str + var_margin: 'MoneyValue' + expected_yield_fifo: 'Quotation' + + +@dataclass +class VirtualPortfolioPosition: + position_uid: str + instrument_uid: str + figi: str + instrument_type: str + quantity: 'Quotation' + average_position_price: 'MoneyValue' + expected_yield: 'Quotation' + expected_yield_fifo: 'Quotation' + expire_date: datetime + current_price: 'MoneyValue' + average_position_price_fifo: 'MoneyValue' + + +@dataclass +class PositionsSecurities: + figi: str + blocked: int + balance: int + position_uid: str + instrument_uid: str + exchange_blocked: bool + instrument_type: str + + +@dataclass +class PositionsFutures: + figi: str + blocked: int + balance: int + position_uid: str + instrument_uid: str + + +@dataclass +class PositionsOptions: + position_uid: str + instrument_uid: str + blocked: int + balance: int + + +@dataclass +class BrokerReportRequest: + generate_broker_report_request: Optional['GenerateBrokerReportRequest' + ] = None + get_broker_report_request: Optional['GetBrokerReportRequest'] = None + + +@dataclass +class BrokerReportResponse: + generate_broker_report_response: Optional['GenerateBrokerReportResponse' + ] = None + get_broker_report_response: Optional['GetBrokerReportResponse'] = None + + +@dataclass +class GenerateBrokerReportRequest: + account_id: str + from_: datetime + to: datetime + + +@dataclass +class GenerateBrokerReportResponse: + task_id: str + + +@dataclass +class GetBrokerReportRequest: + task_id: str + page: Optional[int] = None + + +@dataclass +class GetBrokerReportResponse: + broker_report: List['BrokerReport'] + itemsCount: int + pagesCount: int + page: int + + +@dataclass +class BrokerReport: + trade_id: str + order_id: str + figi: str + execute_sign: str + trade_datetime: datetime + exchange: str + class_code: str + direction: str + name: str + ticker: str + price: 'MoneyValue' + quantity: int + order_amount: 'MoneyValue' + aci_value: 'Quotation' + total_order_amount: 'MoneyValue' + broker_commission: 'MoneyValue' + exchange_commission: 'MoneyValue' + exchange_clearing_commission: 'MoneyValue' + repo_rate: 'Quotation' + party: str + clear_value_date: datetime + sec_value_date: datetime + broker_status: str + separate_agreement_type: str + separate_agreement_number: str + separate_agreement_date: str + delivery_type: str + + +class OperationState(IntEnum): + OPERATION_STATE_UNSPECIFIED = 0 + OPERATION_STATE_EXECUTED = 1 + OPERATION_STATE_CANCELED = 2 + OPERATION_STATE_PROGRESS = 3 + + +class OperationType(IntEnum): + OPERATION_TYPE_UNSPECIFIED = 0 + OPERATION_TYPE_INPUT = 1 + OPERATION_TYPE_BOND_TAX = 2 + OPERATION_TYPE_OUTPUT_SECURITIES = 3 + OPERATION_TYPE_OVERNIGHT = 4 + OPERATION_TYPE_TAX = 5 + OPERATION_TYPE_BOND_REPAYMENT_FULL = 6 + OPERATION_TYPE_SELL_CARD = 7 + OPERATION_TYPE_DIVIDEND_TAX = 8 + OPERATION_TYPE_OUTPUT = 9 + OPERATION_TYPE_BOND_REPAYMENT = 10 + OPERATION_TYPE_TAX_CORRECTION = 11 + OPERATION_TYPE_SERVICE_FEE = 12 + OPERATION_TYPE_BENEFIT_TAX = 13 + OPERATION_TYPE_MARGIN_FEE = 14 + OPERATION_TYPE_BUY = 15 + OPERATION_TYPE_BUY_CARD = 16 + OPERATION_TYPE_INPUT_SECURITIES = 17 + OPERATION_TYPE_SELL_MARGIN = 18 + OPERATION_TYPE_BROKER_FEE = 19 + OPERATION_TYPE_BUY_MARGIN = 20 + OPERATION_TYPE_DIVIDEND = 21 + OPERATION_TYPE_SELL = 22 + OPERATION_TYPE_COUPON = 23 + OPERATION_TYPE_SUCCESS_FEE = 24 + OPERATION_TYPE_DIVIDEND_TRANSFER = 25 + OPERATION_TYPE_ACCRUING_VARMARGIN = 26 + OPERATION_TYPE_WRITING_OFF_VARMARGIN = 27 + OPERATION_TYPE_DELIVERY_BUY = 28 + OPERATION_TYPE_DELIVERY_SELL = 29 + OPERATION_TYPE_TRACK_MFEE = 30 + OPERATION_TYPE_TRACK_PFEE = 31 + OPERATION_TYPE_TAX_PROGRESSIVE = 32 + OPERATION_TYPE_BOND_TAX_PROGRESSIVE = 33 + OPERATION_TYPE_DIVIDEND_TAX_PROGRESSIVE = 34 + OPERATION_TYPE_BENEFIT_TAX_PROGRESSIVE = 35 + OPERATION_TYPE_TAX_CORRECTION_PROGRESSIVE = 36 + OPERATION_TYPE_TAX_REPO_PROGRESSIVE = 37 + OPERATION_TYPE_TAX_REPO = 38 + OPERATION_TYPE_TAX_REPO_HOLD = 39 + OPERATION_TYPE_TAX_REPO_REFUND = 40 + OPERATION_TYPE_TAX_REPO_HOLD_PROGRESSIVE = 41 + OPERATION_TYPE_TAX_REPO_REFUND_PROGRESSIVE = 42 + OPERATION_TYPE_DIV_EXT = 43 + OPERATION_TYPE_TAX_CORRECTION_COUPON = 44 + OPERATION_TYPE_CASH_FEE = 45 + OPERATION_TYPE_OUT_FEE = 46 + OPERATION_TYPE_OUT_STAMP_DUTY = 47 + OPERATION_TYPE_OUTPUT_SWIFT = 50 + OPERATION_TYPE_INPUT_SWIFT = 51 + OPERATION_TYPE_OUTPUT_ACQUIRING = 53 + OPERATION_TYPE_INPUT_ACQUIRING = 54 + OPERATION_TYPE_OUTPUT_PENALTY = 55 + OPERATION_TYPE_ADVICE_FEE = 56 + OPERATION_TYPE_TRANS_IIS_BS = 57 + OPERATION_TYPE_TRANS_BS_BS = 58 + OPERATION_TYPE_OUT_MULTI = 59 + OPERATION_TYPE_INP_MULTI = 60 + OPERATION_TYPE_OVER_PLACEMENT = 61 + OPERATION_TYPE_OVER_COM = 62 + OPERATION_TYPE_OVER_INCOME = 63 + OPERATION_TYPE_OPTION_EXPIRATION = 64 + OPERATION_TYPE_FUTURE_EXPIRATION = 65 + + +@dataclass +class GetDividendsForeignIssuerRequest: + generate_div_foreign_issuer_report: Optional[ + 'GenerateDividendsForeignIssuerReportRequest'] = None + get_div_foreign_issuer_report: Optional[ + 'GetDividendsForeignIssuerReportRequest'] = None + + +@dataclass +class GetDividendsForeignIssuerResponse: + generate_div_foreign_issuer_report_response: Optional[ + 'GenerateDividendsForeignIssuerReportResponse'] = None + div_foreign_issuer_report: Optional[ + 'GetDividendsForeignIssuerReportResponse'] = None + + +@dataclass +class GenerateDividendsForeignIssuerReportRequest: + account_id: str + from_: datetime + to: datetime + + +@dataclass +class GetDividendsForeignIssuerReportRequest: + task_id: str + page: Optional[int] = None + + +@dataclass +class GenerateDividendsForeignIssuerReportResponse: + task_id: str + + +@dataclass +class GetDividendsForeignIssuerReportResponse: + dividends_foreign_issuer_report: List['DividendsForeignIssuerReport'] + itemsCount: int + pagesCount: int + page: int + + +@dataclass +class DividendsForeignIssuerReport: + record_date: datetime + payment_date: datetime + security_name: str + isin: str + issuer_country: str + quantity: int + dividend: 'Quotation' + external_commission: 'Quotation' + dividend_gross: 'Quotation' + tax: 'Quotation' + dividend_amount: 'Quotation' + currency: str + + +@dataclass +class PortfolioStreamRequest: + accounts: List[str] + + +@dataclass +class PortfolioStreamResponse: + subscriptions: Optional['PortfolioSubscriptionResult'] = None + portfolio: Optional['PortfolioResponse'] = None + ping: Optional['Ping'] = None + + +@dataclass +class PortfolioSubscriptionResult: + accounts: List['AccountSubscriptionStatus'] + tracking_id: str + stream_id: str + + +@dataclass +class AccountSubscriptionStatus: + account_id: str + subscription_status: 'PortfolioSubscriptionStatus' + + +class PortfolioSubscriptionStatus(IntEnum): + PORTFOLIO_SUBSCRIPTION_STATUS_UNSPECIFIED = 0 + PORTFOLIO_SUBSCRIPTION_STATUS_SUCCESS = 1 + PORTFOLIO_SUBSCRIPTION_STATUS_ACCOUNT_NOT_FOUND = 2 + PORTFOLIO_SUBSCRIPTION_STATUS_INTERNAL_ERROR = 3 + + +@dataclass +class GetOperationsByCursorRequest: + account_id: str + operation_types: List['OperationType'] + instrument_id: Optional[str] = None + from_: Optional[datetime] = None + to: Optional[datetime] = None + cursor: Optional[str] = None + limit: Optional[int] = None + state: Optional['OperationState'] = None + without_commissions: Optional[bool] = None + without_trades: Optional[bool] = None + without_overnights: Optional[bool] = None + + +@dataclass +class GetOperationsByCursorResponse: + has_next: bool + next_cursor: str + items: List['OperationItem'] + + +@dataclass +class OperationItem: + cursor: str + broker_account_id: str + id: str + parent_operation_id: str + name: str + date: datetime + type: 'OperationType' + description: str + state: 'OperationState' + instrument_uid: str + figi: str + instrument_type: str + instrument_kind: 'InstrumentType' + position_uid: str + payment: 'MoneyValue' + price: 'MoneyValue' + commission: 'MoneyValue' + yield_: 'MoneyValue' + yield_relative: 'Quotation' + accrued_int: 'MoneyValue' + quantity: int + quantity_rest: int + quantity_done: int + cancel_date_time: datetime + cancel_reason: str + trades_info: 'OperationItemTrades' + asset_uid: str + child_operations: List['ChildOperationItem'] + + +@dataclass +class OperationItemTrades: + trades: List['OperationItemTrade'] + + +@dataclass +class OperationItemTrade: + num: str + date: datetime + quantity: int + price: 'MoneyValue' + yield_: 'MoneyValue' + yield_relative: 'Quotation' + + +@dataclass +class PositionsStreamRequest: + accounts: List[str] + + +@dataclass +class PositionsStreamResponse: + subscriptions: Optional['PositionsSubscriptionResult'] = None + position: Optional['PositionData'] = None + ping: Optional['Ping'] = None + + +@dataclass +class PositionsSubscriptionResult: + accounts: List['PositionsSubscriptionStatus'] + tracking_id: str + stream_id: str + + +@dataclass +class PositionsSubscriptionStatus: + account_id: str + subscription_status: 'PositionsAccountSubscriptionStatus' + + +class PositionsAccountSubscriptionStatus(IntEnum): + POSITIONS_SUBSCRIPTION_STATUS_UNSPECIFIED = 0 + POSITIONS_SUBSCRIPTION_STATUS_SUCCESS = 1 + POSITIONS_SUBSCRIPTION_STATUS_ACCOUNT_NOT_FOUND = 2 + POSITIONS_SUBSCRIPTION_STATUS_INTERNAL_ERROR = 3 + + +@dataclass +class PositionData: + account_id: str + money: List['PositionsMoney'] + securities: List['PositionsSecurities'] + futures: List['PositionsFutures'] + options: List['PositionsOptions'] + date: datetime + + +@dataclass +class PositionsMoney: + available_value: 'MoneyValue' + blocked_value: 'MoneyValue' + + +@dataclass +class ChildOperationItem: + instrument_uid: str + payment: 'MoneyValue' diff --git a/tinkoff/invest/grpc/orders.py b/tinkoff/invest/grpc/orders.py new file mode 100644 index 0000000..8571611 --- /dev/null +++ b/tinkoff/invest/grpc/orders.py @@ -0,0 +1,441 @@ +from dataclasses import dataclass +from datetime import datetime +from enum import IntEnum +from typing import Iterable, List, Optional + +from iprotopy import dataclass_to_protobuf, protobuf_to_dataclass + +from base_service import BaseService +from tinkoff.invest.grpc import orders_pb2, orders_pb2_grpc +from tinkoff.invest.grpc.common import ( + ErrorDetail, + MoneyValue, + Ping, + PriceType, + Quotation, + ResponseMetadata, + ResultSubscriptionStatus, +) + + +class OrdersStreamService(BaseService): + """//Stream сделок пользователя""" + _protobuf = orders_pb2 + _protobuf_grpc = orders_pb2_grpc + _protobuf_stub = _protobuf_grpc.OrdersStreamServiceStub + + def TradesStream(self, request: 'TradesStreamRequest') ->Iterable[ + 'TradesStreamResponse']: + for response in self._stub.TradesStream(request= + dataclass_to_protobuf(request, self._protobuf. + TradesStreamRequest()), metadata=self._metadata): + yield protobuf_to_dataclass(response, TradesStreamResponse) + + def OrderStateStream(self, request: 'OrderStateStreamRequest') ->Iterable[ + 'OrderStateStreamResponse']: + for response in self._stub.OrderStateStream(request= + dataclass_to_protobuf(request, self._protobuf. + OrderStateStreamRequest()), metadata=self._metadata): + yield protobuf_to_dataclass(response, OrderStateStreamResponse) + + +class OrdersService(BaseService): + """/* Сервис предназначен для работы с торговыми поручениями:
**1**. + выставление;
**2**. отмена;
**3**. получение статуса;
**4**. + расчёт полной стоимости;
**5**. получение списка заявок.*/""" + _protobuf = orders_pb2 + _protobuf_grpc = orders_pb2_grpc + _protobuf_stub = _protobuf_grpc.OrdersServiceStub + + def PostOrder(self, request: 'PostOrderRequest') ->'PostOrderResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + PostOrderRequest()) + response, call = self._stub.PostOrder.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, PostOrderResponse) + + def PostOrderAsync(self, request: 'PostOrderAsyncRequest' + ) ->'PostOrderAsyncResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + PostOrderAsyncRequest()) + response, call = self._stub.PostOrderAsync.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, PostOrderAsyncResponse) + + def CancelOrder(self, request: 'CancelOrderRequest' + ) ->'CancelOrderResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + CancelOrderRequest()) + response, call = self._stub.CancelOrder.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, CancelOrderResponse) + + def GetOrderState(self, request: 'GetOrderStateRequest') ->'OrderState': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetOrderStateRequest()) + response, call = self._stub.GetOrderState.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, OrderState) + + def GetOrders(self, request: 'GetOrdersRequest') ->'GetOrdersResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetOrdersRequest()) + response, call = self._stub.GetOrders.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, GetOrdersResponse) + + def ReplaceOrder(self, request: 'ReplaceOrderRequest' + ) ->'PostOrderResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + ReplaceOrderRequest()) + response, call = self._stub.ReplaceOrder.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, PostOrderResponse) + + def GetMaxLots(self, request: 'GetMaxLotsRequest') ->'GetMaxLotsResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetMaxLotsRequest()) + response, call = self._stub.GetMaxLots.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, GetMaxLotsResponse) + + def GetOrderPrice(self, request: 'GetOrderPriceRequest' + ) ->'GetOrderPriceResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetOrderPriceRequest()) + response, call = self._stub.GetOrderPrice.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, GetOrderPriceResponse) + + +@dataclass +class TradesStreamRequest: + accounts: List[str] + + +@dataclass +class TradesStreamResponse: + order_trades: Optional['OrderTrades'] = None + ping: Optional['Ping'] = None + subscription: Optional['SubscriptionResponse'] = None + + +@dataclass +class OrderTrades: + order_id: str + created_at: datetime + direction: 'OrderDirection' + figi: str + trades: List['OrderTrade'] + account_id: str + instrument_uid: str + + +@dataclass +class OrderTrade: + date_time: datetime + price: 'Quotation' + quantity: int + trade_id: str + + +@dataclass +class PostOrderRequest: + quantity: int + direction: 'OrderDirection' + account_id: str + order_type: 'OrderType' + order_id: str + instrument_id: str + time_in_force: 'TimeInForceType' + price_type: 'PriceType' + figi: Optional[str] = None + price: Optional['Quotation'] = None + + +@dataclass +class PostOrderResponse: + order_id: str + execution_report_status: 'OrderExecutionReportStatus' + lots_requested: int + lots_executed: int + initial_order_price: 'MoneyValue' + executed_order_price: 'MoneyValue' + total_order_amount: 'MoneyValue' + initial_commission: 'MoneyValue' + executed_commission: 'MoneyValue' + aci_value: 'MoneyValue' + figi: str + direction: 'OrderDirection' + initial_security_price: 'MoneyValue' + order_type: 'OrderType' + message: str + initial_order_price_pt: 'Quotation' + instrument_uid: str + order_request_id: str + response_metadata: 'ResponseMetadata' + + +@dataclass +class PostOrderAsyncRequest: + instrument_id: str + quantity: int + direction: 'OrderDirection' + account_id: str + order_type: 'OrderType' + order_id: str + price: Optional['Quotation'] = None + time_in_force: Optional['TimeInForceType'] = None + price_type: Optional['PriceType'] = None + + +@dataclass +class PostOrderAsyncResponse: + order_request_id: str + execution_report_status: 'OrderExecutionReportStatus' + trade_intent_id: Optional[str] = None + + +@dataclass +class CancelOrderRequest: + account_id: str + order_id: str + order_id_type: Optional['OrderIdType'] = None + + +@dataclass +class CancelOrderResponse: + time: datetime + response_metadata: 'ResponseMetadata' + + +@dataclass +class GetOrderStateRequest: + account_id: str + order_id: str + price_type: 'PriceType' + order_id_type: Optional['OrderIdType'] = None + + +@dataclass +class GetOrdersRequest: + account_id: str + + +@dataclass +class GetOrdersResponse: + orders: List['OrderState'] + + +@dataclass +class OrderState: + order_id: str + execution_report_status: 'OrderExecutionReportStatus' + lots_requested: int + lots_executed: int + initial_order_price: 'MoneyValue' + executed_order_price: 'MoneyValue' + total_order_amount: 'MoneyValue' + average_position_price: 'MoneyValue' + initial_commission: 'MoneyValue' + executed_commission: 'MoneyValue' + figi: str + direction: 'OrderDirection' + initial_security_price: 'MoneyValue' + stages: List['OrderStage'] + service_commission: 'MoneyValue' + currency: str + order_type: 'OrderType' + order_date: datetime + instrument_uid: str + order_request_id: str + + +@dataclass +class OrderStage: + price: 'MoneyValue' + quantity: int + trade_id: str + execution_time: datetime + + +@dataclass +class ReplaceOrderRequest: + account_id: str + order_id: str + idempotency_key: str + quantity: int + price: Optional['Quotation'] = None + price_type: Optional['PriceType'] = None + + +@dataclass +class GetMaxLotsRequest: + account_id: str + instrument_id: str + price: Optional['Quotation'] = None + + +@dataclass +class GetMaxLotsResponse: + currency: str + buy_limits: 'BuyLimitsView' + buy_margin_limits: 'BuyLimitsView' + sell_limits: 'SellLimitsView' + sell_margin_limits: 'SellLimitsView' + + + @dataclass + class BuyLimitsView: + buy_money_amount: 'Quotation' + buy_max_lots: int + buy_max_market_lots: int + + + @dataclass + class SellLimitsView: + sell_max_lots: int + + +@dataclass +class GetOrderPriceRequest: + account_id: str + instrument_id: str + price: 'Quotation' + direction: 'OrderDirection' + quantity: int + + +@dataclass +class GetOrderPriceResponse: + total_order_amount: 'MoneyValue' + initial_order_amount: 'MoneyValue' + lots_requested: int + executed_commission: 'MoneyValue' + executed_commission_rub: 'MoneyValue' + service_commission: 'MoneyValue' + deal_commission: 'MoneyValue' + extra_bond: Optional['ExtraBond'] = None + extra_future: Optional['ExtraFuture'] = None + + + @dataclass + class ExtraBond: + aci_value: 'MoneyValue' + nominal_conversion_rate: 'Quotation' + + + @dataclass + class ExtraFuture: + initial_margin: 'MoneyValue' + + +@dataclass +class OrderStateStreamRequest: + accounts: List[str] + ping_delay_millis: Optional[int] = None + + +@dataclass +class SubscriptionResponse: + tracking_id: str + status: 'ResultSubscriptionStatus' + stream_id: str + accounts: List[str] + error: Optional['ErrorDetail'] = None + + +@dataclass +class OrderStateStreamResponse: + order_state: Optional['OrderState'] = None + ping: Optional['Ping'] = None + subscription: Optional['SubscriptionResponse'] = None + + + @dataclass + class OrderState: + order_id: str + client_code: str + created_at: datetime + execution_report_status: 'OrderExecutionReportStatus' + ticker: str + class_code: str + lot_size: int + direction: 'OrderDirection' + time_in_force: 'TimeInForceType' + order_type: 'OrderType' + account_id: str + initial_order_price: 'MoneyValue' + order_price: 'MoneyValue' + executed_order_price: 'MoneyValue' + currency: str + lots_requested: int + lots_executed: int + lots_left: int + lots_cancelled: int + trades: List['OrderTrade'] + completion_time: datetime + exchange: str + instrument_uid: str + order_request_id: Optional[str] = None + status_info: Optional['StatusCauseInfo'] = None + amount: Optional['MoneyValue'] = None + marker: Optional['MarkerType'] = None + + + class MarkerType(IntEnum): + MARKER_UNKNOWN = 0 + MARKER_BROKER = 1 + MARKER_CHAT = 2 + MARKER_PAPER = 3 + MARKER_MARGIN = 4 + MARKER_TKBNM = 5 + MARKER_SHORT = 6 + MARKER_SPECMM = 7 + MARKER_PO = 8 + + + class StatusCauseInfo(IntEnum): + CAUSE_UNSPECIFIED = 0 + CAUSE_CANCELLED_BY_CLIENT = 15 + CAUSE_CANCELLED_BY_EXCHANGE = 1 + CAUSE_CANCELLED_NOT_ENOUGH_POSITION = 2 + CAUSE_CANCELLED_BY_CLIENT_BLOCK = 3 + CAUSE_REJECTED_BY_BROKER = 4 + CAUSE_REJECTED_BY_EXCHANGE = 5 + CAUSE_CANCELLED_BY_BROKER = 6 + + +class OrderDirection(IntEnum): + ORDER_DIRECTION_UNSPECIFIED = 0 + ORDER_DIRECTION_BUY = 1 + ORDER_DIRECTION_SELL = 2 + + +class OrderType(IntEnum): + ORDER_TYPE_UNSPECIFIED = 0 + ORDER_TYPE_LIMIT = 1 + ORDER_TYPE_MARKET = 2 + ORDER_TYPE_BESTPRICE = 3 + + +class OrderExecutionReportStatus(IntEnum): + EXECUTION_REPORT_STATUS_UNSPECIFIED = 0 + EXECUTION_REPORT_STATUS_FILL = 1 + EXECUTION_REPORT_STATUS_REJECTED = 2 + EXECUTION_REPORT_STATUS_CANCELLED = 3 + EXECUTION_REPORT_STATUS_NEW = 4 + EXECUTION_REPORT_STATUS_PARTIALLYFILL = 5 + + +class TimeInForceType(IntEnum): + TIME_IN_FORCE_UNSPECIFIED = 0 + TIME_IN_FORCE_DAY = 1 + TIME_IN_FORCE_FILL_AND_KILL = 2 + TIME_IN_FORCE_FILL_OR_KILL = 3 + + +class OrderIdType(IntEnum): + ORDER_ID_TYPE_UNSPECIFIED = 0 + ORDER_ID_TYPE_EXCHANGE = 1 + ORDER_ID_TYPE_REQUEST = 2 diff --git a/tinkoff/invest/grpc/sandbox.py b/tinkoff/invest/grpc/sandbox.py new file mode 100644 index 0000000..67fe18c --- /dev/null +++ b/tinkoff/invest/grpc/sandbox.py @@ -0,0 +1,192 @@ +from dataclasses import dataclass +from typing import Optional + +from iprotopy import dataclass_to_protobuf, protobuf_to_dataclass + +from base_service import BaseService +from tinkoff.invest.grpc import sandbox_pb2, sandbox_pb2_grpc +from tinkoff.invest.grpc.common import MoneyValue +from tinkoff.invest.grpc.operations import ( + GetOperationsByCursorRequest, + GetOperationsByCursorResponse, + OperationsRequest, + OperationsResponse, + PortfolioRequest, + PortfolioResponse, + PositionsRequest, + PositionsResponse, + WithdrawLimitsRequest, + WithdrawLimitsResponse, +) +from tinkoff.invest.grpc.orders import ( + CancelOrderRequest, + CancelOrderResponse, + GetMaxLotsRequest, + GetMaxLotsResponse, + GetOrdersRequest, + GetOrdersResponse, + GetOrderStateRequest, + OrderState, + PostOrderRequest, + PostOrderResponse, + ReplaceOrderRequest, +) +from tinkoff.invest.grpc.users import GetAccountsRequest, GetAccountsResponse + + +class SandboxService(BaseService): + """// Методы для работы с песочницей T-Invest API""" + _protobuf = sandbox_pb2 + _protobuf_grpc = sandbox_pb2_grpc + _protobuf_stub = _protobuf_grpc.SandboxServiceStub + + def OpenSandboxAccount(self, request: 'OpenSandboxAccountRequest' + ) ->'OpenSandboxAccountResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + OpenSandboxAccountRequest()) + response, call = self._stub.OpenSandboxAccount.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, OpenSandboxAccountResponse) + + def GetSandboxAccounts(self, request: 'GetAccountsRequest' + ) ->'GetAccountsResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetAccountsRequest()) + response, call = self._stub.GetSandboxAccounts.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, GetAccountsResponse) + + def CloseSandboxAccount(self, request: 'CloseSandboxAccountRequest' + ) ->'CloseSandboxAccountResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + CloseSandboxAccountRequest()) + response, call = self._stub.CloseSandboxAccount.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, CloseSandboxAccountResponse) + + def PostSandboxOrder(self, request: 'PostOrderRequest' + ) ->'PostOrderResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + PostOrderRequest()) + response, call = self._stub.PostSandboxOrder.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, PostOrderResponse) + + def ReplaceSandboxOrder(self, request: 'ReplaceOrderRequest' + ) ->'PostOrderResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + ReplaceOrderRequest()) + response, call = self._stub.ReplaceSandboxOrder.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, PostOrderResponse) + + def GetSandboxOrders(self, request: 'GetOrdersRequest' + ) ->'GetOrdersResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetOrdersRequest()) + response, call = self._stub.GetSandboxOrders.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, GetOrdersResponse) + + def CancelSandboxOrder(self, request: 'CancelOrderRequest' + ) ->'CancelOrderResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + CancelOrderRequest()) + response, call = self._stub.CancelSandboxOrder.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, CancelOrderResponse) + + def GetSandboxOrderState(self, request: 'GetOrderStateRequest' + ) ->'OrderState': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetOrderStateRequest()) + response, call = self._stub.GetSandboxOrderState.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, OrderState) + + def GetSandboxPositions(self, request: 'PositionsRequest' + ) ->'PositionsResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + PositionsRequest()) + response, call = self._stub.GetSandboxPositions.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, PositionsResponse) + + def GetSandboxOperations(self, request: 'OperationsRequest' + ) ->'OperationsResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + OperationsRequest()) + response, call = self._stub.GetSandboxOperations.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, OperationsResponse) + + def GetSandboxOperationsByCursor(self, request: + 'GetOperationsByCursorRequest') ->'GetOperationsByCursorResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetOperationsByCursorRequest()) + response, call = self._stub.GetSandboxOperationsByCursor.with_call( + request=protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, GetOperationsByCursorResponse) + + def GetSandboxPortfolio(self, request: 'PortfolioRequest' + ) ->'PortfolioResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + PortfolioRequest()) + response, call = self._stub.GetSandboxPortfolio.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, PortfolioResponse) + + def SandboxPayIn(self, request: 'SandboxPayInRequest' + ) ->'SandboxPayInResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + SandboxPayInRequest()) + response, call = self._stub.SandboxPayIn.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, SandboxPayInResponse) + + def GetSandboxWithdrawLimits(self, request: 'WithdrawLimitsRequest' + ) ->'WithdrawLimitsResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + WithdrawLimitsRequest()) + response, call = self._stub.GetSandboxWithdrawLimits.with_call(request + =protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, WithdrawLimitsResponse) + + def GetSandboxMaxLots(self, request: 'GetMaxLotsRequest' + ) ->'GetMaxLotsResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetMaxLotsRequest()) + response, call = self._stub.GetSandboxMaxLots.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, GetMaxLotsResponse) + + +@dataclass +class OpenSandboxAccountRequest: + name: Optional[str] = None + + +@dataclass +class OpenSandboxAccountResponse: + account_id: str + + +@dataclass +class CloseSandboxAccountRequest: + account_id: str + + +@dataclass +class CloseSandboxAccountResponse: + pass + + +@dataclass +class SandboxPayInRequest: + account_id: str + amount: 'MoneyValue' + + +@dataclass +class SandboxPayInResponse: + balance: 'MoneyValue' diff --git a/tinkoff/invest/grpc/stoporders.py b/tinkoff/invest/grpc/stoporders.py new file mode 100644 index 0000000..a90dc35 --- /dev/null +++ b/tinkoff/invest/grpc/stoporders.py @@ -0,0 +1,188 @@ +from dataclasses import dataclass +from datetime import datetime +from enum import IntEnum +from typing import List, Optional + +from iprotopy import dataclass_to_protobuf, protobuf_to_dataclass + +from base_service import BaseService +from tinkoff.invest.grpc import stoporders_pb2, stoporders_pb2_grpc +from tinkoff.invest.grpc.common import ( + MoneyValue, + PriceType, + Quotation, + ResponseMetadata, +) + + +class StopOrdersService(BaseService): + """/* Сервис для работы со стоп-заявками: выставление, отмена, получение списка стоп-заявок.*/""" + _protobuf = stoporders_pb2 + _protobuf_grpc = stoporders_pb2_grpc + _protobuf_stub = _protobuf_grpc.StopOrdersServiceStub + + def PostStopOrder(self, request: 'PostStopOrderRequest' + ) ->'PostStopOrderResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + PostStopOrderRequest()) + response, call = self._stub.PostStopOrder.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, PostStopOrderResponse) + + def GetStopOrders(self, request: 'GetStopOrdersRequest' + ) ->'GetStopOrdersResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetStopOrdersRequest()) + response, call = self._stub.GetStopOrders.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, GetStopOrdersResponse) + + def CancelStopOrder(self, request: 'CancelStopOrderRequest' + ) ->'CancelStopOrderResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + CancelStopOrderRequest()) + response, call = self._stub.CancelStopOrder.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, CancelStopOrderResponse) + + +@dataclass +class PostStopOrderRequest: + quantity: int + direction: 'StopOrderDirection' + account_id: str + expiration_type: 'StopOrderExpirationType' + stop_order_type: 'StopOrderType' + instrument_id: str + exchange_order_type: 'ExchangeOrderType' + take_profit_type: 'TakeProfitType' + trailing_data: 'TrailingData' + price_type: 'PriceType' + order_id: str + figi: Optional[str] = None + price: Optional['Quotation'] = None + stop_price: Optional['Quotation'] = None + expire_date: Optional[datetime] = None + + + @dataclass + class TrailingData: + indent: 'Quotation' + indent_type: 'TrailingValueType' + spread: 'Quotation' + spread_type: 'TrailingValueType' + + +@dataclass +class PostStopOrderResponse: + stop_order_id: str + order_request_id: str + response_metadata: 'ResponseMetadata' + + +@dataclass +class GetStopOrdersRequest: + account_id: str + status: 'StopOrderStatusOption' + from_: datetime + to: datetime + + +@dataclass +class GetStopOrdersResponse: + stop_orders: List['StopOrder'] + + +@dataclass +class CancelStopOrderRequest: + account_id: str + stop_order_id: str + + +@dataclass +class CancelStopOrderResponse: + time: datetime + + +@dataclass +class StopOrder: + stop_order_id: str + lots_requested: int + figi: str + direction: 'StopOrderDirection' + currency: str + order_type: 'StopOrderType' + create_date: datetime + activation_date_time: datetime + expiration_time: datetime + price: 'MoneyValue' + stop_price: 'MoneyValue' + instrument_uid: str + take_profit_type: 'TakeProfitType' + trailing_data: 'TrailingData' + status: 'StopOrderStatusOption' + exchange_order_type: 'ExchangeOrderType' + exchange_order_id: Optional[str] = None + + + @dataclass + class TrailingData: + indent: 'Quotation' + indent_type: 'TrailingValueType' + spread: 'Quotation' + spread_type: 'TrailingValueType' + status: 'TrailingStopStatus' + price: 'Quotation' + extr: 'Quotation' + + +class StopOrderDirection(IntEnum): + STOP_ORDER_DIRECTION_UNSPECIFIED = 0 + STOP_ORDER_DIRECTION_BUY = 1 + STOP_ORDER_DIRECTION_SELL = 2 + + +class StopOrderExpirationType(IntEnum): + STOP_ORDER_EXPIRATION_TYPE_UNSPECIFIED = 0 + STOP_ORDER_EXPIRATION_TYPE_GOOD_TILL_CANCEL = 1 + STOP_ORDER_EXPIRATION_TYPE_GOOD_TILL_DATE = 2 + + +class StopOrderType(IntEnum): + STOP_ORDER_TYPE_UNSPECIFIED = 0 + STOP_ORDER_TYPE_TAKE_PROFIT = 1 + STOP_ORDER_TYPE_STOP_LOSS = 2 + STOP_ORDER_TYPE_STOP_LIMIT = 3 + + +class StopOrderStatusOption(IntEnum): + STOP_ORDER_STATUS_UNSPECIFIED = 0 + STOP_ORDER_STATUS_ALL = 1 + STOP_ORDER_STATUS_ACTIVE = 2 + STOP_ORDER_STATUS_EXECUTED = 3 + STOP_ORDER_STATUS_CANCELED = 4 + STOP_ORDER_STATUS_EXPIRED = 5 + + +class ExchangeOrderType(IntEnum): + EXCHANGE_ORDER_TYPE_UNSPECIFIED = 0 + EXCHANGE_ORDER_TYPE_MARKET = 1 + EXCHANGE_ORDER_TYPE_LIMIT = 2 + + +class TakeProfitType(IntEnum): + TAKE_PROFIT_TYPE_UNSPECIFIED = 0 + TAKE_PROFIT_TYPE_REGULAR = 1 + TAKE_PROFIT_TYPE_TRAILING = 2 + + +class TrailingValueType(IntEnum): + TRAILING_VALUE_UNSPECIFIED = 0 + TRAILING_VALUE_ABSOLUTE = 1 + TRAILING_VALUE_RELATIVE = 2 + + +class TrailingStopStatus(IntEnum): + TRAILING_STOP_UNSPECIFIED = 0 + TRAILING_STOP_ACTIVE = 1 + TRAILING_STOP_ACTIVATED = 2 diff --git a/tinkoff/invest/grpc/users.py b/tinkoff/invest/grpc/users.py new file mode 100644 index 0000000..8b49842 --- /dev/null +++ b/tinkoff/invest/grpc/users.py @@ -0,0 +1,145 @@ +from dataclasses import dataclass +from datetime import datetime +from enum import IntEnum +from typing import List, Optional + +from iprotopy import dataclass_to_protobuf, protobuf_to_dataclass + +from base_service import BaseService +from tinkoff.invest.grpc import users_pb2, users_pb2_grpc +from tinkoff.invest.grpc.common import MoneyValue, Quotation + + +class UsersService(BaseService): + """/*С помощью сервиса можно получить:
1. + список счетов пользователя;
2. маржинальные показатели по счёту.*/""" + _protobuf = users_pb2 + _protobuf_grpc = users_pb2_grpc + _protobuf_stub = _protobuf_grpc.UsersServiceStub + + def GetAccounts(self, request: 'GetAccountsRequest' + ) ->'GetAccountsResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetAccountsRequest()) + response, call = self._stub.GetAccounts.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, GetAccountsResponse) + + def GetMarginAttributes(self, request: 'GetMarginAttributesRequest' + ) ->'GetMarginAttributesResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetMarginAttributesRequest()) + response, call = self._stub.GetMarginAttributes.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, GetMarginAttributesResponse) + + def GetUserTariff(self, request: 'GetUserTariffRequest' + ) ->'GetUserTariffResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetUserTariffRequest()) + response, call = self._stub.GetUserTariff.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, GetUserTariffResponse) + + def GetInfo(self, request: 'GetInfoRequest') ->'GetInfoResponse': + protobuf_request = dataclass_to_protobuf(request, self._protobuf. + GetInfoRequest()) + response, call = self._stub.GetInfo.with_call(request= + protobuf_request, metadata=self._metadata) + return protobuf_to_dataclass(response, GetInfoResponse) + + +@dataclass +class GetAccountsRequest: + status: Optional['AccountStatus'] = None + + +@dataclass +class GetAccountsResponse: + accounts: List['Account'] + + +@dataclass +class Account: + id: str + type: 'AccountType' + name: str + status: 'AccountStatus' + opened_date: datetime + closed_date: datetime + access_level: 'AccessLevel' + + +class AccountType(IntEnum): + ACCOUNT_TYPE_UNSPECIFIED = 0 + ACCOUNT_TYPE_TINKOFF = 1 + ACCOUNT_TYPE_TINKOFF_IIS = 2 + ACCOUNT_TYPE_INVEST_BOX = 3 + ACCOUNT_TYPE_INVEST_FUND = 4 + + +class AccountStatus(IntEnum): + ACCOUNT_STATUS_UNSPECIFIED = 0 + ACCOUNT_STATUS_NEW = 1 + ACCOUNT_STATUS_OPEN = 2 + ACCOUNT_STATUS_CLOSED = 3 + ACCOUNT_STATUS_ALL = 4 + + +@dataclass +class GetMarginAttributesRequest: + account_id: str + + +@dataclass +class GetMarginAttributesResponse: + liquid_portfolio: 'MoneyValue' + starting_margin: 'MoneyValue' + minimal_margin: 'MoneyValue' + funds_sufficiency_level: 'Quotation' + amount_of_missing_funds: 'MoneyValue' + corrected_margin: 'MoneyValue' + + +@dataclass +class GetUserTariffRequest: + pass + + +@dataclass +class GetUserTariffResponse: + unary_limits: List['UnaryLimit'] + stream_limits: List['StreamLimit'] + + +@dataclass +class UnaryLimit: + limit_per_minute: int + methods: List[str] + + +@dataclass +class StreamLimit: + limit: int + streams: List[str] + open: int + + +@dataclass +class GetInfoRequest: + pass + + +@dataclass +class GetInfoResponse: + prem_status: bool + qual_status: bool + qualified_for_work_with: List[str] + tariff: str + + +class AccessLevel(IntEnum): + ACCOUNT_ACCESS_LEVEL_UNSPECIFIED = 0 + ACCOUNT_ACCESS_LEVEL_FULL_ACCESS = 1 + ACCOUNT_ACCESS_LEVEL_READ_ONLY = 2 + ACCOUNT_ACCESS_LEVEL_NO_ACCESS = 3 diff --git a/tinkoff/invest/services.py b/tinkoff/invest/services.py index f48e01d..52fabfd 100644 --- a/tinkoff/invest/services.py +++ b/tinkoff/invest/services.py @@ -6,6 +6,10 @@ import grpc from deprecation import deprecated +from tinkoff.invest.grpc.marketdata import ( + MarketDataStreamService as NewMarketDataStreamService, +) + from . import _grpc_helpers from ._errors import handle_request_error, handle_request_error_gen from .grpc import ( @@ -221,7 +225,7 @@ def __init__( sandbox_metadata = get_metadata(sandbox_token or token, app_name) self.instruments = InstrumentsService(channel, metadata) self.market_data = MarketDataService(channel, metadata) - self.market_data_stream = MarketDataStreamService(channel, metadata) + self.market_data_stream = NewMarketDataStreamService(channel, metadata) self.operations = OperationsService(channel, metadata) self.operations_stream = OperationsStreamService(channel, metadata) self.orders_stream = OrdersStreamService(channel, metadata)