"""Обновление котировок MOEX и курса CNY за дату — для запуска по расписанию. python -m app.jobs.update_market # предыдущий рабочий день python -m app.jobs.update_market --date 2026-10-08 Работает от пользователя `system`. Код выхода: 0 — без ошибок (отсутствие торгов ошибкой не считается), 1 — были ошибки по бумагам/курсу или сбой, 2 — неверные аргументы. """ from __future__ import annotations import argparse import logging from collections.abc import Sequence from datetime import date from app.core.logging import setup_logging from app.db.base import run_db from app.db.types import SYSTEM_USER from app.services import fx_rates, market_data from app.services.dates import previous_business_day logger = logging.getLogger("app.jobs.update_market") def _parse_date(value: str) -> date: try: return date.fromisoformat(value) except ValueError as exc: raise argparse.ArgumentTypeError( f"дата должна быть в формате ГГГГ-ММ-ДД, получено «{value}»" ) from exc def _update_quotes(on_date: date) -> bool: try: result = run_db(market_data.update(on_date, SYSTEM_USER)) except Exception: # noqa: BLE001 logger.exception("Котировки: сбой обновления") return False for message in result.messages: logger.info("Котировки: %s", message) logger.log( logging.INFO if result.ok else logging.ERROR, "Котировки на %s: обновлено %d, без торгов %d, ошибок %d", on_date.isoformat(), result.updated, result.no_trades, result.errors, ) return result.ok def _update_fx(on_date: date) -> bool: try: result = run_db(fx_rates.update(on_date, SYSTEM_USER)) except Exception: # noqa: BLE001 logger.exception("Курс CNY: сбой обновления") return False for message in result.messages: logger.log( logging.INFO if result.ok else logging.ERROR, "Курс CNY: %s", message ) return result.ok def main(argv: Sequence[str] | None = None) -> int: parser = argparse.ArgumentParser( prog="python -m app.jobs.update_market", description="Обновить котировки MOEX и курс CNY за дату.", ) parser.add_argument( "--date", type=_parse_date, default=None, help="Дата ГГГГ-ММ-ДД (по умолчанию — предыдущий рабочий день)", ) args = parser.parse_args(argv) setup_logging() on_date = args.date or previous_business_day() logger.info("Старт обновления рыночных данных на %s", on_date.isoformat()) # Курс обновляем, даже если котировки упали, — источники независимы. quotes_ok = _update_quotes(on_date) fx_ok = _update_fx(on_date) ok = quotes_ok and fx_ok logger.log( logging.INFO if ok else logging.ERROR, "Готово: %s", "без ошибок" if ok else "есть ошибки", ) return 0 if ok else 1 if __name__ == "__main__": raise SystemExit(main())