bquant 0.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. bquant/__init__.py +31 -0
  2. bquant/analysis/__init__.py +297 -0
  3. bquant/analysis/candlestick/__init__.py +100 -0
  4. bquant/analysis/chart/__init__.py +98 -0
  5. bquant/analysis/statistical/__init__.py +414 -0
  6. bquant/analysis/statistical/hypothesis_testing.py +657 -0
  7. bquant/analysis/technical/__init__.py +98 -0
  8. bquant/analysis/timeseries/__init__.py +102 -0
  9. bquant/analysis/zones/__init__.py +547 -0
  10. bquant/analysis/zones/sequence_analysis.py +661 -0
  11. bquant/analysis/zones/zone_features.py +520 -0
  12. bquant/cli.py +160 -0
  13. bquant/core/__init__.py +112 -0
  14. bquant/core/cache.py +534 -0
  15. bquant/core/config.py +328 -0
  16. bquant/core/exceptions.py +351 -0
  17. bquant/core/logging_config.py +368 -0
  18. bquant/core/numpy_fix.py +99 -0
  19. bquant/core/performance.py +554 -0
  20. bquant/core/utils.py +327 -0
  21. bquant/data/__init__.py +85 -0
  22. bquant/data/loader.py +436 -0
  23. bquant/data/processor.py +644 -0
  24. bquant/data/samples/__init__.py +442 -0
  25. bquant/data/samples/datasets.py +246 -0
  26. bquant/data/samples/embedded/__init__.py +16 -0
  27. bquant/data/samples/embedded/mt_xauusd_m15.py +9018 -0
  28. bquant/data/samples/embedded/tv_xauusd_1h.py +17018 -0
  29. bquant/data/samples/utils.py +393 -0
  30. bquant/data/schemas.py +285 -0
  31. bquant/data/validator.py +498 -0
  32. bquant/indicators/__init__.py +115 -0
  33. bquant/indicators/base.py +487 -0
  34. bquant/indicators/calculators.py +404 -0
  35. bquant/indicators/library.py +514 -0
  36. bquant/indicators/loaders.py +413 -0
  37. bquant/indicators/macd.py +754 -0
  38. bquant/ml/__init__.py +19 -0
  39. bquant/visualization/__init__.py +316 -0
  40. bquant/visualization/charts.py +616 -0
  41. bquant/visualization/statistical.py +812 -0
  42. bquant/visualization/themes.py +599 -0
  43. bquant/visualization/zones.py +775 -0
  44. bquant-0.0.0.dist-info/METADATA +167 -0
  45. bquant-0.0.0.dist-info/RECORD +49 -0
  46. bquant-0.0.0.dist-info/WHEEL +5 -0
  47. bquant-0.0.0.dist-info/entry_points.txt +2 -0
  48. bquant-0.0.0.dist-info/licenses/LICENSE +21 -0
  49. bquant-0.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,775 @@
1
+ """
2
+ Модуль визуализации зон BQuant
3
+
4
+ Предоставляет инструменты для визуализации торговых зон:
5
+ - Отображение MACD зон на графиках
6
+ - Визуализация характеристик зон
7
+ - Интерактивные графики анализа зон
8
+ - Статистические диаграммы зон
9
+ """
10
+
11
+ import pandas as pd
12
+ import numpy as np
13
+ from typing import Dict, Any, List, Optional, Union, Tuple
14
+ from datetime import datetime
15
+ import warnings
16
+
17
+ from ..core.logging_config import get_logger
18
+ from ..core.exceptions import AnalysisError
19
+
20
+ # Получаем логгер для модуля
21
+ logger = get_logger(__name__)
22
+
23
+ # Проверка доступности библиотек визуализации
24
+ try:
25
+ import plotly.graph_objects as go
26
+ import plotly.subplots as sp
27
+ from plotly.subplots import make_subplots
28
+ import plotly.express as px
29
+ PLOTLY_AVAILABLE = True
30
+ except ImportError:
31
+ PLOTLY_AVAILABLE = False
32
+ logger.warning("Plotly not available - zones visualization will be limited")
33
+
34
+ try:
35
+ import matplotlib.pyplot as plt
36
+ import matplotlib.patches as patches
37
+ import seaborn as sns
38
+ MATPLOTLIB_AVAILABLE = True
39
+ except ImportError:
40
+ MATPLOTLIB_AVAILABLE = False
41
+ logger.warning("Matplotlib not available - zones visualization will be limited")
42
+
43
+
44
+ class ZoneChartBuilder:
45
+ """
46
+ Базовый класс для построения графиков зон.
47
+ """
48
+
49
+ def __init__(self, backend: str = 'plotly'):
50
+ """
51
+ Инициализация построителя графиков зон.
52
+
53
+ Args:
54
+ backend: Библиотека для построения ('plotly' или 'matplotlib')
55
+ """
56
+ self.backend = backend
57
+ self.logger = get_logger(f"{__name__}.ZoneChartBuilder")
58
+
59
+ # Проверяем доступность выбранной библиотеки
60
+ if backend == 'plotly' and not PLOTLY_AVAILABLE:
61
+ if MATPLOTLIB_AVAILABLE:
62
+ self.backend = 'matplotlib'
63
+ self.logger.warning("Plotly not available, switching to matplotlib")
64
+ else:
65
+ raise AnalysisError("No visualization libraries available")
66
+
67
+ elif backend == 'matplotlib' and not MATPLOTLIB_AVAILABLE:
68
+ if PLOTLY_AVAILABLE:
69
+ self.backend = 'plotly'
70
+ self.logger.warning("Matplotlib not available, switching to plotly")
71
+ else:
72
+ raise AnalysisError("No visualization libraries available")
73
+
74
+ # Цветовая схема для зон
75
+ self.zone_colors = {
76
+ 'bull': {'fill': 'rgba(0, 255, 136, 0.3)', 'line': '#00ff88'},
77
+ 'bear': {'fill': 'rgba(255, 68, 68, 0.3)', 'line': '#ff4444'},
78
+ 'support': {'fill': 'rgba(0, 136, 255, 0.3)', 'line': '#0088ff'},
79
+ 'resistance': {'fill': 'rgba(255, 136, 0, 0.3)', 'line': '#ff8800'}
80
+ }
81
+
82
+ self.logger.info(f"Zone chart builder initialized with {self.backend} backend")
83
+
84
+ def _prepare_zone_data(self, zones_data: Union[List[Dict], pd.DataFrame]) -> List[Dict]:
85
+ """
86
+ Подготовка данных зон для визуализации.
87
+
88
+ Args:
89
+ zones_data: Данные зон
90
+
91
+ Returns:
92
+ Список словарей с данными зон
93
+ """
94
+ if isinstance(zones_data, pd.DataFrame):
95
+ return zones_data.to_dict('records')
96
+ elif isinstance(zones_data, list):
97
+ return zones_data
98
+ else:
99
+ raise ValueError("zones_data must be DataFrame or list of dicts")
100
+
101
+
102
+ class ZoneVisualizer(ZoneChartBuilder):
103
+ """
104
+ Класс для визуализации торговых зон.
105
+ """
106
+
107
+ def __init__(self, backend: str = 'plotly', **kwargs):
108
+ """
109
+ Инициализация визуализатора зон.
110
+
111
+ Args:
112
+ backend: Библиотека для построения
113
+ **kwargs: Дополнительные параметры
114
+ """
115
+ super().__init__(backend)
116
+
117
+ # Настройки по умолчанию
118
+ self.default_config = {
119
+ 'width': kwargs.get('width', 1200),
120
+ 'height': kwargs.get('height', 800),
121
+ 'show_zone_labels': kwargs.get('show_zone_labels', True),
122
+ 'show_zone_stats': kwargs.get('show_zone_stats', True),
123
+ 'opacity': kwargs.get('opacity', 0.3)
124
+ }
125
+
126
+ def plot_zones_on_price_chart(self, price_data: pd.DataFrame,
127
+ zones_data: Union[List[Dict], pd.DataFrame],
128
+ title: str = "Price Chart with Zones",
129
+ **kwargs) -> Union[go.Figure, plt.Figure]:
130
+ """
131
+ Отображение зон на графике цен.
132
+
133
+ Args:
134
+ price_data: DataFrame с данными цен (OHLCV)
135
+ zones_data: Данные зон
136
+ title: Заголовок графика
137
+ **kwargs: Дополнительные параметры
138
+
139
+ Returns:
140
+ Объект графика
141
+ """
142
+ zones = self._prepare_zone_data(zones_data)
143
+
144
+ if self.backend == 'plotly':
145
+ return self._create_plotly_zones_on_price(price_data, zones, title, **kwargs)
146
+ else:
147
+ return self._create_matplotlib_zones_on_price(price_data, zones, title, **kwargs)
148
+
149
+ def plot_macd_zones(self, macd_data: pd.DataFrame,
150
+ zones_data: Union[List[Dict], pd.DataFrame],
151
+ title: str = "MACD with Zones",
152
+ **kwargs) -> Union[go.Figure, plt.Figure]:
153
+ """
154
+ Отображение зон на графике MACD.
155
+
156
+ Args:
157
+ macd_data: DataFrame с данными MACD
158
+ zones_data: Данные зон
159
+ title: Заголовок графика
160
+ **kwargs: Дополнительные параметры
161
+
162
+ Returns:
163
+ Объект графика
164
+ """
165
+ zones = self._prepare_zone_data(zones_data)
166
+
167
+ if self.backend == 'plotly':
168
+ return self._create_plotly_macd_zones(macd_data, zones, title, **kwargs)
169
+ else:
170
+ return self._create_matplotlib_macd_zones(macd_data, zones, title, **kwargs)
171
+
172
+ def plot_zones_analysis(self, zones_data: Union[List[Dict], pd.DataFrame],
173
+ analysis_data: Dict[str, Any] = None,
174
+ title: str = "Zones Analysis",
175
+ **kwargs) -> Union[go.Figure, plt.Figure]:
176
+ """
177
+ Визуализация анализа зон.
178
+
179
+ Args:
180
+ zones_data: Данные зон
181
+ analysis_data: Результаты анализа зон (опционально)
182
+ title: Заголовок графика
183
+ **kwargs: Дополнительные параметры
184
+
185
+ Returns:
186
+ Объект графика
187
+ """
188
+ zones = self._prepare_zone_data(zones_data)
189
+
190
+ if self.backend == 'plotly':
191
+ return self._create_plotly_zones_analysis(zones, analysis_data, title, **kwargs)
192
+ else:
193
+ return self._create_matplotlib_zones_analysis(zones, analysis_data, title, **kwargs)
194
+
195
+ def plot_zones_distribution(self, zones_data: Union[List[Dict], pd.DataFrame],
196
+ feature: str = 'duration',
197
+ title: str = "Zones Distribution",
198
+ **kwargs) -> Union[go.Figure, plt.Figure]:
199
+ """
200
+ Визуализация распределения характеристик зон.
201
+
202
+ Args:
203
+ zones_data: Данные зон
204
+ feature: Характеристика для анализа
205
+ title: Заголовок графика
206
+ **kwargs: Дополнительные параметры
207
+
208
+ Returns:
209
+ Объект графика
210
+ """
211
+ zones = self._prepare_zone_data(zones_data)
212
+
213
+ if self.backend == 'plotly':
214
+ return self._create_plotly_zones_distribution(zones, feature, title, **kwargs)
215
+ else:
216
+ return self._create_matplotlib_zones_distribution(zones, feature, title, **kwargs)
217
+
218
+ def plot_zones_correlation(self, zones_data: Union[List[Dict], pd.DataFrame],
219
+ title: str = "Zones Characteristics Correlation",
220
+ **kwargs) -> Union[go.Figure, plt.Figure]:
221
+ """
222
+ Визуализация корреляций характеристик зон.
223
+
224
+ Args:
225
+ zones_data: Данные зон
226
+ title: Заголовок графика
227
+ **kwargs: Дополнительные параметры
228
+
229
+ Returns:
230
+ Объект графика
231
+ """
232
+ zones_df = pd.DataFrame(self._prepare_zone_data(zones_data))
233
+
234
+ if self.backend == 'plotly':
235
+ return self._create_plotly_zones_correlation(zones_df, title, **kwargs)
236
+ else:
237
+ return self._create_matplotlib_zones_correlation(zones_df, title, **kwargs)
238
+
239
+ # Plotly реализации
240
+ def _create_plotly_zones_on_price(self, price_data: pd.DataFrame,
241
+ zones: List[Dict], title: str,
242
+ **kwargs) -> go.Figure:
243
+ """Создание графика цен с зонами с помощью Plotly."""
244
+ # Основной график свечей
245
+ fig = go.Figure()
246
+
247
+ # Добавляем свечной график
248
+ fig.add_trace(go.Candlestick(
249
+ x=price_data.index,
250
+ open=price_data['open'],
251
+ high=price_data['high'],
252
+ low=price_data['low'],
253
+ close=price_data['close'],
254
+ name='Price',
255
+ increasing_line_color='#00ff88',
256
+ decreasing_line_color='#ff4444'
257
+ ))
258
+
259
+ # Добавляем зоны
260
+ for i, zone in enumerate(zones):
261
+ if 'start_time' in zone and 'end_time' in zone:
262
+ zone_type = zone.get('type', 'bull')
263
+ color_config = self.zone_colors.get(zone_type, self.zone_colors['bull'])
264
+
265
+ # Определяем границы зоны по цене
266
+ if 'start_price' in zone and 'end_price' in zone:
267
+ y0 = min(zone['start_price'], zone['end_price'])
268
+ y1 = max(zone['start_price'], zone['end_price'])
269
+ else:
270
+ # Если нет ценовых границ, используем весь диапазон
271
+ y0 = price_data['low'].min()
272
+ y1 = price_data['high'].max()
273
+
274
+ # Добавляем прямоугольник зоны
275
+ fig.add_shape(
276
+ type="rect",
277
+ x0=zone['start_time'],
278
+ y0=y0,
279
+ x1=zone['end_time'],
280
+ y1=y1,
281
+ fillcolor=color_config['fill'],
282
+ line=dict(color=color_config['line'], width=1),
283
+ layer="below"
284
+ )
285
+
286
+ # Добавляем подпись зоны
287
+ if self.default_config['show_zone_labels']:
288
+ fig.add_annotation(
289
+ x=zone['start_time'],
290
+ y=y1,
291
+ text=f"{zone_type.title()} Zone {i+1}",
292
+ showarrow=False,
293
+ font=dict(size=10),
294
+ bgcolor="white",
295
+ opacity=0.8
296
+ )
297
+
298
+ fig.update_layout(
299
+ title=title,
300
+ width=self.default_config['width'],
301
+ height=self.default_config['height'],
302
+ xaxis_rangeslider_visible=False,
303
+ template='plotly_white'
304
+ )
305
+
306
+ return fig
307
+
308
+ def _create_plotly_macd_zones(self, macd_data: pd.DataFrame,
309
+ zones: List[Dict], title: str,
310
+ **kwargs) -> go.Figure:
311
+ """Создание графика MACD с зонами с помощью Plotly."""
312
+ fig = make_subplots(
313
+ rows=2, cols=1,
314
+ shared_xaxes=True,
315
+ vertical_spacing=0.05,
316
+ row_heights=[0.6, 0.4],
317
+ subplot_titles=['MACD with Zones', 'Histogram']
318
+ )
319
+
320
+ # MACD линии
321
+ fig.add_trace(go.Scatter(
322
+ x=macd_data.index,
323
+ y=macd_data['macd'],
324
+ mode='lines',
325
+ name='MACD',
326
+ line=dict(color='blue', width=2)
327
+ ), row=1, col=1)
328
+
329
+ fig.add_trace(go.Scatter(
330
+ x=macd_data.index,
331
+ y=macd_data['macd_signal'],
332
+ mode='lines',
333
+ name='Signal',
334
+ line=dict(color='red', width=2)
335
+ ), row=1, col=1)
336
+
337
+ # Гистограмма
338
+ colors = ['green' if val >= 0 else 'red' for val in macd_data['macd_hist']]
339
+ fig.add_trace(go.Bar(
340
+ x=macd_data.index,
341
+ y=macd_data['macd_hist'],
342
+ name='Histogram',
343
+ marker_color=colors,
344
+ opacity=0.7
345
+ ), row=2, col=1)
346
+
347
+ # Добавляем зоны
348
+ for i, zone in enumerate(zones):
349
+ if 'start_time' in zone and 'end_time' in zone:
350
+ zone_type = zone.get('type', 'bull')
351
+ color = 'lightblue' if zone_type == 'bull' else 'lightpink'
352
+
353
+ # Добавляем зону на график MACD
354
+ fig.add_vrect(
355
+ x0=zone['start_time'],
356
+ x1=zone['end_time'],
357
+ fillcolor=color,
358
+ opacity=self.default_config['opacity'],
359
+ layer="below",
360
+ line_width=0,
361
+ row=1, col=1
362
+ )
363
+
364
+ # Добавляем зону на гистограмму
365
+ fig.add_vrect(
366
+ x0=zone['start_time'],
367
+ x1=zone['end_time'],
368
+ fillcolor=color,
369
+ opacity=self.default_config['opacity'],
370
+ layer="below",
371
+ line_width=0,
372
+ row=2, col=1
373
+ )
374
+
375
+ fig.update_layout(
376
+ title=title,
377
+ width=self.default_config['width'],
378
+ height=self.default_config['height'],
379
+ template='plotly_white',
380
+ showlegend=True
381
+ )
382
+
383
+ return fig
384
+
385
+ def _create_plotly_zones_analysis(self, zones: List[Dict],
386
+ analysis_data: Dict[str, Any],
387
+ title: str, **kwargs) -> go.Figure:
388
+ """Создание графика анализа зон с помощью Plotly."""
389
+ # Создаем DataFrame из зон
390
+ zones_df = pd.DataFrame(zones)
391
+
392
+ if zones_df.empty:
393
+ # Создаем пустой график с сообщением
394
+ fig = go.Figure()
395
+ fig.add_annotation(
396
+ text="No zones data available",
397
+ xref="paper", yref="paper",
398
+ x=0.5, y=0.5, xanchor='center', yanchor='middle'
399
+ )
400
+ fig.update_layout(title=title)
401
+ return fig
402
+
403
+ # Создаем подграфики для различных аспектов анализа
404
+ fig = make_subplots(
405
+ rows=2, cols=2,
406
+ subplot_titles=['Zones by Type', 'Duration Distribution',
407
+ 'Return Distribution', 'Zone Timeline'],
408
+ specs=[[{"type": "pie"}, {"type": "histogram"}],
409
+ [{"type": "histogram"}, {"type": "scatter"}]]
410
+ )
411
+
412
+ # 1. Распределение по типам зон
413
+ if 'zone_type' in zones_df.columns:
414
+ type_counts = zones_df['zone_type'].value_counts()
415
+ fig.add_trace(go.Pie(
416
+ labels=type_counts.index,
417
+ values=type_counts.values,
418
+ name="Zone Types"
419
+ ), row=1, col=1)
420
+
421
+ # 2. Распределение длительности
422
+ if 'duration' in zones_df.columns:
423
+ fig.add_trace(go.Histogram(
424
+ x=zones_df['duration'],
425
+ name="Duration",
426
+ nbinsx=20
427
+ ), row=1, col=2)
428
+
429
+ # 3. Распределение доходности
430
+ if 'price_return' in zones_df.columns:
431
+ fig.add_trace(go.Histogram(
432
+ x=zones_df['price_return'],
433
+ name="Returns",
434
+ nbinsx=20
435
+ ), row=2, col=1)
436
+
437
+ # 4. Временная линия зон
438
+ if 'start_time' in zones_df.columns and 'duration' in zones_df.columns:
439
+ fig.add_trace(go.Scatter(
440
+ x=zones_df['start_time'] if 'start_time' in zones_df.columns else range(len(zones_df)),
441
+ y=zones_df['duration'],
442
+ mode='markers',
443
+ name="Zone Timeline",
444
+ marker=dict(
445
+ size=8,
446
+ color=zones_df['zone_type'].map({'bull': 'blue', 'bear': 'red'}) if 'zone_type' in zones_df.columns else 'blue'
447
+ )
448
+ ), row=2, col=2)
449
+
450
+ fig.update_layout(
451
+ title=title,
452
+ width=self.default_config['width'],
453
+ height=self.default_config['height'],
454
+ template='plotly_white'
455
+ )
456
+
457
+ return fig
458
+
459
+ def _create_plotly_zones_distribution(self, zones: List[Dict],
460
+ feature: str, title: str,
461
+ **kwargs) -> go.Figure:
462
+ """Создание графика распределения характеристик зон с помощью Plotly."""
463
+ zones_df = pd.DataFrame(zones)
464
+
465
+ if zones_df.empty or feature not in zones_df.columns:
466
+ fig = go.Figure()
467
+ fig.add_annotation(
468
+ text=f"No data available for feature: {feature}",
469
+ xref="paper", yref="paper",
470
+ x=0.5, y=0.5, xanchor='center', yanchor='middle'
471
+ )
472
+ fig.update_layout(title=title)
473
+ return fig
474
+
475
+ # Создаем подграфики
476
+ fig = make_subplots(
477
+ rows=1, cols=2,
478
+ subplot_titles=[f'{feature.title()} Distribution', f'{feature.title()} by Zone Type']
479
+ )
480
+
481
+ # Общее распределение
482
+ fig.add_trace(go.Histogram(
483
+ x=zones_df[feature],
484
+ name=f"All {feature}",
485
+ nbinsx=20,
486
+ opacity=0.7
487
+ ), row=1, col=1)
488
+
489
+ # Распределение по типам зон
490
+ if 'zone_type' in zones_df.columns:
491
+ for zone_type in zones_df['zone_type'].unique():
492
+ type_data = zones_df[zones_df['zone_type'] == zone_type][feature]
493
+ fig.add_trace(go.Histogram(
494
+ x=type_data,
495
+ name=f"{zone_type.title()} {feature}",
496
+ nbinsx=15,
497
+ opacity=0.7
498
+ ), row=1, col=2)
499
+
500
+ fig.update_layout(
501
+ title=title,
502
+ width=self.default_config['width'],
503
+ height=self.default_config['height'],
504
+ template='plotly_white',
505
+ barmode='overlay'
506
+ )
507
+
508
+ return fig
509
+
510
+ def _create_plotly_zones_correlation(self, zones_df: pd.DataFrame,
511
+ title: str, **kwargs) -> go.Figure:
512
+ """Создание матрицы корреляций характеристик зон с помощью Plotly."""
513
+ # Выбираем только числовые колонки
514
+ numeric_columns = zones_df.select_dtypes(include=[np.number]).columns
515
+
516
+ if len(numeric_columns) < 2:
517
+ fig = go.Figure()
518
+ fig.add_annotation(
519
+ text="Insufficient numeric data for correlation analysis",
520
+ xref="paper", yref="paper",
521
+ x=0.5, y=0.5, xanchor='center', yanchor='middle'
522
+ )
523
+ fig.update_layout(title=title)
524
+ return fig
525
+
526
+ # Вычисляем корреляции
527
+ corr_matrix = zones_df[numeric_columns].corr()
528
+
529
+ # Создаем heatmap
530
+ fig = go.Figure(data=go.Heatmap(
531
+ z=corr_matrix.values,
532
+ x=corr_matrix.columns,
533
+ y=corr_matrix.columns,
534
+ colorscale='RdBu',
535
+ zmin=-1, zmax=1,
536
+ text=np.round(corr_matrix.values, 2),
537
+ texttemplate="%{text}",
538
+ textfont={"size": 10},
539
+ hoverongaps=False
540
+ ))
541
+
542
+ fig.update_layout(
543
+ title=title,
544
+ width=self.default_config['width'],
545
+ height=self.default_config['height'],
546
+ template='plotly_white'
547
+ )
548
+
549
+ return fig
550
+
551
+ # Matplotlib реализации (упрощенные)
552
+ def _create_matplotlib_zones_on_price(self, price_data: pd.DataFrame,
553
+ zones: List[Dict], title: str,
554
+ **kwargs) -> plt.Figure:
555
+ """Создание графика цен с зонами с помощью Matplotlib."""
556
+ fig, ax = plt.subplots(figsize=(12, 6))
557
+
558
+ # Простой линейный график цен
559
+ ax.plot(price_data.index, price_data['close'], label='Close Price', linewidth=1)
560
+
561
+ # Добавляем зоны как вертикальные полосы
562
+ for i, zone in enumerate(zones):
563
+ if 'start_time' in zone and 'end_time' in zone:
564
+ zone_type = zone.get('type', 'bull')
565
+ color = 'lightblue' if zone_type == 'bull' else 'lightpink'
566
+
567
+ ax.axvspan(zone['start_time'], zone['end_time'],
568
+ alpha=self.default_config['opacity'],
569
+ color=color,
570
+ label=f"{zone_type.title()} Zone" if i == 0 else "")
571
+
572
+ ax.set_title(title)
573
+ ax.legend()
574
+ ax.grid(True, alpha=0.3)
575
+
576
+ return fig
577
+
578
+ def _create_matplotlib_macd_zones(self, macd_data: pd.DataFrame,
579
+ zones: List[Dict], title: str,
580
+ **kwargs) -> plt.Figure:
581
+ """Создание графика MACD с зонами с помощью Matplotlib."""
582
+ fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8), sharex=True)
583
+
584
+ # MACD
585
+ ax1.plot(macd_data.index, macd_data['macd'], label='MACD', color='blue')
586
+ ax1.plot(macd_data.index, macd_data['macd_signal'], label='Signal', color='red')
587
+ ax1.set_title('MACD with Zones')
588
+ ax1.legend()
589
+ ax1.grid(True, alpha=0.3)
590
+
591
+ # Гистограмма
592
+ colors = ['green' if val >= 0 else 'red' for val in macd_data['macd_hist']]
593
+ ax2.bar(macd_data.index, macd_data['macd_hist'], color=colors, alpha=0.7)
594
+ ax2.set_title('Histogram')
595
+ ax2.grid(True, alpha=0.3)
596
+
597
+ # Добавляем зоны
598
+ for zone in zones:
599
+ if 'start_time' in zone and 'end_time' in zone:
600
+ zone_type = zone.get('type', 'bull')
601
+ color = 'lightblue' if zone_type == 'bull' else 'lightpink'
602
+
603
+ ax1.axvspan(zone['start_time'], zone['end_time'],
604
+ alpha=self.default_config['opacity'], color=color)
605
+ ax2.axvspan(zone['start_time'], zone['end_time'],
606
+ alpha=self.default_config['opacity'], color=color)
607
+
608
+ plt.tight_layout()
609
+ return fig
610
+
611
+ def _create_matplotlib_zones_analysis(self, zones: List[Dict],
612
+ analysis_data: Dict[str, Any],
613
+ title: str, **kwargs) -> plt.Figure:
614
+ """Создание графика анализа зон с помощью Matplotlib."""
615
+ zones_df = pd.DataFrame(zones)
616
+
617
+ fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(12, 8))
618
+
619
+ # 1. Распределение по типам
620
+ if 'zone_type' in zones_df.columns:
621
+ type_counts = zones_df['zone_type'].value_counts()
622
+ ax1.pie(type_counts.values, labels=type_counts.index, autopct='%1.1f%%')
623
+ ax1.set_title('Zones by Type')
624
+
625
+ # 2. Распределение длительности
626
+ if 'duration' in zones_df.columns:
627
+ ax2.hist(zones_df['duration'], bins=20, alpha=0.7)
628
+ ax2.set_title('Duration Distribution')
629
+ ax2.set_xlabel('Duration')
630
+
631
+ # 3. Распределение доходности
632
+ if 'price_return' in zones_df.columns:
633
+ ax3.hist(zones_df['price_return'], bins=20, alpha=0.7)
634
+ ax3.set_title('Return Distribution')
635
+ ax3.set_xlabel('Return')
636
+
637
+ # 4. Scatter plot длительность vs доходность
638
+ if 'duration' in zones_df.columns and 'price_return' in zones_df.columns:
639
+ if 'zone_type' in zones_df.columns:
640
+ for zone_type in zones_df['zone_type'].unique():
641
+ type_data = zones_df[zones_df['zone_type'] == zone_type]
642
+ ax4.scatter(type_data['duration'], type_data['price_return'],
643
+ label=zone_type.title(), alpha=0.7)
644
+ ax4.legend()
645
+ else:
646
+ ax4.scatter(zones_df['duration'], zones_df['price_return'], alpha=0.7)
647
+ ax4.set_xlabel('Duration')
648
+ ax4.set_ylabel('Return')
649
+ ax4.set_title('Duration vs Return')
650
+
651
+ plt.suptitle(title)
652
+ plt.tight_layout()
653
+ return fig
654
+
655
+ def _create_matplotlib_zones_distribution(self, zones: List[Dict],
656
+ feature: str, title: str,
657
+ **kwargs) -> plt.Figure:
658
+ """Создание графика распределения с помощью Matplotlib."""
659
+ zones_df = pd.DataFrame(zones)
660
+
661
+ fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
662
+
663
+ # Общее распределение
664
+ if feature in zones_df.columns:
665
+ ax1.hist(zones_df[feature], bins=20, alpha=0.7)
666
+ ax1.set_title(f'{feature.title()} Distribution')
667
+ ax1.set_xlabel(feature.title())
668
+
669
+ # По типам зон
670
+ if 'zone_type' in zones_df.columns and feature in zones_df.columns:
671
+ for zone_type in zones_df['zone_type'].unique():
672
+ type_data = zones_df[zones_df['zone_type'] == zone_type][feature]
673
+ ax2.hist(type_data, bins=15, alpha=0.7, label=zone_type.title())
674
+ ax2.set_title(f'{feature.title()} by Zone Type')
675
+ ax2.set_xlabel(feature.title())
676
+ ax2.legend()
677
+
678
+ plt.suptitle(title)
679
+ plt.tight_layout()
680
+ return fig
681
+
682
+ def _create_matplotlib_zones_correlation(self, zones_df: pd.DataFrame,
683
+ title: str, **kwargs) -> plt.Figure:
684
+ """Создание матрицы корреляций с помощью Matplotlib."""
685
+ # Выбираем только числовые колонки
686
+ numeric_columns = zones_df.select_dtypes(include=[np.number]).columns
687
+
688
+ if len(numeric_columns) < 2:
689
+ fig, ax = plt.subplots(figsize=(8, 6))
690
+ ax.text(0.5, 0.5, 'Insufficient numeric data for correlation analysis',
691
+ ha='center', va='center')
692
+ ax.set_title(title)
693
+ return fig
694
+
695
+ # Вычисляем корреляции
696
+ corr_matrix = zones_df[numeric_columns].corr()
697
+
698
+ # Создаем heatmap
699
+ fig, ax = plt.subplots(figsize=(10, 8))
700
+ im = ax.imshow(corr_matrix.values, cmap='RdBu', vmin=-1, vmax=1)
701
+
702
+ # Настраиваем оси
703
+ ax.set_xticks(range(len(corr_matrix.columns)))
704
+ ax.set_yticks(range(len(corr_matrix.columns)))
705
+ ax.set_xticklabels(corr_matrix.columns, rotation=45)
706
+ ax.set_yticklabels(corr_matrix.columns)
707
+
708
+ # Добавляем значения
709
+ for i in range(len(corr_matrix.columns)):
710
+ for j in range(len(corr_matrix.columns)):
711
+ text = ax.text(j, i, f'{corr_matrix.iloc[i, j]:.2f}',
712
+ ha="center", va="center", color="black")
713
+
714
+ fig.colorbar(im)
715
+ ax.set_title(title)
716
+ plt.tight_layout()
717
+ return fig
718
+
719
+
720
+ # Удобные функции
721
+ def plot_zones_on_chart(price_data: pd.DataFrame, zones_data, **kwargs):
722
+ """
723
+ Быстрое отображение зон на графике цен.
724
+
725
+ Args:
726
+ price_data: DataFrame с данными цен
727
+ zones_data: Данные зон
728
+ **kwargs: Дополнительные параметры
729
+
730
+ Returns:
731
+ Объект графика
732
+ """
733
+ visualizer = ZoneVisualizer()
734
+ return visualizer.plot_zones_on_price_chart(price_data, zones_data, **kwargs)
735
+
736
+
737
+ def plot_macd_zones_chart(macd_data: pd.DataFrame, zones_data, **kwargs):
738
+ """
739
+ Быстрое отображение зон на графике MACD.
740
+
741
+ Args:
742
+ macd_data: DataFrame с данными MACD
743
+ zones_data: Данные зон
744
+ **kwargs: Дополнительные параметры
745
+
746
+ Returns:
747
+ Объект графика
748
+ """
749
+ visualizer = ZoneVisualizer()
750
+ return visualizer.plot_macd_zones(macd_data, zones_data, **kwargs)
751
+
752
+
753
+ def analyze_zones_visually(zones_data, **kwargs):
754
+ """
755
+ Быстрый визуальный анализ зон.
756
+
757
+ Args:
758
+ zones_data: Данные зон
759
+ **kwargs: Дополнительные параметры
760
+
761
+ Returns:
762
+ Объект графика
763
+ """
764
+ visualizer = ZoneVisualizer()
765
+ return visualizer.plot_zones_analysis(zones_data, **kwargs)
766
+
767
+
768
+ # Экспорт
769
+ __all__ = [
770
+ 'ZoneChartBuilder',
771
+ 'ZoneVisualizer',
772
+ 'plot_zones_on_chart',
773
+ 'plot_macd_zones_chart',
774
+ 'analyze_zones_visually'
775
+ ]