All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / changes (pull_request) Successful in 10s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 5m16s
Три XLSX ЦБ (выдачи, ставка, задолженность) в разрезе субъектов, помесячно с 01.2019, + ключевая ставка через SOAP DailyInfo.asmx (метод KeyRate; GET на нём не работает, только POST). Всё анонимно, без ключа. Таблицы: cbr_mortgage_series (region, period_month, series) и cbr_key_rate. fetched_at НЕ обновляется в DO UPDATE — по уроку #2846 колонка значит «когда мы ВПЕРВЫЕ увидели период» и по ней меряется такт публикации источника. Раскладка листов у ЦБ РАЗНАЯ, и это ловушка: в 02_11/02_13 шапка периодов в строке 3 текстом («Январь 2019»), а в 02_14 (задолженность) — уже в строке 2 и настоящими datetime. С захардкоженным индексом строки серия debt_rub молча давала НОЛЬ строк при зелёных тестах. Теперь строка шапки ищется динамически: берётся строка с наибольшим числом распознанных периодов среди первых шести. Проверено на живых файлах: каждая из трёх серий даёт 8 736 точек (96 территорий × 91 месяц, 01.2019–07.2026); по Свердловской области 91 месяц, последняя ставка 11.49. estimator.py не тронут: как ипотечная ставка войдёт в оценку — отдельное продуктовое решение, этот PR только про данные. Миграции 292 (таблицы) и 293 (сид расписания, enabled=false, interval_days 7). Новая зависимость: openpyxl.
95 lines
3.4 KiB
Python
95 lines
3.4 KiB
Python
"""CLI: макро-ряды ЦБ РФ — ипотека по субъектам + ключевая ставка (#issue см. vault).
|
|
|
|
Запуск из контейнера:
|
|
python -m app.tasks.cbr_macro_pull # всё: ипотека + ставка
|
|
python -m app.tasks.cbr_macro_pull --dry-run
|
|
python -m app.tasks.cbr_macro_pull --series rate_rub debt_rub
|
|
python -m app.tasks.cbr_macro_pull --skip-mortgage --from-date 2024-01-01 --to-date 2024-12-31
|
|
python -m app.tasks.cbr_macro_pull --skip-key-rate
|
|
|
|
Делегирует всю логику app.services.cbr_macro (download → parse → upsert); этот
|
|
модуль — только argparse + lifecycle сессии + commit между стадиями.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import logging
|
|
from datetime import date
|
|
|
|
from app.core.db import SessionLocal
|
|
from app.services.cbr_macro import (
|
|
CBR_MORTGAGE_SERIES,
|
|
load_key_rate,
|
|
pull_cbr_mortgage,
|
|
)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
_SERIES_SLUGS = [s.slug for s in CBR_MORTGAGE_SERIES]
|
|
|
|
|
|
def build_parser() -> argparse.ArgumentParser:
|
|
parser = argparse.ArgumentParser(description="Загрузка макро-рядов ЦБ РФ")
|
|
parser.add_argument("--dry-run", action="store_true", help="только посчитать, без upsert")
|
|
parser.add_argument(
|
|
"--series",
|
|
nargs="*",
|
|
choices=_SERIES_SLUGS,
|
|
default=None,
|
|
help="подмножество серий ипотеки (по умолчанию — все)",
|
|
)
|
|
parser.add_argument("--skip-mortgage", action="store_true", help="не тянуть ипотечные серии")
|
|
parser.add_argument("--skip-key-rate", action="store_true", help="не тянуть ключевую ставку")
|
|
parser.add_argument(
|
|
"--from-date", type=date.fromisoformat, default=None, help="ключевая ставка: ISO-дата от"
|
|
)
|
|
parser.add_argument(
|
|
"--to-date", type=date.fromisoformat, default=None, help="ключевая ставка: ISO-дата до"
|
|
)
|
|
return parser
|
|
|
|
|
|
def main() -> None:
|
|
logging.basicConfig(
|
|
level=logging.INFO, format="%(asctime)s %(levelname)s %(name)s: %(message)s"
|
|
)
|
|
parser = build_parser()
|
|
args = parser.parse_args()
|
|
if args.skip_mortgage and args.skip_key_rate:
|
|
parser.error("--skip-mortgage и --skip-key-rate вместе не имеют смысла")
|
|
|
|
mortgage_counts: dict[str, int] = {}
|
|
key_rate_counts: dict[str, int] = {}
|
|
|
|
db = SessionLocal()
|
|
try:
|
|
if not args.skip_mortgage:
|
|
series_list = None
|
|
if args.series:
|
|
series_list = [s for s in CBR_MORTGAGE_SERIES if s.slug in args.series]
|
|
mortgage_counts = pull_cbr_mortgage(
|
|
db, series_list=series_list, dry_run=args.dry_run
|
|
)
|
|
if not args.dry_run:
|
|
db.commit()
|
|
|
|
if not args.skip_key_rate:
|
|
key_rate_counts = load_key_rate(
|
|
db, from_date=args.from_date, to_date=args.to_date, dry_run=args.dry_run
|
|
)
|
|
if not args.dry_run:
|
|
db.commit()
|
|
|
|
logger.info(
|
|
"cbr_macro_pull DONE: dry_run=%s mortgage=%s key_rate=%s",
|
|
args.dry_run,
|
|
mortgage_counts,
|
|
key_rate_counts,
|
|
)
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|