14 KiB
Build 018 — Переключение get_symbol_runtime_status()
Статус
COMPLETE
Цель
Перевести определение торгового состояния инструмента, используемое методом:
ExchangeService.get_symbol_runtime_status()
на каноническую классификацию статусов из подсистемы:
src/market_data/acquisition/
при полном сохранении существующего внешнего контракта ExchangeRuntimeStatus, поведения legacy-кода, UI и runtime-потребителей.
Исходное состояние
До Build 018 классификация биржевых статусов инструмента находилась непосредственно в legacy exchange-слое:
src/integrations/exchange/status.py
и основывалась на локальных наборах:
OPEN_STATUSES
BREAK_STATUSES
Метод:
build_market_status_from_symbol_status()
самостоятельно определял одно из состояний:
OPEN
NOT_TRADABLE
BREAK
UNKNOWN
Это означало, что предметная классификация торгового состояния инструмента оставалась внутри legacy exchange integration layer.
Архитектурное решение
Каноническая классификация статуса инструмента перенесена в:
src/market_data/acquisition/models/status.py
Добавлены следующие сущности:
InstrumentTradingState
InstrumentStatusClassification
classify_instrument_status()
Теперь архитектурная цепочка имеет вид:
raw exchange status
↓
classify_instrument_status()
↓
InstrumentStatusClassification
↓
build_market_status_from_symbol_status()
↓
ExchangeRuntimeStatus
↓
legacy runtime / UI / trading consumers
Таким образом:
market_data/acquisitionотвечает за предметную классификацию состояния инструмента;integrations/exchange/status.pyсохраняет compatibility-функцию преобразования результата в существующийExchangeRuntimeStatus;- существующие runtime-потребители продолжают работать без изменения публичного контракта.
Добавленный файл
src/market_data/acquisition/models/status.py
Файл содержит каноническую модель классификации торгового состояния инструмента.
Основные сущности:
class InstrumentTradingState(StrEnum):
OPEN = "OPEN"
NOT_TRADABLE = "NOT_TRADABLE"
BREAK = "BREAK"
UNKNOWN = "UNKNOWN"
@dataclass(frozen=True, slots=True)
class InstrumentStatusClassification:
state: InstrumentTradingState
normalized_status: str | None
Основная функция:
def classify_instrument_status(
raw_status: str | None,
) -> InstrumentStatusClassification:
Она выполняет:
- нормализацию входного статуса;
- классификацию открытого рынка;
- классификацию неторгуемого инструмента;
- классификацию временной остановки торгов;
- возврат
UNKNOWNдля неизвестного или отсутствующего статуса.
Канонические состояния
Подсистема market_data/acquisition различает четыре предметных состояния:
OPEN
NOT_TRADABLE
BREAK
UNKNOWN
OPEN
Инструмент доступен для торговли.
Поддерживаются существующие legacy-статусы:
TRADING
OPEN
ACTIVE
ENABLED
ONLINE
NOT_TRADABLE
Инструмент существует, но недоступен для обычной торговли.
Поддерживаются:
NOT_TRADABLE
TRADING_DISABLED
MARKET_DISABLED
UNAVAILABLE_FOR_TRADING
CLOSE_ONLY
REDUCE_ONLY
VIEW_ONLY
BREAK
Торги временно остановлены или приостановлены.
Поддерживаются:
BREAK
CLOSED
HALT
HALTED
PAUSED
SUSPENDED
DISABLED
SETTLING
POST_ONLY
UNKNOWN
Используется для:
- неизвестного статуса;
- пустой строки;
None;- значения, отсутствующего в известных классификационных наборах.
Изменение legacy exchange-слоя
Из файла:
src/integrations/exchange/status.py
удалена собственная предметная классификация через публичные наборы:
OPEN_STATUSES
BREAK_STATUSES
Вместо неё используются:
from src.market_data.acquisition.models.status import (
InstrumentTradingState,
classify_instrument_status,
)
Функция:
build_market_status_from_symbol_status()
теперь сначала вызывает:
classification = classify_instrument_status(raw_status)
а затем преобразует каноническое состояние в существующий legacy-контракт:
InstrumentTradingState.OPEN
↓
ExchangeRuntimeStatus(code=OPEN)
InstrumentTradingState.NOT_TRADABLE
↓
ExchangeRuntimeStatus(code=BREAK, reason=market_not_tradable)
InstrumentTradingState.BREAK
↓
ExchangeRuntimeStatus(code=BREAK, reason=market_break)
InstrumentTradingState.UNKNOWN
↓
ExchangeRuntimeStatus(code=UNKNOWN, reason=market_status_unknown)
Сохранённый публичный контракт
Build 018 не изменяет структуру:
ExchangeRuntimeStatus
Сохранены поля:
code
is_open
is_available
is_auth_ok
title
message
ui_line
reason
symbol
raw_status
raw_error
Также сохранён compatibility-метод:
ExchangeRuntimeStatus.as_dict()
Это позволяет не изменять существующие runtime-, UI- и trading-потребители.
Поведение get_symbol_runtime_status()
Метод:
ExchangeService.get_symbol_runtime_status()
сохранил существующий внешний контракт и последовательность обработки.
Архитектурно поток остаётся следующим:
requested symbol
↓
validate_symbol()
↓
ExchangeSymbol
↓
raw symbol status
↓
build_market_status_from_symbol_status()
↓
classify_instrument_status()
↓
ExchangeRuntimeStatus
Для открытого рынка дополнительно сохраняется проверка свежести рыночного snapshot:
OPEN
↓
get_fresh_market_snapshot()
↓
age_seconds > 60
↓
STALE_MARKET_DATA / BREAK
Stale threshold сохранён:
60 секунд
Проверка stale market data выполняется только для рынка, первоначально классифицированного как OPEN.
Сохранённое поведение
Build 018 сохраняет следующие legacy-сценарии:
- mock exchange;
- явный
symbol; - использование
default_symbol, если аргумент равенNone; - invalid symbol;
- ошибка при validation;
OPEN;NOT_TRADABLE;BREAK;UNKNOWN;- stale market data;
- отсутствие
age_seconds; - ошибка получения snapshot;
- нормализованный matched symbol;
- существующий
ExchangeRuntimeStatus; - существующие
reason; - существующие UI-тексты;
- существующие
raw_status.
Кэширование и сетевые запросы
Build 018 не добавляет:
- новый cache;
- новый REST-запрос;
- дополнительную загрузку
exchangeInfo; - дополнительный acquisition service;
- отдельный status feed runtime.
get_symbol_runtime_status() продолжает использовать существующий путь:
validate_symbol()
↓
get_exchange_symbols()
↓
existing ExchangeService cache
↓
Instrument Acquisition path
Таким образом, миграция не создаёт параллельного источника Instrument Reference Data.
Пустые status feed-файлы
На момент Build 018 следующие файлы существуют, но остаются пустыми:
src/market_data/acquisition/models/status.py
src/market_data/acquisition/handlers/status_handler.py
src/market_data/acquisition/feeds/status_feed.py
После Build 018 файл:
src/market_data/acquisition/models/status.py
получил реализацию канонической классификации торгового состояния инструмента.
Файлы:
src/market_data/acquisition/handlers/status_handler.py
src/market_data/acquisition/feeds/status_feed.py
в рамках Build 018 намеренно не реализуются.
Причина: текущая задача не создаёт отдельный Status Feed и не должна вводить новый источник сетевых запросов или параллельный runtime-путь.
Добавленные тесты
Добавлен тестовый файл:
tests/unit/market_data/acquisition/models/test_instrument_status.py
Он проверяет каноническую классификацию:
- все открытые статусы;
- все неторгуемые статусы;
- все break-статусы;
- регистронезависимость;
- удаление внешних пробелов;
- неизвестный статус;
- пустой статус;
None;- immutable-контракт результата.
Также расширено покрытие:
tests/unit/integrations/exchange/test_status.py
для проверки compatibility-преобразования:
InstrumentStatusClassification
↓
ExchangeRuntimeStatus
Целевой regression-набор метода находится в:
tests/unit/integrations/exchange/test_service_symbol_runtime_status.py
Дублирующий тестовый файл:
tests/unit/integrations/exchange/test_service_runtime_status.py
удалён.
Проверка целевого runtime-контракта
Выполнена команда:
python -m pytest \
tests/unit/integrations/exchange/test_service_symbol_runtime_status.py \
-q
Результат:
34 passed in 0.09s
Проверка компиляции
Выполнена команда:
python -m py_compile \
src/market_data/acquisition/models/status.py \
src/integrations/exchange/status.py \
src/integrations/exchange/service.py \
tests/unit/market_data/acquisition/models/test_instrument_status.py \
tests/unit/integrations/exchange/test_status.py \
tests/unit/integrations/exchange/test_service_symbol_runtime_status.py
Результат:
Успешно.
Ошибок компиляции нет.
Полный regression suite
Выполнена команда:
python -m pytest -q
Результат:
387 passed in 0.20s
Архитектурный результат
После Build 018 ответственность разделена следующим образом:
market_data/acquisition/models/status.py
↓
каноническая предметная классификация статуса инструмента
integrations/exchange/status.py
↓
compatibility mapping в legacy ExchangeRuntimeStatus
integrations/exchange/service.py
↓
runtime orchestration, validation и stale market data check
runtime / UI / trading consumers
↓
продолжают использовать существующий ExchangeRuntimeStatus
В результате:
- предметная классификация статуса инструмента больше не принадлежит legacy exchange-слою;
- дублирование
OPEN_STATUSES/BREAK_STATUSESустранено; ExchangeRuntimeStatusсохранён как compatibility boundary;- существующие потребители не требуют массового рефакторинга;
- новый REST-путь не создан;
- новый cache не создан;
- поведение работающего бота сохранено.
Итог
BUILD 018 — COMPLETE
Build 018 завершён при полном прохождении целевых тестов, компиляции и общего regression suite:
34 targeted tests passed
387 total tests passed