bquant.analysis.zones.pipeline — Пайплайн анализа зон v2.1

Этот документ фиксирует ключевые изменения API, связанные с глобальным расчётом свингов. Все описания приведены на русском языке в соответствии с требованиями плана 6.2.2.

Обзор рабочего процесса

  1. ZoneAnalysisPipeline._prepare_data() — подготовка данных и вычисление индикаторов.

  2. ZoneAnalysisPipeline._calculate_global_swings() — (новый шаг) глобальный расчёт свингов, если swing_scope="global".

  3. ZoneAnalysisPipeline._detect_zones() — детекция зон выбранной стратегией.

  4. ZoneAnalysisPipeline._inject_swing_context() — (новый шаг) инъекция глобального контекста в каждую зону.

  5. ZoneAnalysisPipeline._analyze_zones() — извлечение признаков, включая ZoneFeaturesAnalyzer.

Диаграмма последовательности:

prepare_dataframe() ──▶ _calculate_global_swings()
         │                    │
         │                    └──► SwingContext (глобальные точки)
         ▼
 detect_zones() ──▶ _inject_swing_context(zones, context)
         │
         ▼
 analyze_zones() ──▶ ZoneAnalysisResult (zones + features + metadata)

_calculate_global_swings(data: pd.DataFrame) -> SwingContext

  • Вызывается при config.swing_scope == "global" (значение по умолчанию).

  • Получает подготовленный датафрейм (с индикаторами, ATR и т.п.).

  • Находит активную стратегию свингов через _get_active_swing_strategy().

  • Требует, чтобы стратегия реализовала метод calculate_global() и вернула SwingContext.

  • Логирует количество найденных точек, что важно для диагностики.

  • При любой ошибке выбрасывает исключение, которое перехватывается на уровне _run_without_cache() и приводит к фолбэку в per_zone.

Минимальный пример

pipeline = ZoneAnalysisPipeline(config.with_swing_scope("global"), analyzer)
context = pipeline._calculate_global_swings(prepared_df)
print(len(context.swing_points))

_inject_swing_context(zones: List[ZoneInfo], swing_context: SwingContext)

  • Присваивает ссылку на глобальный контекст каждому ZoneInfo.

  • Не изменяет порядок и не фильтрует зоны.

  • Логирует количество обработанных зон (уровень DEBUG).

  • После вызова метод ZoneInfo.get_zone_swings() возвращает глобальные точки без повторного расчёта.

Контрольный сценарий

zones = pipeline._detect_zones(prepared_df)
pipeline._inject_swing_context(zones, context)
assert all(zone.swing_context is context for zone in zones)

ZoneAnalysisBuilder.with_swing_scope(scope: Literal["per_zone", "global"])

  • Fluent-метод билдера, который управляет режимом расчёта свингов.

  • Допустимые значения: "global" (по умолчанию) и "per_zone".

  • Хранит выбранное значение в ZoneAnalysisConfig, которое затем читает пайплайн.

  • Если метод не вызвать, используется global (по умолчанию).

Пример использования билдера

from bquant.analysis.zones import analyze_zones

result = (
    analyze_zones(df)
    .with_swing_scope("global")
    .with_strategies(swing="zigzag")
    .analyze()
    .build()
)

Обработка ошибок и фолбэки

  • Если стратегия не поддерживает calculate_global, пайплайн логирует предупреждение и переключается на per_zone.

  • При неуспешном глобальном расчёте (исключение в стратегии) _run_without_cache() оставляет зоны без контекста; анализатор признаков автоматически использует локальные данные.

  • В трассировке ZoneAnalysisResult.metadata['swing_calculation_mode'] фиксируется фактический режим (глобальный или локальный).

Эти изменения делают работу пайплайна предсказуемой и прозрачной, а также упрощают диагностику при интеграции глобальных свингов в пользовательские сценарии.