finam-sdk 2.16.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. finam_sdk-2.16.0/LICENSE +21 -0
  2. finam_sdk-2.16.0/PKG-INFO +297 -0
  3. finam_sdk-2.16.0/README.md +260 -0
  4. finam_sdk-2.16.0/finam_sdk.egg-info/PKG-INFO +297 -0
  5. finam_sdk-2.16.0/finam_sdk.egg-info/SOURCES.txt +92 -0
  6. finam_sdk-2.16.0/finam_sdk.egg-info/dependency_links.txt +1 -0
  7. finam_sdk-2.16.0/finam_sdk.egg-info/requires.txt +12 -0
  8. finam_sdk-2.16.0/finam_sdk.egg-info/top_level.txt +1 -0
  9. finam_sdk-2.16.0/finam_trade_api/__init__.py +53 -0
  10. finam_sdk-2.16.0/finam_trade_api/_metadata.py +69 -0
  11. finam_sdk-2.16.0/finam_trade_api/accounts.py +37 -0
  12. finam_sdk-2.16.0/finam_trade_api/aio.py +280 -0
  13. finam_sdk-2.16.0/finam_trade_api/assets.py +64 -0
  14. finam_sdk-2.16.0/finam_trade_api/auth.py +229 -0
  15. finam_sdk-2.16.0/finam_trade_api/auth_messages.py +32 -0
  16. finam_sdk-2.16.0/finam_trade_api/client.py +254 -0
  17. finam_sdk-2.16.0/finam_trade_api/exceptions.py +99 -0
  18. finam_sdk-2.16.0/finam_trade_api/market_data.py +63 -0
  19. finam_sdk-2.16.0/finam_trade_api/metrics.py +14 -0
  20. finam_sdk-2.16.0/finam_trade_api/orders.py +59 -0
  21. finam_sdk-2.16.0/finam_trade_api/proto/__init__.py +0 -0
  22. finam_sdk-2.16.0/finam_trade_api/proto/grpc/__init__.py +0 -0
  23. finam_sdk-2.16.0/finam_trade_api/proto/grpc/gateway/__init__.py +0 -0
  24. finam_sdk-2.16.0/finam_trade_api/proto/grpc/gateway/protoc_gen_openapiv2/__init__.py +0 -0
  25. finam_sdk-2.16.0/finam_trade_api/proto/grpc/gateway/protoc_gen_openapiv2/options/__init__.py +0 -0
  26. finam_sdk-2.16.0/finam_trade_api/proto/grpc/gateway/protoc_gen_openapiv2/options/annotations_pb2.py +37 -0
  27. finam_sdk-2.16.0/finam_trade_api/proto/grpc/gateway/protoc_gen_openapiv2/options/annotations_pb2.pyi +55 -0
  28. finam_sdk-2.16.0/finam_trade_api/proto/grpc/gateway/protoc_gen_openapiv2/options/annotations_pb2_grpc.py +24 -0
  29. finam_sdk-2.16.0/finam_trade_api/proto/grpc/gateway/protoc_gen_openapiv2/options/annotations_pb2_grpc.pyi +20 -0
  30. finam_sdk-2.16.0/finam_trade_api/proto/grpc/gateway/protoc_gen_openapiv2/options/openapiv2_pb2.py +148 -0
  31. finam_sdk-2.16.0/finam_trade_api/proto/grpc/gateway/protoc_gen_openapiv2/options/openapiv2_pb2.pyi +1743 -0
  32. finam_sdk-2.16.0/finam_trade_api/proto/grpc/gateway/protoc_gen_openapiv2/options/openapiv2_pb2_grpc.py +24 -0
  33. finam_sdk-2.16.0/finam_trade_api/proto/grpc/gateway/protoc_gen_openapiv2/options/openapiv2_pb2_grpc.pyi +20 -0
  34. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/__init__.py +0 -0
  35. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/__init__.py +0 -0
  36. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/accounts/__init__.py +0 -0
  37. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/accounts/accounts_service_pb2.py +79 -0
  38. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/accounts/accounts_service_pb2.pyi +568 -0
  39. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/accounts/accounts_service_pb2_grpc.py +250 -0
  40. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/accounts/accounts_service_pb2_grpc.pyi +154 -0
  41. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/assets/__init__.py +0 -0
  42. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/assets/assets_service_pb2.py +135 -0
  43. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/assets/assets_service_pb2.pyi +1104 -0
  44. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/assets/assets_service_pb2_grpc.py +485 -0
  45. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/assets/assets_service_pb2_grpc.pyi +285 -0
  46. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/auth/__init__.py +0 -0
  47. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/auth/auth_service_pb2.py +60 -0
  48. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/auth/auth_service_pb2.pyi +264 -0
  49. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/auth/auth_service_pb2_grpc.py +208 -0
  50. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/auth/auth_service_pb2_grpc.pyi +145 -0
  51. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/corporateactions/__init__.py +0 -0
  52. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/corporateactions/corporate_actions_service_pb2.py +76 -0
  53. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/corporateactions/corporate_actions_service_pb2.pyi +497 -0
  54. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/corporateactions/corporate_actions_service_pb2_grpc.py +233 -0
  55. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/corporateactions/corporate_actions_service_pb2_grpc.pyi +94 -0
  56. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/marketdata/__init__.py +0 -0
  57. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/marketdata/marketdata_service_pb2.py +107 -0
  58. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/marketdata/marketdata_service_pb2.pyi +1026 -0
  59. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/marketdata/marketdata_service_pb2_grpc.py +425 -0
  60. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/marketdata/marketdata_service_pb2_grpc.pyi +202 -0
  61. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/metrics/__init__.py +0 -0
  62. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/metrics/usage_metrics_service_pb2.py +48 -0
  63. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/metrics/usage_metrics_service_pb2.pyi +95 -0
  64. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/metrics/usage_metrics_service_pb2_grpc.py +110 -0
  65. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/metrics/usage_metrics_service_pb2_grpc.pyi +79 -0
  66. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/orders/__init__.py +0 -0
  67. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/orders/orders_service_pb2.py +103 -0
  68. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/orders/orders_service_pb2.pyi +887 -0
  69. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/orders/orders_service_pb2_grpc.py +469 -0
  70. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/orders/orders_service_pb2_grpc.pyi +348 -0
  71. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/reports/__init__.py +0 -0
  72. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/reports/reports_service_pb2.py +65 -0
  73. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/reports/reports_service_pb2.pyi +298 -0
  74. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/reports/reports_service_pb2_grpc.py +195 -0
  75. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/reports/reports_service_pb2_grpc.pyi +106 -0
  76. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/side_pb2.py +37 -0
  77. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/side_pb2.pyi +41 -0
  78. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/side_pb2_grpc.py +24 -0
  79. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/side_pb2_grpc.pyi +20 -0
  80. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/trade_pb2.py +40 -0
  81. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/trade_pb2.pyi +93 -0
  82. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/trade_pb2_grpc.py +24 -0
  83. finam_sdk-2.16.0/finam_trade_api/proto/grpc/tradeapi/v1/trade_pb2_grpc.pyi +20 -0
  84. finam_sdk-2.16.0/finam_trade_api/py.typed +0 -0
  85. finam_sdk-2.16.0/finam_trade_api/reports.py +33 -0
  86. finam_sdk-2.16.0/finam_trade_api/retry.py +204 -0
  87. finam_sdk-2.16.0/pyproject.toml +98 -0
  88. finam_sdk-2.16.0/setup.cfg +4 -0
  89. finam_sdk-2.16.0/tests/test_auth_manager.py +417 -0
  90. finam_sdk-2.16.0/tests/test_client_integration.py +348 -0
  91. finam_sdk-2.16.0/tests/test_exceptions.py +93 -0
  92. finam_sdk-2.16.0/tests/test_metadata.py +72 -0
  93. finam_sdk-2.16.0/tests/test_retry.py +341 -0
  94. finam_sdk-2.16.0/tests/test_shims.py +40 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Finam
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,297 @@
1
+ Metadata-Version: 2.4
2
+ Name: finam-sdk
3
+ Version: 2.16.0
4
+ Summary: Official Python SDK for the Finam Trade API (gRPC)
5
+ Author-email: Finam <tradeapi@finam.ru>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/FinamWeb/finam-trade-api
8
+ Project-URL: Documentation, https://tradeapi.finam.ru/
9
+ Project-URL: Repository, https://github.com/FinamWeb/finam-trade-api
10
+ Keywords: finam,trading,grpc,trade-api,brokerage
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: Financial and Insurance Industry
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Office/Business :: Financial :: Investment
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.9
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: grpcio>=1.60
26
+ Requires-Dist: protobuf>=4.25
27
+ Requires-Dist: googleapis-common-protos>=1.62
28
+ Provides-Extra: dev
29
+ Requires-Dist: pytest>=7; extra == "dev"
30
+ Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
31
+ Requires-Dist: pytest-cov>=4; extra == "dev"
32
+ Requires-Dist: mypy>=1.8; extra == "dev"
33
+ Requires-Dist: mypy-protobuf>=3.6; extra == "dev"
34
+ Requires-Dist: ruff>=0.3; extra == "dev"
35
+ Requires-Dist: grpcio-tools>=1.60; extra == "dev"
36
+ Dynamic: license-file
37
+
38
+ # Finam Trade API — Python SDK
39
+
40
+ Thin Python SDK for the [Finam Trade API](https://tradeapi.finam.ru/). Wraps
41
+ the generated gRPC stubs with:
42
+
43
+ - a single `FinamClient` / `AsyncFinamClient` entry point,
44
+ - automatic JWT issuance and background refresh (via `AuthService.SubscribeJwtRenewal`),
45
+ - typed exceptions mapped from gRPC status codes,
46
+ - exponential-backoff retries on transient failures (`UNAVAILABLE`, `RESOURCE_EXHAUSTED`).
47
+
48
+ Service methods are invoked directly on the generated stubs, so the full proto
49
+ surface is available without an extra translation layer.
50
+
51
+ ## Installation
52
+
53
+ ```sh
54
+ pip install finam-sdk
55
+ ```
56
+
57
+ > The PyPI distribution is `finam-sdk`; the Python import name is
58
+ > `finam_trade_api`. (The `finam-trade-api` name on PyPI is held by an
59
+ > unrelated third-party REST client.)
60
+
61
+ ## Quickstart (sync)
62
+
63
+ ```python
64
+ from finam_trade_api import FinamClient
65
+ from finam_trade_api.accounts import GetAccountRequest
66
+ from finam_trade_api.market_data import SubscribeQuoteRequest
67
+
68
+ with FinamClient(secret="YOUR_API_TOKEN") as client:
69
+ account = client.accounts.GetAccount(GetAccountRequest(account_id="A12345"))
70
+ print(account)
71
+
72
+ # Streaming RPCs return iterators.
73
+ for tick in client.market_data.SubscribeQuote(
74
+ SubscribeQuoteRequest(symbols=["SBER@MISX"])
75
+ ):
76
+ print(tick)
77
+ ```
78
+
79
+ ## Quickstart (asyncio)
80
+
81
+ ```python
82
+ import asyncio
83
+
84
+ from finam_trade_api import AsyncFinamClient
85
+ from finam_trade_api.market_data import SubscribeQuoteRequest
86
+
87
+
88
+ async def main() -> None:
89
+ async with AsyncFinamClient(secret="YOUR_API_TOKEN") as client:
90
+ async for tick in client.market_data.SubscribeQuote(
91
+ SubscribeQuoteRequest(symbols=["SBER@MISX"])
92
+ ):
93
+ print(tick)
94
+
95
+
96
+ asyncio.run(main())
97
+ ```
98
+
99
+ ## Available services
100
+
101
+ The client exposes the full Trade API surface via sub-clients:
102
+
103
+ | Attribute | gRPC service | What it does |
104
+ | -------------------- | ---------------------- | --------------------------------------------- |
105
+ | `client.auth` | `AuthService` | Token issuance + details (usually automatic). |
106
+ | `client.accounts` | `AccountsService` | Accounts, positions, trades, transactions. |
107
+ | `client.assets` | `AssetsService` | Instruments, exchanges, schedules, options. |
108
+ | `client.market_data` | `MarketDataService` | Bars, quotes, order book, trade streams. |
109
+ | `client.orders` | `OrdersService` | Place / cancel orders, order + trade streams. |
110
+ | `client.reports` | `ReportsService` | Account reports. |
111
+ | `client.metrics` | `UsageMetricsService` | API usage / quota metrics. |
112
+
113
+ ## API reference
114
+
115
+ Every RPC defined in the `.proto` files is exposed directly on the sub-client.
116
+ Request and response message types are re-exported from short, per-service
117
+ modules:
118
+
119
+ | Module | Use with |
120
+ | --- | --- |
121
+ | `finam_trade_api.accounts` | `client.accounts.*` |
122
+ | `finam_trade_api.assets` | `client.assets.*` |
123
+ | `finam_trade_api.market_data` | `client.market_data.*` |
124
+ | `finam_trade_api.orders` | `client.orders.*` (includes `Side`) |
125
+ | `finam_trade_api.reports` | `client.reports.*` |
126
+ | `finam_trade_api.metrics` | `client.metrics.*` |
127
+ | `finam_trade_api.auth_messages` | `client.auth.*` (rarely needed — JWT handled automatically) |
128
+
129
+ The original deeply-nested paths
130
+ (`finam_trade_api.proto.grpc.tradeapi.v1.<service>.<service>_service_pb2`)
131
+ still work and remain the source of truth.
132
+
133
+ Legend: ▶ unary · ⇉ server-stream · ⇄ bidi-stream
134
+
135
+ ### `client.auth` — `AuthService`
136
+
137
+ | Method | Kind | Purpose |
138
+ | --- | :---: | --- |
139
+ | `Auth(AuthRequest)` | ▶ | Exchange API secret for a JWT. *Called for you on construction.* |
140
+ | `TokenDetails(TokenDetailsRequest)` | ▶ | Inspect a JWT — expiry, market-data permissions, visible account IDs. |
141
+ | `SubscribeJwtRenewal(SubscribeJwtRenewalRequest)` | ⇉ | Stream of refreshed JWTs. *Consumed for you in the background.* |
142
+
143
+ ### `client.accounts` — `AccountsService`
144
+
145
+ | Method | Kind | Purpose |
146
+ | --- | :---: | --- |
147
+ | `GetAccount(GetAccountRequest)` | ▶ | Account info: equity, cash, positions, margin. |
148
+ | `Trades(TradesRequest)` | ▶ | Historical trades for an account. |
149
+ | `Transactions(TransactionsRequest)` | ▶ | Cash movements and other non-trade transactions. |
150
+ | `SubscribeAccount(GetAccountRequest)` | ⇉ | Streaming account updates. |
151
+
152
+ ### `client.assets` — `AssetsService`
153
+
154
+ | Method | Kind | Purpose |
155
+ | --- | :---: | --- |
156
+ | `Exchanges(ExchangesRequest)` | ▶ | List of supported exchanges. |
157
+ | `Assets(AssetsRequest)` | ▶ | Tradable instruments (filtered). |
158
+ | `AllAssets(AllAssetsRequest)` | ▶ | Full instrument catalog. |
159
+ | `GetAsset(GetAssetRequest)` | ▶ | Single instrument by symbol. |
160
+ | `GetAssetParams(GetAssetParamsRequest)` | ▶ | Trading parameters for an instrument. |
161
+ | `OptionsChain(OptionsChainRequest)` | ▶ | Options chain for an underlying. |
162
+ | `Schedule(ScheduleRequest)` | ▶ | Trading session schedule. |
163
+ | `Clock(ClockRequest)` | ▶ | Server clock (use for time-aligned operations). |
164
+ | `GetConstituents(GetConstituentsRequest)` | ▶ | Index constituents. |
165
+
166
+ ### `client.market_data` — `MarketDataService`
167
+
168
+ | Method | Kind | Purpose |
169
+ | --- | :---: | --- |
170
+ | `Bars(BarsRequest)` | ▶ | OHLC candles (any timeframe via `TimeFrame` enum). |
171
+ | `LastQuote(QuoteRequest)` | ▶ | Most recent quote snapshot. |
172
+ | `OrderBook(OrderBookRequest)` | ▶ | Order book snapshot. |
173
+ | `LatestTrades(LatestTradesRequest)` | ▶ | Most recent trades for a symbol. |
174
+ | `SubscribeQuote(SubscribeQuoteRequest)` | ⇉ | Live quote stream. |
175
+ | `SubscribeOrderBook(SubscribeOrderBookRequest)` | ⇉ | Live order-book updates. |
176
+ | `SubscribeLatestTrades(SubscribeLatestTradesRequest)` | ⇉ | Live trades stream. |
177
+ | `SubscribeBars(SubscribeBarsRequest)` | ⇉ | Live candle stream. |
178
+
179
+ ### `client.orders` — `OrdersService`
180
+
181
+ | Method | Kind | Purpose |
182
+ | --- | :---: | --- |
183
+ | `PlaceOrder(Order)` | ▶ | Place market / limit / stop / stop-limit / multi-leg order. |
184
+ | `PlaceSLTPOrder(SLTPOrder)` | ▶ | Place an SL/TP (stop-loss + take-profit) order. |
185
+ | `CancelOrder(CancelOrderRequest)` | ▶ | Cancel an active order. |
186
+ | `GetOrders(OrdersRequest)` | ▶ | List active orders for an account. |
187
+ | `GetOrder(GetOrderRequest)` | ▶ | Single order by ID. |
188
+ | `SubscribeOrders(SubscribeOrdersRequest)` | ⇉ | Live order-state updates. |
189
+ | `SubscribeTrades(SubscribeTradesRequest)` | ⇉ | Live execution / fill stream. |
190
+ | `SubscribeOrderTrade(stream OrderTradeRequest)` | ⇄ | Bidi stream — order + trade events, request-driven. |
191
+
192
+ ### `client.reports` — `ReportsService`
193
+
194
+ | Method | Kind | Purpose |
195
+ | --- | :---: | --- |
196
+ | `CreateAccountReport(CreateAccountReportRequest)` | ▶ | Generate an account report (async — returns a job handle). |
197
+ | `GetAccountReportInfo(GetAccountReportInfoRequest)` | ▶ | Poll report status. |
198
+ | `SubscribeAccountReportInfo(SubscribeAccountReportInfoRequest)` | ⇉ | Stream report status updates instead of polling. |
199
+
200
+ ### `client.metrics` — `UsageMetricsService`
201
+
202
+ | Method | Kind | Purpose |
203
+ | --- | :---: | --- |
204
+ | `GetUsageMetrics(GetUsageMetricsRequest)` | ▶ | API usage / quota stats for the current token. |
205
+
206
+ ### Client lifecycle
207
+
208
+ | Operation | Sync | Async |
209
+ | --- | --- | --- |
210
+ | Construct | `FinamClient(secret, *, endpoint=DEFAULT_ENDPOINT, retry_policy=DEFAULT_POLICY, channel_options=None)` | `AsyncFinamClient(secret, ...)` — same args |
211
+ | Start | *immediate, blocks for initial JWT* | `await client.start()` — or use `async with` |
212
+ | Current JWT | `client.get_token()` → `str \| None` | `client.get_token()` → `str \| None` (sync read of cached snapshot) |
213
+ | Close | `client.close()` | `await client.close()` |
214
+ | Context manager | `with FinamClient(...) as client:` | `async with AsyncFinamClient(...) as client:` |
215
+ | Testing (no TLS) | `FinamClient.for_testing(secret, endpoint="localhost:50051")` | `AsyncFinamClient.for_testing(secret, endpoint="localhost:50051")` |
216
+
217
+ > `for_testing(...)` opens an insecure (plaintext) channel against an in-process fake server. **Never use against `api.finam.ru`** — it sends your JWT in clear.
218
+
219
+ ## Error handling
220
+
221
+ Wrap raw `grpc.RpcError` into a typed `FinamError`:
222
+
223
+ ```python
224
+ import grpc
225
+ from finam_trade_api import FinamClient, RateLimitError, from_rpc_error
226
+
227
+ with FinamClient(secret="...") as client:
228
+ try:
229
+ client.accounts.GetAccount(GetAccountRequest(account_id="A12345"))
230
+ except grpc.RpcError as raw:
231
+ err = from_rpc_error(raw)
232
+ if isinstance(err, RateLimitError):
233
+ ...
234
+ raise err
235
+ ```
236
+
237
+ Exception classes: `AuthError` (401), `PermissionDeniedError` (403),
238
+ `InvalidArgumentError` (400), `NotFoundError` (404), `RateLimitError` (429),
239
+ `InternalError` (500), `ServiceUnavailableError` (503), `DeadlineExceededError` (504).
240
+ All inherit from `FinamError`.
241
+
242
+ ## Retries
243
+
244
+ Unary RPCs are retried automatically on `UNAVAILABLE` and `RESOURCE_EXHAUSTED`
245
+ with exponential backoff + jitter. Streaming RPCs are *not* retried — the
246
+ caller is expected to handle reconnection at a meaningful boundary
247
+ (e.g. resuming from the last received bar).
248
+
249
+ Override the policy:
250
+
251
+ ```python
252
+ from finam_trade_api import FinamClient, RetryPolicy
253
+
254
+ policy = RetryPolicy(max_attempts=6, initial_backoff=0.5, max_backoff=10.0)
255
+ client = FinamClient(secret="...", retry_policy=policy)
256
+ ```
257
+
258
+ ## Local build
259
+
260
+ From the repository root:
261
+
262
+ ```sh
263
+ cd python
264
+ pip install -e ".[dev]"
265
+ ./scripts/generate_proto.sh
266
+ ```
267
+
268
+ `scripts/generate_proto.sh` compiles the `.proto` files in `../proto/` into
269
+ `finam_trade_api/proto/`. Re-run it whenever the protos change.
270
+
271
+ ## Layout
272
+
273
+ ```
274
+ python/
275
+ ├── pyproject.toml
276
+ ├── README.md
277
+ ├── LICENSE
278
+ ├── scripts/
279
+ │ └── generate_proto.sh # protoc invocation (contributors only)
280
+ ├── examples/ # runnable scripts
281
+ └── finam_trade_api/
282
+ ├── __init__.py
283
+ ├── client.py # FinamClient (sync)
284
+ ├── aio.py # AsyncFinamClient
285
+ ├── auth.py # JWT lifecycle
286
+ ├── retry.py # retry policy + interceptors
287
+ ├── exceptions.py # typed errors
288
+ ├── _metadata.py # Authorization header plumbing
289
+ ├── accounts.py # message re-exports (per-service)
290
+ ├── assets.py
291
+ ├── auth_messages.py
292
+ ├── market_data.py
293
+ ├── orders.py
294
+ ├── reports.py
295
+ ├── metrics.py
296
+ └── proto/ # generated stubs (committed; ships in wheel)
297
+ ```
@@ -0,0 +1,260 @@
1
+ # Finam Trade API — Python SDK
2
+
3
+ Thin Python SDK for the [Finam Trade API](https://tradeapi.finam.ru/). Wraps
4
+ the generated gRPC stubs with:
5
+
6
+ - a single `FinamClient` / `AsyncFinamClient` entry point,
7
+ - automatic JWT issuance and background refresh (via `AuthService.SubscribeJwtRenewal`),
8
+ - typed exceptions mapped from gRPC status codes,
9
+ - exponential-backoff retries on transient failures (`UNAVAILABLE`, `RESOURCE_EXHAUSTED`).
10
+
11
+ Service methods are invoked directly on the generated stubs, so the full proto
12
+ surface is available without an extra translation layer.
13
+
14
+ ## Installation
15
+
16
+ ```sh
17
+ pip install finam-sdk
18
+ ```
19
+
20
+ > The PyPI distribution is `finam-sdk`; the Python import name is
21
+ > `finam_trade_api`. (The `finam-trade-api` name on PyPI is held by an
22
+ > unrelated third-party REST client.)
23
+
24
+ ## Quickstart (sync)
25
+
26
+ ```python
27
+ from finam_trade_api import FinamClient
28
+ from finam_trade_api.accounts import GetAccountRequest
29
+ from finam_trade_api.market_data import SubscribeQuoteRequest
30
+
31
+ with FinamClient(secret="YOUR_API_TOKEN") as client:
32
+ account = client.accounts.GetAccount(GetAccountRequest(account_id="A12345"))
33
+ print(account)
34
+
35
+ # Streaming RPCs return iterators.
36
+ for tick in client.market_data.SubscribeQuote(
37
+ SubscribeQuoteRequest(symbols=["SBER@MISX"])
38
+ ):
39
+ print(tick)
40
+ ```
41
+
42
+ ## Quickstart (asyncio)
43
+
44
+ ```python
45
+ import asyncio
46
+
47
+ from finam_trade_api import AsyncFinamClient
48
+ from finam_trade_api.market_data import SubscribeQuoteRequest
49
+
50
+
51
+ async def main() -> None:
52
+ async with AsyncFinamClient(secret="YOUR_API_TOKEN") as client:
53
+ async for tick in client.market_data.SubscribeQuote(
54
+ SubscribeQuoteRequest(symbols=["SBER@MISX"])
55
+ ):
56
+ print(tick)
57
+
58
+
59
+ asyncio.run(main())
60
+ ```
61
+
62
+ ## Available services
63
+
64
+ The client exposes the full Trade API surface via sub-clients:
65
+
66
+ | Attribute | gRPC service | What it does |
67
+ | -------------------- | ---------------------- | --------------------------------------------- |
68
+ | `client.auth` | `AuthService` | Token issuance + details (usually automatic). |
69
+ | `client.accounts` | `AccountsService` | Accounts, positions, trades, transactions. |
70
+ | `client.assets` | `AssetsService` | Instruments, exchanges, schedules, options. |
71
+ | `client.market_data` | `MarketDataService` | Bars, quotes, order book, trade streams. |
72
+ | `client.orders` | `OrdersService` | Place / cancel orders, order + trade streams. |
73
+ | `client.reports` | `ReportsService` | Account reports. |
74
+ | `client.metrics` | `UsageMetricsService` | API usage / quota metrics. |
75
+
76
+ ## API reference
77
+
78
+ Every RPC defined in the `.proto` files is exposed directly on the sub-client.
79
+ Request and response message types are re-exported from short, per-service
80
+ modules:
81
+
82
+ | Module | Use with |
83
+ | --- | --- |
84
+ | `finam_trade_api.accounts` | `client.accounts.*` |
85
+ | `finam_trade_api.assets` | `client.assets.*` |
86
+ | `finam_trade_api.market_data` | `client.market_data.*` |
87
+ | `finam_trade_api.orders` | `client.orders.*` (includes `Side`) |
88
+ | `finam_trade_api.reports` | `client.reports.*` |
89
+ | `finam_trade_api.metrics` | `client.metrics.*` |
90
+ | `finam_trade_api.auth_messages` | `client.auth.*` (rarely needed — JWT handled automatically) |
91
+
92
+ The original deeply-nested paths
93
+ (`finam_trade_api.proto.grpc.tradeapi.v1.<service>.<service>_service_pb2`)
94
+ still work and remain the source of truth.
95
+
96
+ Legend: ▶ unary · ⇉ server-stream · ⇄ bidi-stream
97
+
98
+ ### `client.auth` — `AuthService`
99
+
100
+ | Method | Kind | Purpose |
101
+ | --- | :---: | --- |
102
+ | `Auth(AuthRequest)` | ▶ | Exchange API secret for a JWT. *Called for you on construction.* |
103
+ | `TokenDetails(TokenDetailsRequest)` | ▶ | Inspect a JWT — expiry, market-data permissions, visible account IDs. |
104
+ | `SubscribeJwtRenewal(SubscribeJwtRenewalRequest)` | ⇉ | Stream of refreshed JWTs. *Consumed for you in the background.* |
105
+
106
+ ### `client.accounts` — `AccountsService`
107
+
108
+ | Method | Kind | Purpose |
109
+ | --- | :---: | --- |
110
+ | `GetAccount(GetAccountRequest)` | ▶ | Account info: equity, cash, positions, margin. |
111
+ | `Trades(TradesRequest)` | ▶ | Historical trades for an account. |
112
+ | `Transactions(TransactionsRequest)` | ▶ | Cash movements and other non-trade transactions. |
113
+ | `SubscribeAccount(GetAccountRequest)` | ⇉ | Streaming account updates. |
114
+
115
+ ### `client.assets` — `AssetsService`
116
+
117
+ | Method | Kind | Purpose |
118
+ | --- | :---: | --- |
119
+ | `Exchanges(ExchangesRequest)` | ▶ | List of supported exchanges. |
120
+ | `Assets(AssetsRequest)` | ▶ | Tradable instruments (filtered). |
121
+ | `AllAssets(AllAssetsRequest)` | ▶ | Full instrument catalog. |
122
+ | `GetAsset(GetAssetRequest)` | ▶ | Single instrument by symbol. |
123
+ | `GetAssetParams(GetAssetParamsRequest)` | ▶ | Trading parameters for an instrument. |
124
+ | `OptionsChain(OptionsChainRequest)` | ▶ | Options chain for an underlying. |
125
+ | `Schedule(ScheduleRequest)` | ▶ | Trading session schedule. |
126
+ | `Clock(ClockRequest)` | ▶ | Server clock (use for time-aligned operations). |
127
+ | `GetConstituents(GetConstituentsRequest)` | ▶ | Index constituents. |
128
+
129
+ ### `client.market_data` — `MarketDataService`
130
+
131
+ | Method | Kind | Purpose |
132
+ | --- | :---: | --- |
133
+ | `Bars(BarsRequest)` | ▶ | OHLC candles (any timeframe via `TimeFrame` enum). |
134
+ | `LastQuote(QuoteRequest)` | ▶ | Most recent quote snapshot. |
135
+ | `OrderBook(OrderBookRequest)` | ▶ | Order book snapshot. |
136
+ | `LatestTrades(LatestTradesRequest)` | ▶ | Most recent trades for a symbol. |
137
+ | `SubscribeQuote(SubscribeQuoteRequest)` | ⇉ | Live quote stream. |
138
+ | `SubscribeOrderBook(SubscribeOrderBookRequest)` | ⇉ | Live order-book updates. |
139
+ | `SubscribeLatestTrades(SubscribeLatestTradesRequest)` | ⇉ | Live trades stream. |
140
+ | `SubscribeBars(SubscribeBarsRequest)` | ⇉ | Live candle stream. |
141
+
142
+ ### `client.orders` — `OrdersService`
143
+
144
+ | Method | Kind | Purpose |
145
+ | --- | :---: | --- |
146
+ | `PlaceOrder(Order)` | ▶ | Place market / limit / stop / stop-limit / multi-leg order. |
147
+ | `PlaceSLTPOrder(SLTPOrder)` | ▶ | Place an SL/TP (stop-loss + take-profit) order. |
148
+ | `CancelOrder(CancelOrderRequest)` | ▶ | Cancel an active order. |
149
+ | `GetOrders(OrdersRequest)` | ▶ | List active orders for an account. |
150
+ | `GetOrder(GetOrderRequest)` | ▶ | Single order by ID. |
151
+ | `SubscribeOrders(SubscribeOrdersRequest)` | ⇉ | Live order-state updates. |
152
+ | `SubscribeTrades(SubscribeTradesRequest)` | ⇉ | Live execution / fill stream. |
153
+ | `SubscribeOrderTrade(stream OrderTradeRequest)` | ⇄ | Bidi stream — order + trade events, request-driven. |
154
+
155
+ ### `client.reports` — `ReportsService`
156
+
157
+ | Method | Kind | Purpose |
158
+ | --- | :---: | --- |
159
+ | `CreateAccountReport(CreateAccountReportRequest)` | ▶ | Generate an account report (async — returns a job handle). |
160
+ | `GetAccountReportInfo(GetAccountReportInfoRequest)` | ▶ | Poll report status. |
161
+ | `SubscribeAccountReportInfo(SubscribeAccountReportInfoRequest)` | ⇉ | Stream report status updates instead of polling. |
162
+
163
+ ### `client.metrics` — `UsageMetricsService`
164
+
165
+ | Method | Kind | Purpose |
166
+ | --- | :---: | --- |
167
+ | `GetUsageMetrics(GetUsageMetricsRequest)` | ▶ | API usage / quota stats for the current token. |
168
+
169
+ ### Client lifecycle
170
+
171
+ | Operation | Sync | Async |
172
+ | --- | --- | --- |
173
+ | Construct | `FinamClient(secret, *, endpoint=DEFAULT_ENDPOINT, retry_policy=DEFAULT_POLICY, channel_options=None)` | `AsyncFinamClient(secret, ...)` — same args |
174
+ | Start | *immediate, blocks for initial JWT* | `await client.start()` — or use `async with` |
175
+ | Current JWT | `client.get_token()` → `str \| None` | `client.get_token()` → `str \| None` (sync read of cached snapshot) |
176
+ | Close | `client.close()` | `await client.close()` |
177
+ | Context manager | `with FinamClient(...) as client:` | `async with AsyncFinamClient(...) as client:` |
178
+ | Testing (no TLS) | `FinamClient.for_testing(secret, endpoint="localhost:50051")` | `AsyncFinamClient.for_testing(secret, endpoint="localhost:50051")` |
179
+
180
+ > `for_testing(...)` opens an insecure (plaintext) channel against an in-process fake server. **Never use against `api.finam.ru`** — it sends your JWT in clear.
181
+
182
+ ## Error handling
183
+
184
+ Wrap raw `grpc.RpcError` into a typed `FinamError`:
185
+
186
+ ```python
187
+ import grpc
188
+ from finam_trade_api import FinamClient, RateLimitError, from_rpc_error
189
+
190
+ with FinamClient(secret="...") as client:
191
+ try:
192
+ client.accounts.GetAccount(GetAccountRequest(account_id="A12345"))
193
+ except grpc.RpcError as raw:
194
+ err = from_rpc_error(raw)
195
+ if isinstance(err, RateLimitError):
196
+ ...
197
+ raise err
198
+ ```
199
+
200
+ Exception classes: `AuthError` (401), `PermissionDeniedError` (403),
201
+ `InvalidArgumentError` (400), `NotFoundError` (404), `RateLimitError` (429),
202
+ `InternalError` (500), `ServiceUnavailableError` (503), `DeadlineExceededError` (504).
203
+ All inherit from `FinamError`.
204
+
205
+ ## Retries
206
+
207
+ Unary RPCs are retried automatically on `UNAVAILABLE` and `RESOURCE_EXHAUSTED`
208
+ with exponential backoff + jitter. Streaming RPCs are *not* retried — the
209
+ caller is expected to handle reconnection at a meaningful boundary
210
+ (e.g. resuming from the last received bar).
211
+
212
+ Override the policy:
213
+
214
+ ```python
215
+ from finam_trade_api import FinamClient, RetryPolicy
216
+
217
+ policy = RetryPolicy(max_attempts=6, initial_backoff=0.5, max_backoff=10.0)
218
+ client = FinamClient(secret="...", retry_policy=policy)
219
+ ```
220
+
221
+ ## Local build
222
+
223
+ From the repository root:
224
+
225
+ ```sh
226
+ cd python
227
+ pip install -e ".[dev]"
228
+ ./scripts/generate_proto.sh
229
+ ```
230
+
231
+ `scripts/generate_proto.sh` compiles the `.proto` files in `../proto/` into
232
+ `finam_trade_api/proto/`. Re-run it whenever the protos change.
233
+
234
+ ## Layout
235
+
236
+ ```
237
+ python/
238
+ ├── pyproject.toml
239
+ ├── README.md
240
+ ├── LICENSE
241
+ ├── scripts/
242
+ │ └── generate_proto.sh # protoc invocation (contributors only)
243
+ ├── examples/ # runnable scripts
244
+ └── finam_trade_api/
245
+ ├── __init__.py
246
+ ├── client.py # FinamClient (sync)
247
+ ├── aio.py # AsyncFinamClient
248
+ ├── auth.py # JWT lifecycle
249
+ ├── retry.py # retry policy + interceptors
250
+ ├── exceptions.py # typed errors
251
+ ├── _metadata.py # Authorization header plumbing
252
+ ├── accounts.py # message re-exports (per-service)
253
+ ├── assets.py
254
+ ├── auth_messages.py
255
+ ├── market_data.py
256
+ ├── orders.py
257
+ ├── reports.py
258
+ ├── metrics.py
259
+ └── proto/ # generated stubs (committed; ships in wheel)
260
+ ```