From e1981a24bf844aa760f2e465906ad073db571b6d Mon Sep 17 00:00:00 2001 From: Sergey Krylov Date: Sat, 7 Nov 2026 20:13:24 +0300 Subject: [PATCH] docs(adr): record investment performance vs index decision (WealthLedger/main#54) --- adr/023-investment-performance-vs-index.md | 90 ++++++++++++++++++++++ adr/README.md | 1 + 2 files changed, 91 insertions(+) create mode 100644 adr/023-investment-performance-vs-index.md diff --git a/adr/023-investment-performance-vs-index.md b/adr/023-investment-performance-vs-index.md new file mode 100644 index 0000000..7f76264 --- /dev/null +++ b/adr/023-investment-performance-vs-index.md @@ -0,0 +1,90 @@ +# 023. Результат инвестирования относительно индекса Мосбиржи + +**Status:** Accepted. **Date:** 2026-11-07. Дополняет [ADR +019](019-hourly-reads-and-online-instrument-reference.md) исключением для +публичной истории закрытий индексов MOEX (по образцу +[ADR 022](022-stored-instrument-classification.md)). Решение оформлено в +[Issue WealthLedger/main#54](https://git.personal.ksv741.ru/WealthLedger/main/issues/54) +и утверждённом change `specs/openspec/changes/2026-11-07-investment-performance-vs-index/` +в репозитории specs. + +## Context + +Вкладка «Результат» должна показать, как счёт или «Все счета» справились с +деньгами, которые в него внесли, и сравнить это с вложением тех же денег в +индекс. Простая доходность «стоимость / вложено − 1» искажает оценку, когда +пополнения и выводы распределены во времени. Доходность по времени (TWR) +требует истории стоимости на каждую дату потока, а её в системе нет: хранится +только последний Portfolio. + +Сравнение с ценовым IMOEX не отвечает на вопрос пользователя: IMOEX не +включает дивиденды и купоны, а эталон должен учитывать их так же, как +портфель. ADR 019 запрещает хранить справочные данные как долговременный +источник; индексы — публичные временные ряды, для которых онлайн-запрос при +каждом открытии вкладки неприемлем по задержке и лимитам внешнего сервиса. + +## Decision + +- **«Доходность» для «Результата инвестирования» — money-weighted return (XIRR)** + по внешним денежным потокам счёта и текущей оценке Portfolio. Термин + «доходность» снимается с запрета только для этого понятия; прочие понятия + «не доходность» сохраняют прежний текст. +- **Сравнение — теневой портфель в индексе.** Те же внешние потоки + конвертируются в единицы индекса по закрытию дня потока (или ближайшего + предыдущего торгового дня) и оцениваются по закрытию на дату расчёта. + Эталон — полный доходный индекс MCFTRR; XIRR индекса считается на тех же + потоках. Это идея PME по Long–Nickels; в интерфейсе — «те же деньги в + индексе Мосбиржи». +- **IMOEX — только справочный индекс.** Он показывается рядом, но не + участвует в «опережении» и не является базой сравнения. +- **Только RUB.** Счёт с потоками или стоимостью в другой валюте не + рассчитывается (причина `NON_RUB_ACTIVITY`); конвертация валют не + выполняется. +- **Период короче года** показывается как «за N дн.» без annualization; + `basis = annual` только при истории от 365 дней. +- **Хранение закрытий индексов.** Пара (индекс, торговый день по Москве) → + CLOSE хранится локально с upsert. Это исключение из ADR 019: публичная + история индекса, не привязанная к пользователю или подключению, хранится + как долговременные данные. Остальные справочные сведения ADR 019 не + меняются. + +### Отклонённые варианты + +- **Простой ROI** (`стоимость / вложено − 1`): искажён моментами пополнений + и выводов, поэтому не сравнивается с индексом на тех же деньгах. +- **TWR (time-weighted return):** требует стоимости портфеля на каждую дату + потока; история оценок в системе отсутствует. Сохранение такой истории + вне этого решения. +- **Ценовой IMOEX как ориентир:** не учитывает дивиденды и купоны, поэтому + сравнение с портфелем, где они учтены, смещено. +- **Конвертация валют (FX):** потребовала бы исторических курсов и + отдельного решения о методике; не нужна для личного RUB-учёта. + +## Consequences + +- Результат зависит от сохранённых операций T-Bank и последнего полного + Portfolio: неполная история или неполная оценка дают `data: null` или + `completeness: incomplete` по правилам change, а не подменяются оценкой. +- Первая загрузка индекса догружает историю от `from − 10 дней`; при + недостатке закрытий появляется `INDEX_HISTORY_UNAVAILABLE`. Фоновая + синхронизация индексов не вводится. +- Исключение из ADR 019 ограничено закрытиями индексов MOEX. + +### Оговорки и условия источника + +- **Налоги.** MCFTRR при расчёте дивидендов и купонов использует ставки для + организаций, а не НДФЛ физического лица. Индекс — ориентир альтернативы, + а не точная модель налогов пользователя. Оговорка фиксируется в методике + («Как считали»). +- **Данные MOEX ISS.** ISS бесплатно отдаёт данные «для ознакомления». + Приложение личное и локальное, данные не распространяются; источник + указывается в «Как считали». +- **Правило парности переводов** между своими счетами в «Все счета» пока + подтверждается на реальных данных; это открытый вопрос change, а не часть + решения. + +## Links + +- Issue: [WealthLedger/main#54](https://git.personal.ksv741.ru/WealthLedger/main/issues/54) +- Change: `specs/openspec/changes/2026-11-07-investment-performance-vs-index/` + (proposal, system-analysis «Расчёт» и «Индексы MOEX», design, Decisions backend 3, 5) diff --git a/adr/README.md b/adr/README.md index 6cac8d9..a98f3b5 100644 --- a/adr/README.md +++ b/adr/README.md @@ -27,3 +27,4 @@ - [020 — Evidence for hourly sync read boundaries](020-hourly-sync-verification-evidence.md) - [021 — Тихое чтение и редкие подтверждения](021-quiet-reading-and-rare-confirmations.md) - [022 — Хранимая классификация инструментов T-Bank](022-stored-instrument-classification.md) +- [023 — Результат инвестирования относительно индекса Мосбиржи](023-investment-performance-vs-index.md)