feat(db): flow_link, metric_cash_flow_broker и price_coverage
Три таблицы одной миграцией, а не тремя: автогенерация из трёх параллельных веток дала бы три ревизии с общим down_revision, то есть ручную разборку ветвления вместо экономии. price_coverage засевается прямо в миграции из price_daily: она отвечает на вопрос «с какой даты мы УЖЕ спрашивали ISS», и без засева первый же прогон moex перекачал бы историю всех 77 бумаг целиком. flow_link_kind снимается на откате явно. DROP TABLE оставляет тип в базе, и следующий upgrade упал бы на CREATE TYPE — то же, что уже сделано для остальных енумов домена.
This commit is contained in:
@@ -48,6 +48,40 @@ class MetricCashFlowMonthly(Base):
|
||||
computed_at: Mapped[datetime] = mapped_column(server_default=func.now())
|
||||
|
||||
|
||||
class MetricCashFlowBroker(Base):
|
||||
"""Money put into and taken out of the brokerage accounts, per scope and month.
|
||||
|
||||
The sibling of `metric_cash_flow_monthly`, for the other half of the picture: that one
|
||||
answers what the household earned and spent, this one what it moved across the portfolio
|
||||
boundary. The scope key is the same string as everywhere else in the investment metrics
|
||||
(`all`, `account:<id>`, `portfolio:<id>`).
|
||||
|
||||
Deposits and withdrawals are kept apart, both as positive magnitudes, because the screen
|
||||
shows both bars: a month that took 200 000 ₽ in and 200 000 ₽ out is not the same month
|
||||
as one that saw no money at all, and a single signed sum cannot tell them apart.
|
||||
`net_rub = deposits_rub - withdrawals_rub` and equals the month's sum of
|
||||
`metric_portfolio_value_daily.external_flow_rub` for the same scope.
|
||||
|
||||
A month with no flow gets no row at all — the series is sparse on purpose, so the client
|
||||
can tell "nothing happened" from "zero on balance".
|
||||
"""
|
||||
|
||||
__tablename__ = "metric_cash_flow_broker"
|
||||
|
||||
scope: Mapped[str] = mapped_column(String(32), primary_key=True)
|
||||
month: Mapped[date] = mapped_column(primary_key=True)
|
||||
"""First day of the month."""
|
||||
deposits_rub: Mapped[Decimal]
|
||||
"""Everything that came in, positive: cash deposits and securities transferred in."""
|
||||
withdrawals_rub: Mapped[Decimal]
|
||||
"""Everything that went out, also positive."""
|
||||
net_rub: Mapped[Decimal]
|
||||
"""deposits - withdrawals; negative in a month that took more out than it put in."""
|
||||
event_count: Mapped[int] = mapped_column(Integer, default=0)
|
||||
"""Flow events behind the row — the ones that converted; see `metric_data_quality`."""
|
||||
computed_at: Mapped[datetime] = mapped_column(server_default=func.now())
|
||||
|
||||
|
||||
class MetricSpendingByCategory(Base):
|
||||
__tablename__ = "metric_spending_by_category"
|
||||
__table_args__ = (UniqueConstraint("month", "category_id", postgresql_nulls_not_distinct=True),)
|
||||
|
||||
Reference in New Issue
Block a user