# Данные и показатели портфеля Этот справочник объясняет значения снимка одного счёта. Он нужен при чтении экрана, API-ответа или разборе расхождения сумм. Для [общего портфеля](all-accounts.md) действуют те же денежные правила, но данные счетов получаются не одновременно. ## Точные значения и неизвестность Деньги представлены значением Money: ISO-код валюты и десятичная строка, например `{ "currency": "RUB", "value": "12500.5" }` — условный пример. Количества также передаются десятичными строками. Backend выполняет десятичную арифметику без промежуточного `Number`, нормализует отрицательные целую и дробную части и убирает незначащие конечные нули. Экспоненциальной записи нет. Frontend форматирует полученные строки в русской локали без сокращения, округления сумм и потери присланных дробных цифр. `null` означает, что показатель нельзя определить из доступных данных. Это не ноль. Известная нулевая цена отличается от отсутствующей; позиция с ненулевым количеством и неизвестной стоимостью остаётся в составе. Несколько валют никогда не складываются в одну общую стоимость. ## Состав и денежные показатели | Понятие или показатель | Смысл и источник | Ограничение | | --- | --- | --- | | Позиция | Ненулевое количество обычного инструмента из `GetPortfolio.positions` | Виртуальные позиции не включаются; порядок источника сохраняется | | `quantity` | Количество из текущей позиции брокера | Допустимы дробные и отрицательные количества; это не число лотов | | `currentValue` | Количество × текущая цена из `GetPortfolio` | `null`, если цена или её валюта недоступны | | `averagePurchasePrice` | Средняя цена позиции, переданная брокером | Это цена единицы, а не сумма затрат или рассчитанная приложением история покупок | | `absoluteReturn` | Количество × (текущая цена − средняя цена) | Требует обеих цен в одной известной валюте; не включает продажи, купоны и дивиденды | | Cash Balance | Суммы из `GetPositions.money`, объединённые по валюте | Заблокированные деньги не прибавляются; торгуемый инструмент `CURRENCY` остаётся позицией | | `totalsByCurrency` | Стоимости позиций + доступные деньги той же валюты | Не включает невычислимую стоимость; не обещает полную оценку портфеля | | `lastSuccessfulAt` | Время формирования успешного снимка, UTC | Не является временем каждой котировки; запасной снимок сохраняет исходное время | | `isStale` | Истёк часовой срок свежести сохранённого portfolio source | Не описывает состояние клиентского кэша или ошибку фонового запроса | Ненулевые денежные остатки одной валюты суммируются. Позиции одинаковых инструментов в ответе отдельного счёта не объединяются; визуальная группировка между счетами описана [отдельно](all-accounts.md#данные-и-вычисления). Сводка уже включает Cash Balance: прибавление денег к ней второй раз неверно. При отсутствии вычислимой стоимости у части позиций известный итог остаётся полезен, но представляет только оценённую часть. Известные нулевые итоги отдельного счёта не создают валютные карточки. Если `totalsByCurrency` пуст, но позиции или деньги присутствуют, это не пустой портфель. ## Идентификация и оформление инструмента UID определяет конкретный инструмент брокера и используется для перехода на его страницу. FIGI, ISIN и тикер сохраняются как доступные идентификаторы; одно название или совпадение тикера не доказывает тождество инструментов. Для получения метаданных backend сначала использует UID, затем FIGI. Отображаемое имя выбирается в порядке: полное имя, тикер, FIGI. Если нет и FIGI, текущая реализация использует `Unknown instrument`. ISIN, тикер и `logoName` могут быть `null`. `logoName` — имя файла бренда, а не URL: frontend строит ссылку на публичный CDN. Ошибка изображения или метаданных не меняет количество, суммы и свежесть снимка и не скрывает финансовые данные. Metadata обновляется независимо; отсутствие имени не задерживает выдачу финансового снимка и оставляет доступный идентификатор. ## Структура и доли `structure` распределяет стоимость по четырём категориям: акции (`STOCK`), облигации (`BOND`), прочие инструменты (`OTHER`) и деньги (`CASH`). Торгуемые валютные инструменты входят в `OTHER`; денежные остатки — в `CASH`. Сервер строит структуру из позиций и денег, без повторного добавления `totalsByCurrency`. Доля категории — её стоимость / известная стоимость позиций и денег в выбранной валюте × 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) и [точные значения и валютные агрегаты](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/portfolio-view/spec.md#requirement-точные-значения-и-валютные-агрегаты). Структура и общий режим подтверждены реализацией и её проверками; отдельных требований к ним в основной спецификации портфеля пока нет. Поля транспорта следует сверять с [HTTP API](../../architecture/http-api.md), а свежесть — с [потоком загрузки](flows/portfolio-loading.md).