spec: plan investment performance vs Moscow Exchange index (WealthLedger/main#54)
Conventional commits / commits (pull_request) Successful in 15s
Specs security / security (pull_request) Successful in 8s
Specs verify / verify (pull_request) Successful in 12s

This commit is contained in:
2026-11-07 20:09:57 +03:00
parent 1b20067ca7
commit 5625c52b29
13 changed files with 1598 additions and 0 deletions
@@ -0,0 +1,25 @@
sequenceDiagram
participant API as WealthLedger backend
participant Idx as Saved index history
participant MOEX as MOEX ISS
API->>Idx: Последняя сохранённая дата, время последней попытки (по индексу)
alt Покрыто до дня `to` или попытка была < 1 ч назад
Idx-->>API: Сохранённые закрытия
else Нужна догрузка (одна одновременная попытка на индекс)
loop Страницы по 100 строк (start = 0, 100, …) до TOTAL
API->>MOEX: GET /iss/history/engines/stock/markets/index/securities/{SECID}.json<br/>?from&till&start&iss.meta=off&history.columns=TRADEDATE,CLOSE
alt 200 с валидными строками
MOEX-->>API: TRADEDATE, CLOSE + history.cursor(INDEX,TOTAL,PAGESIZE)
API->>Idx: Upsert (индекс, торговый день) → точное закрытие
else Таймаут 10 с / не-2xx / невалидный ответ
MOEX-->>API: сбой
Note over API: Прервать догрузку; сохранённое не удалять;<br/>лог integration.moex.index_history.failed
end
end
Idx-->>API: Сохранённые закрытия
end
alt Последнее закрытие ≥ to − 10 календарных дней
Note over API: Покрытие достаточно; asOf = последняя дата закрытия
else Иначе
Note over API: INDEX_HISTORY_UNAVAILABLE для этого индекса
end
@@ -0,0 +1,38 @@
sequenceDiagram
actor User
participant UI as WealthLedger frontend
participant API as WealthLedger backend
participant Store as Saved investment data
participant Idx as Saved index history
participant MOEX as MOEX ISS
User->>UI: Открывает вкладку «Результат» (accountId | all)
UI->>API: GET /brokerage-accounts/{accountId|all}/performance
API->>Store: Сессия, connection, доступ к счёту(ам)
alt Нет сессии / нет подключения / счёт недоступен
API-->>UI: Problem Details 401 / 503 TBANK_NOT_CONNECTED / 404
UI-->>User: Существующие состояния ошибки счёта
else Доступ подтверждён
API->>Store: Граница истории, покрытие операций, последняя полная оценка Portfolio
Note over API: По каждому счёту: причины недоступности<br/>(HISTORY_START_UNKNOWN, OPERATIONS_HISTORY_INCOMPLETE,<br/>NON_RUB_ACTIVITY, UNVALUED_SECURITIES_TRANSFER,<br/>PORTFOLIO_VALUATION_INCOMPLETE)
alt Не осталось счетов для расчёта
API-->>UI: 200 {data: null, meta.unavailable: [...]}
UI-->>User: «Доходность недоступна» + причина
else Есть счета для расчёта
API->>API: Внешние потоки по дате, чистые вложения, прибыль, XIRR
API->>Idx: Закрытия MCFTRR, IMOEX за [from, to]
opt История не покрывает период (см. index-refresh.mmd)
Idx->>MOEX: Догрузка недостающих торговых дней
end
alt MCFTRR покрывает период
API->>API: Теневой портфель, XIRR индекса, опережение, series
else MCFTRR недоступен
API->>API: benchmark/outperformance недоступны (INDEX_HISTORY_UNAVAILABLE), series = []
end
API-->>UI: 200 {data: Performance, meta.dependencies}
UI-->>User: Показатели, график, «Как считали», предупреждение о неполноте
end
end
alt Технический сбой backend
API-->>UI: Problem Details 5xx
UI-->>User: Ошибка только во вкладке «Результат», с повтором
end