3.4 KiB
3.4 KiB
Portfolio Enricher Optimization
Date: 2026-06-14 Status: Approved Author: AI Agent
Problem
GET /api/v1/portfolios/1 с 104 позициями (90 облигаций + 14 акций) выполняется ~29 секунд из-за 298 последовательных HTTP-запросов к MOEX ISS через rate limiter (10 req/s).
Root Cause
Per-position enrichment в PortfolioService.enrichPositions() генерирует:
| Шаг | Вызовов | Метод |
|---|---|---|
| shortName | 104 | getSecurityDescription — избыточно |
| Акции (14) | 14 | getShareMarketData |
| Облигации (90) | 90 | getBondData |
| Облигации (90) | 90 | getBondMarketData — дублирует endpoint |
| Total | 298 |
Две ключевые проблемы:
getBondDataиgetBondMarketDataвызывают один и тот же MOEX endpoint, но парсят разные таблицы ответаgetSecurityDescriptionдля shortName — избыточен: shortName уже доступен в market data ответах- Каждый secid запрашивается отдельно, хотя MOEX ISS поддерживает batch через
?securities=параметр
Solution
1. Merge bond data calls
Новый метод getBondDataCombined(secid) делает один запрос к MOEX и парсит обе таблицы (securities + marketdata), возвращая объединённый результат.
Profit: 180 → 90 запросов для bonds
2. Remove redundant getSecurityDescription
getShareMarketDataresponse уже содержитSHORTNAMEвsecuritiesтаблице — добавим полеshortNameв типMoexShareMarketDatagetBondDataCombinedуже возвращает shortName изsecuritiesтаблицы
Profit: 104 → 0 запросов
3. Batch requests by market
Группируем secid по типу (share/bond) и делаем 2 batch-запроса вместо индивидуальных:
GET /engines/stock/markets/shares/securities.json?securities=SBER,VTBR,...&boards=TQBRGET /engines/stock/markets/bonds/securities.json?securities=RU000A...,SU26240...&boards=TQCB
Новые методы: getShareMarketDataBatch(secids), getBondMarketDataBatch(secids).
Profit: 104 → 2 запроса
Metrics
| Scenario | API calls | Est. time (10 req/s) |
|---|---|---|
| Before | 298 | ~29.8s |
| After | 2 | ~0.3s |
Files Changed
| File | Change |
|---|---|
apps/backend/src/modules/moex-client/moex-client.types.ts |
Add shortName to MoexShareMarketData |
apps/backend/src/modules/moex-client/moex-client.service.ts |
+getShareMarketDataBatch, +getBondMarketDataBatch, merge bond methods, add shortName to share response |
apps/backend/src/modules/portfolio/portfolio.service.ts |
Rewrite enrichPositions — batch, no redundant calls |
Risks and Mitigations
- MOEX ISS rate limiting: Batch reduces requests, lowering risk. Circuit breaker stays intact.
- Cache invalidation: Batch results cached per market, not per secid. TTL unchanged (900s market data).
- Empty batches: If portfolio has no shares or no bonds, skip market entirely. No unnecessary calls.
- Long secid lists: URL length may exceed limits. Mitigation: split batches if secids > 50 per call (monitor and split if needed).