docs: document tbank invest integration
This commit is contained in:
parent
3fe4e7a4ec
commit
b10a2cfb0d
30
apps/docs/docs/adr/ADR-011-tbank-invest-grpc.md
Normal file
30
apps/docs/docs/adr/ADR-011-tbank-invest-grpc.md
Normal file
@ -0,0 +1,30 @@
|
||||
# ADR-011: Интеграция с T-Bank Invest использует gRPC
|
||||
|
||||
**Статус:** Accepted
|
||||
|
||||
**Дата:** 2026-06-16
|
||||
|
||||
## Контекст
|
||||
|
||||
MoexVibe нужна read-only интеграция с T-Bank Invest для брокерских счетов и ИИС: текущие позиции,
|
||||
деньги на счёте и история операций. T-Bank предоставляет gRPC, REST-прокси, WebSocket и официальный
|
||||
JS SDK.
|
||||
|
||||
## Решение
|
||||
|
||||
Использовать тонкую backend gRPC-интеграцию на основе официальных proto-контрактов. REST оставить
|
||||
для ручной диагностики, а официальный JS SDK не делать прямой зависимостью первого варианта.
|
||||
|
||||
## Обоснование
|
||||
|
||||
- gRPC — основной протокол T-Bank Invest API.
|
||||
- Unary methods покрывают счета, портфель, позиции, операции и инструменты.
|
||||
- Stream methods можно добавить позже без изменения публичного MoexVibe API.
|
||||
- Собственный транспортный слой позволяет контролировать rate limiting, cache TTL, redaction
|
||||
metadata, test doubles и будущий переход от одного server token к per-user token storage.
|
||||
|
||||
## Последствия
|
||||
|
||||
- Backend хранит vendored proto-контракты T-Bank Invest.
|
||||
- Backend владеет T-Bank-specific rate limits и cache TTL.
|
||||
- Интеграция остаётся read-only, пока отдельный ADR не разрешит торговые операции и заявки.
|
||||
@ -12,5 +12,6 @@
|
||||
| [ADR-008](ADR-008-auth-system) | Accepted | Authentication и Authorization |
|
||||
| [ADR-009](ADR-009-portfolio-domain) | Accepted | Доменная модель портфеля |
|
||||
| [ADR-010](ADR-010-backend-price-computation) | Accepted | Расчёт цен на backend |
|
||||
| [ADR-011](ADR-011-tbank-invest-grpc) | Accepted | Интеграция с T-Bank Invest через gRPC |
|
||||
|
||||
Все опубликованные ADR находятся в `apps/docs/docs/adr/` и отображаются в этом Docusaurus-разделе.
|
||||
|
||||
@ -37,7 +37,7 @@ flowchart LR
|
||||
|
||||
```typescript
|
||||
getOrFetch<T>(
|
||||
keyPrefix: string, // 'marketdata' | 'history' | 'candles' | 'search' | 'bond' | 'dividends'
|
||||
keyPrefix: string, // 'marketdata' | 'history' | 'candles' | 'search' | 'bond' | 'dividends' | 'tbank:*'
|
||||
keyParts: string[], // ['shares', 'SBER'] | ['SBER', '2026-06-13', '2026-06-14']
|
||||
fetchFn: () => Promise<T>,
|
||||
ttlConfigKey: string, // 'marketDataTtl' | 'historyTtl' | etc.
|
||||
@ -78,3 +78,14 @@ export class CacheModule {}
|
||||
| Спецификация инструмента | `securityTtl` | 86400s (24 ч) | `CACHE_SECURITY_TTL` |
|
||||
| Поиск | `searchTtl` | 3600s (1 ч) | `CACHE_SEARCH_TTL` |
|
||||
| Дивиденды | `dividendsTtl` | 86400s (24 ч) | `CACHE_DIVIDENDS_TTL` |
|
||||
| Счета T-Bank | `tbankAccountsTtl` | 3600s (1 ч) | `CACHE_TBANK_ACCOUNTS_TTL` |
|
||||
| Портфель T-Bank | `tbankPortfolioTtl` | 60s (1 мин) | `CACHE_TBANK_PORTFOLIO_TTL` |
|
||||
| Операции T-Bank | `tbankOperationsTtl` | 300s (5 мин) | `CACHE_TBANK_OPERATIONS_TTL` |
|
||||
| Инструменты T-Bank | `tbankInstrumentTtl` | 86400s (24 ч) | `CACHE_TBANK_INSTRUMENT_TTL` |
|
||||
|
||||
## T-Bank cache
|
||||
|
||||
`TBankModule` использует те же механики `CacheService`, но с отдельными key prefixes
|
||||
`tbank:accounts`, `tbank:portfolio`, `tbank:positions`, `tbank:operations` и `tbank:instrument`.
|
||||
Это позволяет держать агрессивно короткий TTL для текущего портфеля и более длинный TTL для
|
||||
справочных данных инструментов.
|
||||
|
||||
@ -11,12 +11,21 @@
|
||||
| `MOEX_RATE_LIMIT` | `10` | Максимум запросов в секунду к MOEX |
|
||||
| `MOEX_CIRCUIT_BREAKER_THRESHOLD` | `5` | Количество ошибок до открытия circuit breaker |
|
||||
| `MOEX_CIRCUIT_BREAKER_RESET_SECONDS` | `30` | Время в секундах до сброса circuit breaker |
|
||||
| `T_BANK_TOKEN` | `''` | Server-side токен T-Bank Invest |
|
||||
| `T_BANK_BASE_URL` | `invest-public-api.tbank.ru:443` | gRPC endpoint T-Bank Invest |
|
||||
| `T_BANK_APP_NAME` | `ksv741.moex-vibe` | Metadata приложения для T-Bank |
|
||||
| `T_BANK_RATE_LIMIT_PER_SECOND` | `5` | Локальный rate limiter для T-Bank |
|
||||
| `T_BANK_REQUEST_TIMEOUT_MS` | `10000` | Deadline gRPC-запроса (мс) |
|
||||
| `CACHE_MARKET_DATA_TTL` | `900` | TTL рыночных данных (секунды) |
|
||||
| `CACHE_HISTORY_TTL` | `3600` | TTL истории торгов (секунды) |
|
||||
| `CACHE_CANDLES_TTL` | `3600` | TTL свечей (секунды) |
|
||||
| `CACHE_SECURITY_TTL` | `86400` | TTL спецификации инструмента (секунды) |
|
||||
| `CACHE_SEARCH_TTL` | `3600` | TTL результатов поиска (секунды) |
|
||||
| `CACHE_DIVIDENDS_TTL` | `86400` | TTL дивидендов (секунды) |
|
||||
| `CACHE_TBANK_ACCOUNTS_TTL` | `3600` | TTL списка брокерских счетов T-Bank (секунды) |
|
||||
| `CACHE_TBANK_PORTFOLIO_TTL` | `60` | TTL брокерского портфеля T-Bank (секунды) |
|
||||
| `CACHE_TBANK_OPERATIONS_TTL` | `300` | TTL страницы операций T-Bank (секунды) |
|
||||
| `CACHE_TBANK_INSTRUMENT_TTL` | `86400` | TTL метаданных инструментов T-Bank (секунды) |
|
||||
|
||||
## Файл конфигурации
|
||||
|
||||
@ -33,6 +42,13 @@ registerAs('app', () => ({
|
||||
process.env.MOEX_CIRCUIT_BREAKER_RESET_SECONDS || '30', 10,
|
||||
),
|
||||
},
|
||||
tbank: {
|
||||
token: process.env.T_BANK_TOKEN || '',
|
||||
baseUrl: process.env.T_BANK_BASE_URL || 'invest-public-api.tbank.ru:443',
|
||||
appName: process.env.T_BANK_APP_NAME || 'ksv741.moex-vibe',
|
||||
rateLimitPerSecond: parseInt(process.env.T_BANK_RATE_LIMIT_PER_SECOND || '5', 10),
|
||||
requestTimeoutMs: parseInt(process.env.T_BANK_REQUEST_TIMEOUT_MS || '10000', 10),
|
||||
},
|
||||
cache: {
|
||||
marketDataTtl: parseInt(process.env.CACHE_MARKET_DATA_TTL || '900', 10),
|
||||
historyTtl: parseInt(process.env.CACHE_HISTORY_TTL || '3600', 10),
|
||||
@ -40,6 +56,10 @@ registerAs('app', () => ({
|
||||
securityTtl: parseInt(process.env.CACHE_SECURITY_TTL || '86400', 10),
|
||||
searchTtl: parseInt(process.env.CACHE_SEARCH_TTL || '3600', 10),
|
||||
dividendsTtl: parseInt(process.env.CACHE_DIVIDENDS_TTL || '86400', 10),
|
||||
tbankAccountsTtl: parseInt(process.env.CACHE_TBANK_ACCOUNTS_TTL || '3600', 10),
|
||||
tbankPortfolioTtl: parseInt(process.env.CACHE_TBANK_PORTFOLIO_TTL || '60', 10),
|
||||
tbankOperationsTtl: parseInt(process.env.CACHE_TBANK_OPERATIONS_TTL || '300', 10),
|
||||
tbankInstrumentTtl: parseInt(process.env.CACHE_TBANK_INSTRUMENT_TTL || '86400', 10),
|
||||
},
|
||||
}));
|
||||
```
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
flowchart TB
|
||||
AppModule["AppModule"]
|
||||
GlobalModules["Глобальные модули<br/>ConfigModule<br/>PrismaModule<br/>CacheModule<br/>MoexClientModule"]
|
||||
FeatureModules["Feature-модули<br/>HealthModule<br/>AuthModule<br/>PortfolioModule<br/>SecuritiesModule<br/>SharesModule<br/>BondsModule<br/>CandlesModule"]
|
||||
FeatureModules["Feature-модули<br/>HealthModule<br/>AuthModule<br/>PortfolioModule<br/>SecuritiesModule<br/>SharesModule<br/>BondsModule<br/>CandlesModule<br/>TBankModule"]
|
||||
|
||||
AppModule --> GlobalModules
|
||||
AppModule --> FeatureModules
|
||||
@ -21,10 +21,12 @@ flowchart TB
|
||||
AuthModule["AuthModule"]
|
||||
PortfolioModule["PortfolioModule"]
|
||||
MarketModules["SecuritiesModule<br/>SharesModule<br/>BondsModule<br/>CandlesModule"]
|
||||
TBankModule["TBankModule"]
|
||||
|
||||
PrismaService["PrismaService"]
|
||||
CacheService["CacheService"]
|
||||
MoexClientService["MoexClientService"]
|
||||
TBankClientService["TBankClientService"]
|
||||
|
||||
PrismaModule --> PrismaService
|
||||
CacheModule --> CacheService
|
||||
@ -37,6 +39,10 @@ flowchart TB
|
||||
|
||||
MarketModules --> CacheService
|
||||
MarketModules --> MoexClientService
|
||||
|
||||
TBankModule --> CacheService
|
||||
TBankModule --> PrismaService
|
||||
TBankModule --> TBankClientService
|
||||
```
|
||||
|
||||
## Список модулей
|
||||
@ -53,6 +59,7 @@ flowchart TB
|
||||
| `BondsModule` | Нет | `modules/bonds/` | Облигации |
|
||||
| `CandlesModule` | Нет | `modules/candles/` | Свечи OHLCV |
|
||||
| `PortfolioModule` | Нет | `modules/portfolio/` | Пользовательские портфели и аналитика |
|
||||
| `TBankModule` | Нет | `modules/tbank/` | Read-only брокерские портфели T-Bank Invest |
|
||||
|
||||
### PrismaModule
|
||||
|
||||
@ -131,3 +138,16 @@ flowchart TB
|
||||
- Обогащение позиций текущими ценами из MOEX
|
||||
- Расчёт summary, PnL и долей портфеля
|
||||
- Все endpoints защищены JWT
|
||||
|
||||
### TBankModule
|
||||
|
||||
Read-only интеграция с T-Bank Invest для брокерских счетов и ИИС.
|
||||
|
||||
- `TBankClientService` создаёт gRPC clients по vendored proto-контрактам и добавляет metadata
|
||||
`Authorization` + `x-app-name`
|
||||
- `BrokerAccountsService` фильтрует только открытые брокерские счета и ИИС
|
||||
- `BrokerPortfolioService` объединяет портфель, позиции, cash и метаданные инструментов
|
||||
- `BrokerOperationsService` отдаёт cursor-paginated историю операций
|
||||
- `BrokerOperationSyncService` сохраняет историю операций в отдельные Prisma-таблицы
|
||||
- Direct-read endpoints используют `CacheService` с T-Bank TTL и не записывают данные в ручной
|
||||
`PortfolioModule`
|
||||
|
||||
@ -3,6 +3,12 @@
|
||||
`PortfolioModule` позволяет пользователям создавать и вести виртуальные инвестиционные портфели для
|
||||
аналитики и отслеживания позиций.
|
||||
|
||||
## Ручные портфели и брокерские портфели
|
||||
|
||||
`PortfolioModule` остаётся доменом ручных виртуальных портфелей. Брокерские счета T-Bank Invest
|
||||
экспортируются отдельным `TBankModule` под `/api/v1/broker/*` и не сохраняются как записи
|
||||
`Portfolio`.
|
||||
|
||||
## Обзор
|
||||
|
||||
- **Backend:** `PortfolioModule` (`apps/backend/src/modules/portfolio/`)
|
||||
|
||||
71
apps/docs/docs/backend/tbank-invest.md
Normal file
71
apps/docs/docs/backend/tbank-invest.md
Normal file
@ -0,0 +1,71 @@
|
||||
# T-Bank Invest
|
||||
|
||||
`TBankModule` — read-only интеграция backend с T-Bank Invest API. Frontend не обращается к
|
||||
T-Bank напрямую: он использует endpoints MoexVibe под `/api/v1/broker`.
|
||||
|
||||
## Область поддержки
|
||||
|
||||
Первая версия показывает только открытые брокерские счета и ИИС:
|
||||
|
||||
- `ACCOUNT_TYPE_TINKOFF`
|
||||
- `ACCOUNT_TYPE_TINKOFF_IIS`
|
||||
|
||||
Инвесткопилка, счета ЦФА, дебетовые счета, накопительные счета и счета фондов денежного рынка
|
||||
игнорируются.
|
||||
|
||||
## Протокол
|
||||
|
||||
MoexVibe использует gRPC endpoint `invest-public-api.tbank.ru:443`. REST-прокси T-Bank считается
|
||||
инструментом для ручной диагностики, а не основным протоколом интеграции.
|
||||
|
||||
Backend отправляет metadata:
|
||||
|
||||
```text
|
||||
Authorization: Bearer <T_BANK_TOKEN>
|
||||
x-app-name: ksv741.moex-vibe
|
||||
```
|
||||
|
||||
Токен читается из env-переменных backend и не возвращается во frontend, Swagger responses или логи.
|
||||
|
||||
## Backend endpoints
|
||||
|
||||
Все endpoints защищены JWT и возвращают стандартную оболочку `{ data, meta }`.
|
||||
|
||||
| Endpoint | Описание |
|
||||
|---|---|
|
||||
| `GET /api/v1/broker/accounts` | Открытые брокерские счета и ИИС |
|
||||
| `GET /api/v1/broker/accounts/:accountId/portfolio` | Итоги портфеля, позиции, деньги и заблокированные деньги |
|
||||
| `GET /api/v1/broker/accounts/:accountId/operations` | История операций с cursor pagination |
|
||||
|
||||
## Методы T-Bank
|
||||
|
||||
| Задача | Метод T-Bank |
|
||||
|---|---|
|
||||
| Счета | `UsersService/GetAccounts` |
|
||||
| Итоги портфеля | `OperationsService/GetPortfolio` |
|
||||
| Деньги и settled-позиции | `OperationsService/GetPositions` |
|
||||
| История операций | `OperationsService/GetOperationsByCursor` |
|
||||
| Метаданные инструментов | `InstrumentsService/GetInstrumentBy` |
|
||||
|
||||
## Кеширование и синхронизация
|
||||
|
||||
Direct-read endpoints используют короткий in-memory cache, чтобы не спамить T-Bank API при
|
||||
переключении страниц и повторных запросах:
|
||||
|
||||
- счета: `CACHE_TBANK_ACCOUNTS_TTL`
|
||||
- портфель: `CACHE_TBANK_PORTFOLIO_TTL`
|
||||
- страницы операций: `CACHE_TBANK_OPERATIONS_TTL`
|
||||
- метаданные инструментов: `CACHE_TBANK_INSTRUMENT_TTL`
|
||||
|
||||
Для долговременной истории операций есть отдельные таблицы Prisma:
|
||||
|
||||
- `BrokerOperation` — нормализованная операция и сырой JSON payload;
|
||||
- `BrokerOperationSyncState` — состояние последней синхронизации по брокерскому счёту.
|
||||
|
||||
Эти таблицы не связаны с ручными портфелями `Portfolio` и `Position`.
|
||||
|
||||
## Безопасность
|
||||
|
||||
Текущая версия рассчитана на single-user/admin сценарий: используется один server-side
|
||||
`T_BANK_TOKEN`. Перед multi-user режимом нужно добавить зашифрованное хранение пользовательских
|
||||
T-Bank токенов и привязку каждого брокерского счёта к владельцу.
|
||||
@ -17,6 +17,7 @@ const sidebars: SidebarsConfig = {
|
||||
'backend/configuration',
|
||||
'backend/caching',
|
||||
'backend/moex-client',
|
||||
'backend/tbank-invest',
|
||||
'backend/securities',
|
||||
'backend/portfolio',
|
||||
],
|
||||
@ -63,6 +64,7 @@ const sidebars: SidebarsConfig = {
|
||||
'adr/ADR-008-auth-system',
|
||||
'adr/ADR-009-portfolio-domain',
|
||||
'adr/ADR-010-backend-price-computation',
|
||||
'adr/ADR-011-tbank-invest-grpc',
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user