"""benchmark: the MOEX indices the portfolio is compared against The list is data, but there is no screen to add to it, and an empty `benchmark` table leaves `/analytics/benchmarks` and the overlay on the price chart with nothing to draw. IMOEX and MCFTR are the pair the comparison is built around (a price index next to its dividend- reinvested twin, so the gap between them is visible); RGBITR is there for a bond-heavy portfolio and is not shown unasked. A row that is already there is left as the user set it. Revision ID: f3a91c7d5e28 Revises: e8b21f6a90c3 Create Date: 2026-09-20 18:00:00.000000 """ from __future__ import annotations from collections.abc import Sequence import sqlalchemy as sa from alembic import op revision: str = "f3a91c7d5e28" down_revision: str | None = "e8b21f6a90c3" branch_labels: str | Sequence[str] | None = None depends_on: str | Sequence[str] | None = None BENCHMARKS = [ ("IMOEX", "Индекс МосБиржи", "price", True), ("MCFTR", "Индекс МосБиржи полной доходности «брутто»", "total_return", True), ( "RGBITR", "Индекс МосБиржи государственных облигаций (полной доходности)", "total_return", False, ), ] def upgrade() -> None: insert = sa.text( "INSERT INTO benchmark (code, name, kind, source, currency, is_default, is_active) " "VALUES (:code, :name, CAST(:kind AS benchmark_kind), 'moex', 'RUB', :is_default, true) " "ON CONFLICT (code) DO NOTHING" ) for code, name, kind, is_default in BENCHMARKS: op.execute(insert.bindparams(code=code, name=name, kind=kind, is_default=is_default)) def downgrade() -> None: op.execute(sa.text("DELETE FROM benchmark WHERE code IN ('IMOEX', 'MCFTR', 'RGBITR')"))