docs: describe RUB-only behavior (WealthLedger/main#55)

This commit is contained in:
2026-11-11 08:22:39 +03:00
parent f504a0f566
commit e0b54aa2bb
17 changed files with 86 additions and 102 deletions
+17 -17
View File
@@ -9,6 +9,7 @@
Деньги представлены значением Money: ISO-код валюты и десятичная строка,
например `{ "currency": "RUB", "value": "12500.5" }` — условный пример.
Валюта всегда `RUB`: система работает только с рублями.
Количества также передаются десятичными строками. Backend выполняет
десятичную арифметику без промежуточного `Number`, нормализует отрицательные
целую и дробную части и убирает незначащие конечные нули. Экспоненциальной
@@ -18,7 +19,7 @@
`null` означает, что показатель нельзя определить из доступных данных.
Это не ноль. Известная нулевая цена отличается от отсутствующей;
позиция с ненулевым количеством и неизвестной стоимостью остаётся в составе.
Несколько валют никогда не складываются в одну общую стоимость.
Позиции и деньги в валютах, отличных от RUB, отфильтровываются при получении из T-Bank и не участвуют ни в одном итоге.
## Состав и денежные показатели
@@ -26,25 +27,25 @@
| --- | --- | --- |
| Позиция | Ненулевое количество обычного инструмента из `GetPortfolio.positions` | Виртуальные позиции не включаются; порядок источника сохраняется |
| `quantity` | Количество из текущей позиции брокера | Допустимы дробные и отрицательные количества; это не число лотов |
| `currentValue` | Количество × текущая цена из `GetPortfolio` | `null`, если цена или её валюта недоступны |
| `currentValue` | Количество × текущая цена из `GetPortfolio` | `null`, если цена недоступна |
| `averagePurchasePrice` | Средняя цена позиции, переданная брокером | Это цена единицы, а не сумма затрат или рассчитанная приложением история покупок |
| `absoluteReturn` | Количество × (текущая цена − средняя цена) | Требует обеих цен в одной известной валюте; не включает продажи, купоны и дивиденды |
| Cash Balance | Суммы из `GetPositions.money`, объединённые по валюте | Заблокированные деньги не прибавляются; торгуемый инструмент `CURRENCY` остаётся позицией |
| `totalsByCurrency` | Стоимости позиций + доступные деньги той же валюты | Не включает невычислимую стоимость; не обещает полную оценку портфеля |
| `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: прибавление денег к ней второй раз неверно.
При отсутствии вычислимой стоимости у части позиций известный итог остаётся
полезен, но представляет только оценённую часть. Известные нулевые итоги
отдельного счёта не создают валютные карточки. Если `totalsByCurrency` пуст,
но позиции или деньги присутствуют, это не пустой портфель.
отдельного счёта не создают отдельную итоговую карточку. Если итог Portfolio
отсутствует, но позиции или деньги присутствуют, это не пустой портфель.
## Результат инвестирования
@@ -81,33 +82,32 @@ ISIN, тикер и `logoName` могут быть `null`. `logoName` — имя
облигации (`BOND`), прочие инструменты (`OTHER`) и деньги (`CASH`).
Торгуемые валютные инструменты входят в `OTHER`; денежные остатки — в `CASH`.
Сервер строит структуру из позиций и денег, без повторного добавления
`totalsByCurrency`.
итога Portfolio.
Доля категории — её стоимость / известная стоимость позиций и денег
в выбранной валюте × 100. Backend округляет процент до шести знаков;
× 100. Backend округляет процент до шести знаков;
frontend показывает до сотых. Положительное значение меньше 0,01%
отображается как «< 0,01 %», если серверное округление не превратило его в ноль.
В геометрию диаграммы передаются только числовые проценты; суммы в списке
и подсказке форматируются из исходных точных строк.
Доля на карточке отдельной позиции использует другой знаменатель:
сумму стоимостей всех позиций той же валюты **без денег**. Это приблизительный
сумму стоимостей всех отображаемых позиций **без денег**. Это приблизительный
показатель для отображения, рассчитанный frontend. Он не изменяет Money.
В режиме всех счетов знаменатель охватывает все показанные счета.
| Состояние | Доступное представление |
| --- | --- |
| Все составляющие оценены, неотрицательны, итог положителен | Суммы, доли и кольцевая диаграмма выбранной валюты |
| Есть позиция без оценки | `unvaluedCategories` содержит её категорию и количество; суммы известной части остаются, доли и кольцо недоступны для всех валют |
| Есть отрицательная составляющая | Суммы со знаком остаются; доли и кольцо отключены для её валюты, даже если итог категории положителен |
| Все составляющие оценены, неотрицательны, итог положителен | Суммы, доли и кольцевая диаграмма |
| Есть позиция без оценки | `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-точные-значения-и-валютные-агрегаты).
и [точные значения и итоговая сумма в 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),