build 039: complete Quotes Feed migration foundation

This commit is contained in:
2026-07-14 09:58:16 +03:00
parent 26deb861bc
commit 7b62873832
443 changed files with 80452 additions and 1335 deletions

View File

@@ -0,0 +1,142 @@
# app/src/market_data/acquisition/registry.py
from __future__ import annotations
from src.market_data.acquisition.exceptions import (
InstrumentFeedRegistryError,
QuoteFeedRegistryError,
)
from src.market_data.acquisition.protocol import (
InstrumentFeedProtocol,
QuoteFeedProtocol,
)
# Реестр доступных Feed справочника инструментов.
class InstrumentFeedRegistry:
def __init__(self) -> None:
self._feeds: dict[str, InstrumentFeedProtocol] = {}
def register(
self,
source_name: str,
feed: InstrumentFeedProtocol,
) -> None:
"""
Зарегистрировать Instrument Feed для указанного источника.
Повторная регистрация того же имени запрещена, чтобы исключить
неявную замену production-зависимости.
"""
normalized_source_name = self._normalize_source_name(source_name)
if not isinstance(feed, InstrumentFeedProtocol):
raise InstrumentFeedRegistryError(
f"Объект для источника '{normalized_source_name}' "
"не соответствует InstrumentFeedProtocol."
)
if normalized_source_name in self._feeds:
raise InstrumentFeedRegistryError(
f"Instrument Feed для источника "
f"'{normalized_source_name}' уже зарегистрирован."
)
self._feeds[normalized_source_name] = feed
def get(
self,
source_name: str,
) -> InstrumentFeedProtocol:
"""Вернуть зарегистрированный Instrument Feed по имени источника."""
normalized_source_name = self._normalize_source_name(source_name)
feed = self._feeds.get(normalized_source_name)
if feed is None:
raise InstrumentFeedRegistryError(
f"Instrument Feed для источника "
f"'{normalized_source_name}' не зарегистрирован."
)
return feed
def _normalize_source_name(
self,
source_name: str,
) -> str:
normalized_source_name = source_name.strip()
if not normalized_source_name:
raise InstrumentFeedRegistryError(
"Имя источника Instrument Feed не должно быть пустым."
)
return normalized_source_name
# Реестр доступных потоков текущих котировок.
class QuoteFeedRegistry:
def __init__(self) -> None:
self._feeds: dict[str, QuoteFeedProtocol] = {}
def register(
self,
source_name: str,
feed: QuoteFeedProtocol,
) -> None:
"""
Зарегистрировать Quotes Feed для указанного источника.
Повторная регистрация того же имени запрещена, чтобы исключить
неявную замену production-зависимости.
"""
normalized_source_name = self._normalize_source_name(source_name)
if not isinstance(feed, QuoteFeedProtocol):
raise QuoteFeedRegistryError(
f"Объект для источника '{normalized_source_name}' "
"не соответствует QuoteFeedProtocol."
)
if normalized_source_name in self._feeds:
raise QuoteFeedRegistryError(
f"Quotes Feed для источника "
f"'{normalized_source_name}' уже зарегистрирован."
)
self._feeds[normalized_source_name] = feed
def get(
self,
source_name: str,
) -> QuoteFeedProtocol:
"""Вернуть зарегистрированный Quotes Feed по имени источника."""
normalized_source_name = self._normalize_source_name(source_name)
feed = self._feeds.get(normalized_source_name)
if feed is None:
raise QuoteFeedRegistryError(
f"Quotes Feed для источника "
f"'{normalized_source_name}' не зарегистрирован."
)
return feed
def _normalize_source_name(
self,
source_name: str,
) -> str:
normalized_source_name = source_name.strip()
if not normalized_source_name:
raise QuoteFeedRegistryError(
"Имя источника Quotes Feed не должно быть пустым."
)
return normalized_source_name