Files
docs/domains/portfolio/data-reference.md
codex-bot 7fbd4273ba
Docs security / security (push) Successful in 7s
Docs verify / verify (push) Successful in 13s
docs: describe RUB-only behavior (WealthLedger/main#55) (#68)
2026-11-11 09:19:49 +03:00

115 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Данные и показатели портфеля
Этот справочник объясняет значения снимка одного счёта. Он нужен при чтении
экрана, API-ответа или разборе расхождения сумм. Для
[общего портфеля](all-accounts.md) действуют те же денежные правила,
но данные счетов получаются не одновременно.
## Точные значения и неизвестность
Деньги представлены значением Money: ISO-код валюты и десятичная строка,
например `{ "currency": "RUB", "value": "12500.5" }` — условный пример.
Валюта всегда `RUB`: система работает только с рублями.
Количества также передаются десятичными строками. Backend выполняет
десятичную арифметику без промежуточного `Number`, нормализует отрицательные
целую и дробную части и убирает незначащие конечные нули. Экспоненциальной
записи нет. Frontend форматирует полученные строки в русской локали без
сокращения, округления сумм и потери присланных дробных цифр.
`null` означает, что показатель нельзя определить из доступных данных.
Это не ноль. Известная нулевая цена отличается от отсутствующей;
позиция с ненулевым количеством и неизвестной стоимостью остаётся в составе.
Позиции и деньги в валютах, отличных от RUB, отфильтровываются при получении из T-Bank и не участвуют ни в одном итоге.
## Состав и денежные показатели
| Понятие или показатель | Смысл и источник | Ограничение |
| --- | --- | --- |
| Позиция | Ненулевое количество обычного инструмента из `GetPortfolio.positions` | Виртуальные позиции не включаются; порядок источника сохраняется |
| `quantity` | Количество из текущей позиции брокера | Допустимы дробные и отрицательные количества; это не число лотов |
| `currentValue` | Количество × текущая цена из `GetPortfolio` | `null`, если цена недоступна |
| `averagePurchasePrice` | Средняя цена позиции, переданная брокером | Это цена единицы, а не сумма затрат или рассчитанная приложением история покупок |
| `absoluteReturn` | Количество × (текущая цена − средняя цена) | Требует обеих цен; не включает продажи, купоны и дивиденды |
| Cash Balance | Суммы RUB из `GetPositions.money`, объединённые в один остаток | Заблокированные деньги не прибавляются; торгуемый инструмент `CURRENCY` остаётся позицией |
| Итог Portfolio | Стоимости позиций + Cash Balance в RUB | Не включает невычислимую стоимость; не обещает полную оценку портфеля |
| `lastSuccessfulAt` | Время формирования успешного снимка, UTC | Не является временем каждой котировки; запасной снимок сохраняет исходное время |
| `isStale` | Истёк часовой срок свежести сохранённого portfolio source | Не описывает состояние клиентского кэша или ошибку фонового запроса |
| `sector` | Сектор инструмента в том виде, как его определяет T-Bank, с обрезанными пробелами | Только для позиций `STOCK`, `BOND` и `FUND`; значение из одних пробел считается отсутствующим. Во всех остальных случаях — `null` |
| `issuer` | Бренд актива инструмента по данным T-Bank: `{ id, name }` | Только для позиций `STOCK`, `BOND` и `FUND`, когда у актива известны uid и название бренда. Во всех остальных случаях — `null`. Не влияет на количество, стоимость и свежесть снимка; используется вкладкой [«Концентрация»](concentration.md) |
Ненулевые денежные остатки суммируются в один Cash Balance. Позиции одинаковых
инструментов в ответе отдельного счёта не объединяются; визуальная группировка
между счетами описана [отдельно](all-accounts.md#данные-и-вычисления).
Сводка уже включает Cash Balance: прибавление денег к ней второй раз неверно.
При отсутствии вычислимой стоимости у части позиций известный итог остаётся
полезен, но представляет только оценённую часть. Известные нулевые итоги
отдельного счёта не создают отдельную итоговую карточку. Если итог Portfolio
отсутствует, но позиции или деньги присутствуют, это не пустой портфель.
## Результат инвестирования
| Поле | Смысл | Ограничение |
| --- | --- | --- |
| `netInvested`, `currentValue`, `profit` | Чистые внешние потоки, сумма RUB-оценок, их разность | Только RUB, копейки |
| `return.value` | Доля XIRR (`0.151` = 15,1 %) | `null` с `unavailableReason`; при `basis = period` — за весь период |
| `benchmark`, `reference` | Те же потоки в MCFTRR и IMOEX | IMOEX только справка |
| `outperformance` | Разница долей и стоимостей с MCFTRR | `null`, если любая сторона недоступна |
| `series` | Точки торговых дней MCFTRR | Пусто без истории индекса |
Подробнее — [результат инвестирования](investment-performance.md).
## Идентификация и оформление инструмента
UID определяет конкретный инструмент брокера и используется для перехода
на его страницу. FIGI, ISIN и тикер сохраняются как доступные идентификаторы;
одно название или совпадение тикера не доказывает тождество инструментов.
Для получения метаданных backend сначала использует UID, затем FIGI.
Отображаемое имя выбирается в порядке: полное имя, тикер, FIGI.
Если нет и FIGI, текущая реализация использует `Unknown instrument`.
ISIN, тикер и `logoName` могут быть `null`. `logoName` — имя файла бренда,
а не URL: frontend строит ссылку на публичный CDN. Ошибка изображения
или метаданных не меняет количество, суммы и свежесть снимка и не скрывает
финансовые данные. Metadata обновляется независимо; отсутствие имени не задерживает выдачу
финансового снимка и оставляет доступный идентификатор.
`logoName` не равен эмитенту из вкладки «Концентрация»: он берётся из metadata
инструмента, а эмитент — из [классификации инструмента](flows/portfolio-loading.md#обновление-сектора-и-эмитента).
## Структура и доли
`structure` распределяет стоимость по четырём категориям: акции (`STOCK`),
облигации (`BOND`), прочие инструменты (`OTHER`) и деньги (`CASH`).
Торгуемые валютные инструменты входят в `OTHER`; денежные остатки — в `CASH`.
Сервер строит структуру из позиций и денег, без повторного добавления
итога Portfolio.
Доля категории — её стоимость / известная стоимость позиций и денег
× 100. Backend округляет процент до шести знаков;
frontend показывает до сотых. Положительное значение меньше 0,01%
отображается как «< 0,01 %», если серверное округление не превратило его в ноль.
В геометрию диаграммы передаются только числовые проценты; суммы в списке
и подсказке форматируются из исходных точных строк.
Доля на карточке отдельной позиции использует другой знаменатель:
сумму стоимостей всех отображаемых позиций **без денег**. Это приблизительный
показатель для отображения, рассчитанный frontend. Он не изменяет Money.
В режиме всех счетов знаменатель охватывает все показанные счета.
| Состояние | Доступное представление |
| --- | --- |
| Все составляющие оценены, неотрицательны, итог положителен | Суммы, доли и кольцевая диаграмма |
| Есть позиция без оценки | `unvaluedCategories` содержит её категорию и количество; суммы известной части остаются, доли и кольцо недоступны |
| Есть отрицательная составляющая | Суммы со знаком остаются; доли и кольцо отключены, даже если итог категории положителен |
| Состав пуст или имеет нулевую стоимость | Текстовое состояние вместо кольца |
В общем портфеле проверка
отрицательных денег выполняется по остаткам счетов до взаимозачёта.
Нормативные основы: [нормализованный состав](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/portfolio-view/spec.md#requirement-нормализованный-состав-portfolio)
и [точные значения и итоговая сумма в RUB](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/portfolio-view/spec.md#requirement-точные-значения-и-итоговая-сумма-в-rub).
Структура и общий режим подтверждены реализацией и её проверками;
отдельных требований к ним в основной спецификации портфеля пока нет.
Поля транспорта следует сверять с [HTTP API](../../architecture/http-api.md),
а свежесть — с [потоком загрузки](flows/portfolio-loading.md).