feat(analytics): доходы, ребалансировка, налоги, бенчмарки и цели — фаза 4

Второй источник выплат: sources/tinvest/sync_events.py (GetDividends,
GetBondCoupons, GetBondEvents) и sources/moex/payouts.py (ISS bondization +
dividends). Приоритет между ними — pricing/payouts.resolve_payouts, решается
на чтении, а не на записи: corporate_action уникален по (instrument_id, kind,
source, source_id), обе версии сосуществуют, и правило можно поменять без
ресинка истории. Амортизация от MOEX идёт в bond_nominal_schedule, а не
в corporate_action — этим типом безраздельно владеет
ledger/corporate_actions.py.

analytics/income.py — metric_income_monthly (факт) и metric_income_calendar
(прошлое и прогноз) с basis paid/announced/history на каждой строке, три
источника числа не смешиваются. analytics/rebalance.py — сделки по
portfolio_target пропорционально внутри бакета, лоты только вниз, покупки не
занимают у ещё не свершившихся продаж. analytics/tax.py — оценка, не замена
справки брокера: дивиденды/купоны gross, реализованный результат из
lot_disposal с переоценкой каждой ноги на свою дату. analytics/benchmarks.py —
TWR индекса на сетке портфеля, kind (price/total_return) не скрывается.
analytics/goals.py — прогресс цели и нужный взнос по trailing XIRR.

Четыре шага зарегистрированы в register_steps: benchmarks после returns
(общая сетка дат), rebalance после allocation (её веса, не пересчитывает),
income и tax после lots (нужен lot_disposal).
This commit is contained in:
Dmitry
2026-09-19 10:42:50 +03:00
parent ff3b76871d
commit 15f5812ea4
42 changed files with 10607 additions and 3 deletions
+26
View File
@@ -25,19 +25,33 @@ from fintracker.models.ledger import (
)
from fintracker.models.metrics import (
AllocationDimension,
IncomeBasis,
MetricAllocation,
MetricBenchmarkReturns,
MetricCashFlowBroker,
MetricCashFlowMonthly,
MetricDataQuality,
MetricGoalProgress,
MetricHolding,
MetricIncomeCalendar,
MetricIncomeMonthly,
MetricNetWorthDaily,
MetricPortfolioValueDaily,
MetricRebalance,
MetricRefreshLog,
MetricReturns,
MetricRunway,
MetricSpendingByCategory,
MetricTaxYear,
)
from fintracker.models.planning import (
Benchmark,
BenchmarkKind,
Goal,
PortfolioTarget,
)
from fintracker.models.pricing import (
BondNominalSchedule,
CashSnapshot,
CorporateAction,
CorporateActionKind,
@@ -95,6 +109,9 @@ __all__ = [
"AllocationDimension",
"AppUser",
"AssetClass",
"Benchmark",
"BenchmarkKind",
"BondNominalSchedule",
"Broker",
"CashSnapshot",
"CashTxn",
@@ -111,6 +128,8 @@ __all__ = [
"FlowLinkKind",
"FlowType",
"FxRateDaily",
"Goal",
"IncomeBasis",
"Instrument",
"InstrumentAlias",
"JobStatus",
@@ -118,20 +137,27 @@ __all__ = [
"LotDisposal",
"Merchant",
"MetricAllocation",
"MetricBenchmarkReturns",
"MetricCashFlowBroker",
"MetricCashFlowMonthly",
"MetricDataQuality",
"MetricGoalProgress",
"MetricHolding",
"MetricIncomeCalendar",
"MetricIncomeMonthly",
"MetricNetWorthDaily",
"MetricPortfolioValueDaily",
"MetricRebalance",
"MetricRefreshLog",
"MetricReturns",
"MetricRunway",
"MetricSpendingByCategory",
"MetricTaxYear",
"PendingInstrument",
"PendingInstrumentStatus",
"Portfolio",
"PortfolioAccount",
"PortfolioTarget",
"PositionSnapshot",
"PriceCoverage",
"PriceDaily",