# bquant.analysis.zones — Анализ зон

> 💡 **Хотите понять, как это работает?**
>
> Этот документ — технический справочник по API. Для глубокого концептуального разбора внутренней логики пайплайна, читайте наше руководство **[Глубокое погружение: Пайплайн анализатора зон](../../developer_guide/zone_analyzer_deep_dive.md)**.

> **Универсальная Архитектура**
> 
> Анализ зон теперь работает с **ЛЮБЫМ индикатором** без изменений кода!
> 
> **Поддерживаемые индикаторы:**
> - ЛЮБОЙ осциллятор: MACD, RSI, AO, CCI, Stochastic, Williams %R, MFI, CMF, ROC
> - Пользовательские индикаторы из pandas_ta (158 индикаторов)
> - Ваши собственные расчеты
> 
> **Ключевая инновация:** `ZoneInfo.indicator_context` - зоны сами описывают свою стратегию детекции
> 
> **Доказанная универсальность:**
> - ✅ 115 тестов с 10+ реальными индикаторами (MACD, RSI, AO, CCI, Stochastic, Williams, MFI, CMF, ROC, custom)
> - ✅ 100% прохождение тестов
> - ✅ FICTIONAL_INDICATOR_99 тест - работает с индикатором, которого не существует!
> - ✅ НЕТ жестко закодированных имен индикаторов
> 
> **Справочник API:**
> - [Универсальные Стратегии](strategies.md) - аналитические стратегии для ЛЮБОГО индикатора
> - [Руководство по Расширению](../developer_guide/zone_detection_strategies.md) - создание пользовательских стратегий
> - [Модели глобальных свингов](zones/models.md) — `SwingPoint`, `SwingContext`, `ZoneInfo.get_zone_swings()`
> - [Пайплайн с поддержкой global scope](zones/pipeline.md) — `_calculate_global_swings`, `_inject_swing_context`
> - [Стратегии свингов v2](zones/strategies.md) — протокол `SwingCalculationStrategy` и ZigZag/FindPeaks/PivotPoints

## Обзор

Инструменты работы с торговыми зонами: поддержка/сопротивление, признаки зон, последовательности и кластеризация.

## Универсальная Архитектура (v2.1)

### Ключевая Концепция: indicator_context

Каждая обнаруженная зона содержит словарь `indicator_context`, который описывает **КАК** зона была обнаружена:

```python
from bquant.analysis.zones import analyze_zones

result = analyze_zones(df).detect_zones('zero_crossing', indicator_col='RSI_14').build()

# Access zone's detection context
zone = result.zones[0]
context = zone.indicator_context

print(context['detection_indicator'])  # → 'RSI_14'
print(context['detection_strategy'])   # → 'zero_crossing'
print(context['signal_line'])          # → None (single-line indicator)
```

**Стандартные поля (заполняются стратегией детекции):**
- `detection_indicator`: Имя основного столбца индикатора (например, 'RSI_14', 'macd_hist')
- `detection_strategy`: Используемая стратегия (например, 'zero_crossing', 'threshold', 'line_crossing')
- `signal_line`: Вторичный индикатор для 2-линейных стратегий (например, 'STOCH_D')
- `detection_rules`: Полный словарь правил для справки

**Удобные методы:**
```python
# Get primary indicator column
indicator = zone.get_primary_indicator_column()  # → 'RSI_14'

# Get signal line (if exists)
signal = zone.get_signal_line_column()  # → 'STOCH_D' or None
```

### Примеры с Разными Индикаторами

#### MACD (zero-crossing oscillator)
```python
result = (
    analyze_zones(df)
    .with_indicator('custom', 'macd', fast_period=12, slow_period=26, signal_period=9)
    .detect_zones('zero_crossing', indicator_col='macd_hist')
    .analyze()
    .build()
)

# Context: {'detection_indicator': 'macd_hist', 'detection_strategy': 'zero_crossing'}
```

#### RSI (ограниченный индикатор на основе порогов)
```python
result = (
    analyze_zones(df)
    .with_indicator('pandas_ta', 'rsi', length=14)
    .detect_zones('threshold',
                 indicator_col='RSI_14',
                 upper_threshold=70,
                 lower_threshold=30)
    .analyze()
    .build()
)

# Context: {'detection_indicator': 'RSI_14', 'detection_strategy': 'threshold'}
```

#### Stochastic (пересечение 2 линий)
```python
result = (
    analyze_zones(df)
    .with_indicator('pandas_ta', 'stoch', k=14, d=3)
    .detect_zones('line_crossing',
                 line1_col='STOCHk_14_3_3',
                 line2_col='STOCHd_14_3_3')
    .analyze()
    .build()
)

# Context: {'detection_indicator': 'STOCHk_14_3_3', 'signal_line': 'STOCHd_14_3_3'}
```

#### Пользовательский Индикатор (доказывает универсальность!)
```python
# Create your own indicator
df['MY_CUSTOM_OSC'] = df['close'].diff(5) / df['close'].rolling(20).std()

result = (
    analyze_zones(df)
    .detect_zones('zero_crossing', indicator_col='MY_CUSTOM_OSC')
    .analyze()
    .build()
)

# ✅ Работает сразу - НЕТ необходимости в изменениях кода!
# Context: {'detection_indicator': 'MY_CUSTOM_OSC', 'detection_strategy': 'zero_crossing'}
```

#### FICTIONAL_INDICATOR_99 (финальное доказательство)

```python
import numpy as np
from bquant.analysis.zones import analyze_zones
from bquant.data.samples import get_sample_data

df = get_sample_data('tv_xauusd_1h').copy()

# Индикатор, которого НЕ существует в кодовой базе — создаём синусоиду
df['FICTIONAL_INDICATOR_99'] = np.sin(np.linspace(0, 6 * np.pi, len(df))) * 5

result = (
    analyze_zones(df)
    .detect_zones('zero_crossing', indicator_col='FICTIONAL_INDICATOR_99')
    .analyze()
    .build()
)

first_zone = result.zones[0]
print(len(result.zones))  # → 4 зоны
print(first_zone.indicator_context['detection_indicator'])  # → 'FICTIONAL_INDICATOR_99'
```

> ✅ **Если работает с индикатором, которого никогда не было в коде,** то архитектура действительно универсальна.



### Что Нового в v2.1

**Универсальный Анализ Зон:**
- ✨ **5 Стратегий Детекции** - zero_crossing, threshold, line_crossing, preloaded, combined
- ✨ **Работает с ЛЮБЫМ индикатором** - MACD, RSI, Stochastic, AO, CCI, custom, etc.
- ✨ **indicator_context** - зоны сами описывают параметры детекции
- ✨ **Pipeline API** - fluent builder с поддержкой кэширования
- ✨ **Доказанная универсальность** - FICTIONAL_INDICATOR_99 тест проходит

**Аналитические Стратегии (67 метрик всего):**
- ✨ **Паттерн Стратегия** для расширяемых метрик (8 стратегий)
- ✨ **Swing анализ:** 23 метрики через 3 стратегии (ZigZag, FindPeaks, PivotPoints)
- ✨ **Shape анализ:** 3 метрики через StatisticalShapeStrategy (универсальный - любой осциллятор)
- ✨ **Детекция дивергенции:** 4 метрики через ClassicDivergenceStrategy (универсальный)
- ✨ **Оценка волатильности:** 10 метрик через CombinedVolatilityStrategy
- ✨ **Volume анализ:** 4 метрики через StandardVolumeStrategy (универсальная корреляция)
- ✨ **Временные метрики:** 2 метрики (peak_time_ratio, trough_time_ratio)

**Документация:**
- **Универсальная Архитектура:** См. выше (🟢 v2.1 - стабильно)
- **Паттерн Стратегия:** См. [strategies.md](strategies.md) (🟢 стабильный API)
- **Руководство по Расширению:** См. [developer guide](../developer_guide/zone_detection_strategies.md) (пользовательские стратегии)

### Использование Аналитических Стратегий (v2.1)

🎯 **НОВЫЙ API:** Настройка swing, shape, divergence, volatility и volume стратегий с помощью `.with_strategies()`

**Простой swing анализ:**
```python
from bquant.analysis.zones import analyze_zones

result = (
    analyze_zones(df)
    .detect_zones('zero_crossing', indicator_col='macd_hist')
    .with_strategies(swing='find_peaks')  # ✅ NEW!
    .analyze(clustering=True)
    .build()
)

# Access swing metrics
zone = result.zones[0]
print(f"Peaks: {zone.features['num_peaks']}")
print(f"Troughs: {zone.features['num_troughs']}")
print(f"Drawdown: {zone.features['drawdown_from_peak']}")
```

**Множественные стратегии:**
```python
result = (
    analyze_zones(df)
    .detect_zones('zero_crossing', indicator_col='macd_hist')
    .with_strategies(
        swing='find_peaks',       # Swing detection
        shape='statistical',      # Shape analysis
        divergence='classic',     # Divergence detection
        volume='standard'         # Volume analysis
    )
    .analyze(clustering=True)
    .build()
)

# All features available in zone.features
zone = result.zones[0]
print(f"Swing: {zone.features.get('num_peaks', 0)} peaks")
print(f"Shape: {zone.features.get('skewness', 0)} skewness")
print(f"Divergence: {zone.features.get('has_classic_divergence', False)}")
print(f"Volume: {zone.features.get('volume_indicator_corr', 0)} correlation")
```

**Доступные стратегии:**
- **swing:** `'find_peaks'`, `'zigzag'`, `'pivot_points'`, или пользовательский экземпляр
- **shape:** `'statistical'` или пользовательский экземпляр (по умолчанию: 'statistical')
- **divergence:** `'classic'` или пользовательский экземпляр
- **volatility:** пользовательский экземпляр (по умолчанию: CombinedVolatilityStrategy)
- **volume:** `'standard'` или пользовательский экземпляр

**Работает с ЛЮБЫМ индикатором:**
```python
# RSI with swing analysis
result = (
    analyze_zones(df)
    .with_indicator('pandas_ta', 'rsi', period=14)
    .detect_zones('threshold', 
                 indicator_col='RSI_14',
                 upper_threshold=70, 
                 lower_threshold=30)
    .with_strategies(swing='pivot_points')  # ✅ Works!
    .build()
)

# Custom indicator with multiple strategies
df['MY_OSC'] = df['close'].diff(5) / df['close'].rolling(20).std()

result = (
    analyze_zones(df)
    .detect_zones('zero_crossing', indicator_col='MY_OSC')
    .with_strategies(
        swing='find_peaks',
        shape='statistical'
    )
    .build()
)
```

**Примечания:**
- Характеристики автоматически доступны в `zone.features` (не требуется ручное извлечение)
- Все стратегии опциональны (по умолчанию: None = пропустить)
- Обратно совместимо с существующим кодом

## Universal Pipeline API (v2.1)

### Основные компоненты

#### `analyze_zones(df) -> ZoneAnalysisBuilder`
Точка входа для Universal Pipeline. Возвращает fluent builder для настройки анализа.

#### `ZoneAnalysisBuilder`
Fluent interface для настройки анализа:
- `.with_indicator(source, name, **params)` - настройка индикатора
- `.detect_zones(strategy, **params)` - настройка детекции зон
- `.with_strategies(**strategies)` - настройка аналитических стратегий
- `.analyze(**options)` - настройка анализа
- `.with_cache(enable=True, ttl=3600)` - настройка кэширования
- `.build()` - запуск анализа

#### `ZoneAnalysisResult`
Результат анализа с полным набором данных:
- `zones: List[ZoneInfo]` - найденные зоны
- `statistics: Dict` - статистика анализа
- `hypothesis_tests: Optional[HypothesisTestSuite]` - статистические тесты
- `clustering: Optional[Dict]` - результаты кластеризации
- `sequence_analysis: Optional[Dict]` - анализ последовательностей
- **`visualize(mode, **kwargs)`** - встроенная визуализация зон

📊 **[Подробнее о визуализации →](../visualization/zones.md)** - режимы overview/detail/comparison/statistics, backend Plotly/Matplotlib

#### `ZoneInfo`
Модель зоны с полным контекстом:
- `zone_id: int` - уникальный идентификатор
- `type: str` - тип зоны ('bull'/'bear')
- `start_time: Timestamp` - время начала
- `end_time: Timestamp` - время окончания
- `features: Optional[Dict]` - извлеченные характеристики
- `indicator_context: Dict` - контекст индикатора

### Legacy API (Deprecated)

⚠️ **DEPRECATED:** Следующие компоненты устарели в v2.1:

- `Zone` class → `ZoneInfo` dataclass
- `find_support_resistance()` → Universal detection strategies
- `ZoneAnalyzer` → `UniversalZoneAnalyzer` через pipeline
- `extract_zone_features()` → автоматическое извлечение в pipeline

**Руководство по Миграции:**
```python
# Старый способ (Deprecated)
from bquant.analysis.zones import find_support_resistance, extract_zone_features
zones = find_support_resistance(data, window=20, min_touches=2)
features = extract_zone_features(zone_info)

# Новый способ (Universal Pipeline)
from bquant.analysis.zones import analyze_zones
result = (
    analyze_zones(data)
    .detect_zones('threshold', indicator_col='rsi', upper_threshold=70)
    .analyze(clustering=True)
    .build()
)
zones = result.zones
features = zones[0].features  # Автоматически извлечены
```

## Примеры

### Примеры Universal Pipeline

#### MACD Analysis
```python
from bquant.analysis.zones import analyze_zones
from bquant.data.samples import get_sample_data

data = get_sample_data('tv_xauusd_1h')

result = (
    analyze_zones(data)
    .with_indicator('custom', 'macd', fast_period=12, slow_period=26, signal_period=9)
    .detect_zones('zero_crossing', indicator_col='macd_hist')
    .with_strategies(swing='find_peaks', divergence='classic')
    .analyze(clustering=True, n_clusters=3)
    .build()
)

print(f"Найдено зон: {len(result.zones)}")
for zone in result.zones[:3]:
    if zone.features:
        print(f"Зона {zone.zone_id}: {zone.type}")
```

#### RSI Analysis
```python
result = (
    analyze_zones(data)
    .with_indicator('pandas_ta', 'rsi', length=14)
    .detect_zones('threshold', indicator_col='rsi', 
                  upper_threshold=70, lower_threshold=30)
    .with_strategies(swing='pivot_points', volatility='combined')
    .analyze(clustering=True)
    .build()
)
```

#### Пользовательский Индикатор
```python
# Создаем собственный индикатор
data['MY_OSC'] = data['close'].diff(5) / data['close'].rolling(20).std()

result = (
    analyze_zones(data)
    .detect_zones('zero_crossing', indicator_col='MY_OSC')
    .with_strategies(swing='find_peaks', shape='statistical')
    .analyze(clustering=True)
    .build()
)
```

### Legacy Примеры (Deprecated)

⚠️ **DEPRECATED:** Используйте Universal Pipeline вместо этих примеров:

```python
# Старый способ (Deprecated)
import pandas as pd

from bquant.analysis.zones import find_support_resistance

data = pd.DataFrame(
    {
        "open": [100, 101, 102, 103, 102, 101, 100, 99, 100, 101, 102, 101],
        "high": [101, 102, 103, 104, 103, 102, 101, 100, 101, 102, 103, 102],
        "low": [99, 100, 101, 102, 101, 100, 99, 98, 99, 100, 101, 100],
        "close": [100, 101, 102, 102, 101, 100, 100, 99, 100, 101, 102, 101],
        "volume": [1000, 1100, 1080, 1150, 1120, 1090, 1110, 1130, 1140, 1125, 1115, 1105],
    },
    index=pd.date_range("2024-01-01", periods=12, freq="H"),
)

zones = find_support_resistance(data, window=3, min_touches=1)

if zones:
    legacy_zone = zones[0]
    duration_hours = legacy_zone.duration.total_seconds() / 3600
    print(
        f"{legacy_zone.zone_type} zone from {legacy_zone.start_time:%Y-%m-%d %H:%M} "
        f"to {legacy_zone.end_time:%Y-%m-%d %H:%M} ({duration_hours:.0f} hours)"
    )
else:
    print("No support/resistance zones detected with the legacy API.")

# ZoneFeaturesAnalyzer можно использовать как и раньше, передавая словарь зоны.
# Пример:
# zfa = ZoneFeaturesAnalyzer()
# features = zfa.extract_zone_features({
#     "zone_id": legacy_zone.zone_id,
#     "type": legacy_zone.zone_type,
#     "data": data.loc[legacy_zone.start_time : legacy_zone.end_time],
#     "indicator_context": {"detection_strategy": "legacy_support_resistance"},
# })
```

## См. также

- **[Universal Pipeline](pipeline.md)** - Полная документация Universal Pipeline v2.1
- **[Zone Detection Strategies](strategies.md)** - Детальное описание 5 стратегий детекции
- **[Statistical Analysis](statistical.md)** - Тесты гипотез и статистический анализ
- **[Examples](../../examples/README.md)** - Готовые примеры использования
- **[Migration Guide](../../examples/README.md)** - Переход с legacy API
