Окно бэкфилла начинается с history_from доски, а не с первой покупки: график цены показывает историю бумаги целиком. Для активных бенчмарков source=moex синк создаёт instrument и качает индекс с его доски (IMOEX и RGBITR на SNDX, MCFTR на RTSI). Миграция засевает IMOEX, MCFTR и RGBITR; тесты чистят таблицы перед каждым тестом, чтобы сид не попадал в первый из них.
50 lines
1.8 KiB
Python
50 lines
1.8 KiB
Python
"""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')"))
|