feat(moex): история бумаг с листинга и цены индексов для бенчмарков
Окно бэкфилла начинается с history_from доски, а не с первой покупки: график цены показывает историю бумаги целиком. Для активных бенчмарков source=moex синк создаёт instrument и качает индекс с его доски (IMOEX и RGBITR на SNDX, MCFTR на RTSI). Миграция засевает IMOEX, MCFTR и RGBITR; тесты чистят таблицы перед каждым тестом, чтобы сид не попадал в первый из них.
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
"""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')"))
|
||||
Reference in New Issue
Block a user