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.
- bquant/__init__.py +31 -0
- bquant/analysis/__init__.py +297 -0
- bquant/analysis/candlestick/__init__.py +100 -0
- bquant/analysis/chart/__init__.py +98 -0
- bquant/analysis/statistical/__init__.py +414 -0
- bquant/analysis/statistical/hypothesis_testing.py +657 -0
- bquant/analysis/technical/__init__.py +98 -0
- bquant/analysis/timeseries/__init__.py +102 -0
- bquant/analysis/zones/__init__.py +547 -0
- bquant/analysis/zones/sequence_analysis.py +661 -0
- bquant/analysis/zones/zone_features.py +520 -0
- bquant/cli.py +160 -0
- bquant/core/__init__.py +112 -0
- bquant/core/cache.py +534 -0
- bquant/core/config.py +328 -0
- bquant/core/exceptions.py +351 -0
- bquant/core/logging_config.py +368 -0
- bquant/core/numpy_fix.py +99 -0
- bquant/core/performance.py +554 -0
- bquant/core/utils.py +327 -0
- bquant/data/__init__.py +85 -0
- bquant/data/loader.py +436 -0
- bquant/data/processor.py +644 -0
- bquant/data/samples/__init__.py +442 -0
- bquant/data/samples/datasets.py +246 -0
- bquant/data/samples/embedded/__init__.py +16 -0
- bquant/data/samples/embedded/mt_xauusd_m15.py +9018 -0
- bquant/data/samples/embedded/tv_xauusd_1h.py +17018 -0
- bquant/data/samples/utils.py +393 -0
- bquant/data/schemas.py +285 -0
- bquant/data/validator.py +498 -0
- bquant/indicators/__init__.py +115 -0
- bquant/indicators/base.py +487 -0
- bquant/indicators/calculators.py +404 -0
- bquant/indicators/library.py +514 -0
- bquant/indicators/loaders.py +413 -0
- bquant/indicators/macd.py +754 -0
- bquant/ml/__init__.py +19 -0
- bquant/visualization/__init__.py +316 -0
- bquant/visualization/charts.py +616 -0
- bquant/visualization/statistical.py +812 -0
- bquant/visualization/themes.py +599 -0
- bquant/visualization/zones.py +775 -0
- bquant-0.0.0.dist-info/METADATA +167 -0
- bquant-0.0.0.dist-info/RECORD +49 -0
- bquant-0.0.0.dist-info/WHEEL +5 -0
- bquant-0.0.0.dist-info/entry_points.txt +2 -0
- bquant-0.0.0.dist-info/licenses/LICENSE +21 -0
- bquant-0.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
"""
|
|
2
|
+
High-level calculators and utilities for BQuant indicators
|
|
3
|
+
|
|
4
|
+
This module provides convenient functions for calculating indicators and managing indicator workflows.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import pandas as pd
|
|
8
|
+
import numpy as np
|
|
9
|
+
from typing import Dict, Any, Optional, List, Union, Tuple
|
|
10
|
+
from datetime import datetime
|
|
11
|
+
|
|
12
|
+
from .base import IndicatorFactory, IndicatorResult, BaseIndicator
|
|
13
|
+
from .library import register_builtin_indicators
|
|
14
|
+
from .loaders import LibraryManager
|
|
15
|
+
from ..core.exceptions import IndicatorCalculationError
|
|
16
|
+
from ..core.logging_config import get_logger
|
|
17
|
+
|
|
18
|
+
logger = get_logger(__name__)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class IndicatorCalculator:
|
|
22
|
+
"""
|
|
23
|
+
High-level calculator for technical indicators.
|
|
24
|
+
|
|
25
|
+
Provides convenient methods for calculating multiple indicators and managing results.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def __init__(self, data: pd.DataFrame, auto_load_libraries: bool = True):
|
|
29
|
+
"""
|
|
30
|
+
Initialize calculator with price data.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
data: DataFrame with OHLCV price data
|
|
34
|
+
auto_load_libraries: Whether to automatically load external libraries
|
|
35
|
+
"""
|
|
36
|
+
self.data = data.copy()
|
|
37
|
+
self.results = {}
|
|
38
|
+
self.logger = get_logger(f"{__name__}.IndicatorCalculator")
|
|
39
|
+
|
|
40
|
+
# Автоматическая загрузка библиотек
|
|
41
|
+
if auto_load_libraries:
|
|
42
|
+
self._load_all_indicators()
|
|
43
|
+
|
|
44
|
+
def _load_all_indicators(self):
|
|
45
|
+
"""Load all available indicators."""
|
|
46
|
+
try:
|
|
47
|
+
# Загружаем встроенные индикаторы
|
|
48
|
+
builtin_count = register_builtin_indicators()
|
|
49
|
+
self.logger.info(f"Loaded {builtin_count} builtin indicators")
|
|
50
|
+
|
|
51
|
+
# Загружаем внешние библиотеки
|
|
52
|
+
library_results = LibraryManager.load_all_libraries()
|
|
53
|
+
total_library = sum(library_results.values())
|
|
54
|
+
self.logger.info(f"Loaded {total_library} external indicators")
|
|
55
|
+
|
|
56
|
+
except Exception as e:
|
|
57
|
+
self.logger.warning(f"Failed to load some indicators: {e}")
|
|
58
|
+
|
|
59
|
+
def calculate(self, indicator_name: str, **kwargs) -> IndicatorResult:
|
|
60
|
+
"""
|
|
61
|
+
Calculate single indicator.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
indicator_name: Name of the indicator
|
|
65
|
+
**kwargs: Indicator parameters
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
IndicatorResult with calculation results
|
|
69
|
+
"""
|
|
70
|
+
try:
|
|
71
|
+
self.logger.info(f"Calculating indicator: {indicator_name}")
|
|
72
|
+
|
|
73
|
+
# Создаем индикатор через фабрику
|
|
74
|
+
indicator = IndicatorFactory.create_indicator(indicator_name, self.data, **kwargs)
|
|
75
|
+
|
|
76
|
+
# Вычисляем результат
|
|
77
|
+
result = indicator.calculate_with_cache(self.data, **kwargs)
|
|
78
|
+
|
|
79
|
+
# Сохраняем результат
|
|
80
|
+
self.results[indicator_name] = result
|
|
81
|
+
|
|
82
|
+
self.logger.info(f"Successfully calculated {indicator_name}")
|
|
83
|
+
return result
|
|
84
|
+
|
|
85
|
+
except Exception as e:
|
|
86
|
+
self.logger.error(f"Failed to calculate {indicator_name}: {e}")
|
|
87
|
+
raise IndicatorCalculationError(
|
|
88
|
+
f"Calculation failed for {indicator_name}: {e}",
|
|
89
|
+
{'indicator': indicator_name, 'parameters': kwargs}
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
def calculate_multiple(self, indicators: Dict[str, Dict[str, Any]]) -> Dict[str, IndicatorResult]:
|
|
93
|
+
"""
|
|
94
|
+
Calculate multiple indicators.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
indicators: Dictionary {indicator_name: parameters}
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
Dictionary of results {indicator_name: IndicatorResult}
|
|
101
|
+
"""
|
|
102
|
+
results = {}
|
|
103
|
+
|
|
104
|
+
for name, params in indicators.items():
|
|
105
|
+
try:
|
|
106
|
+
result = self.calculate(name, **params)
|
|
107
|
+
results[name] = result
|
|
108
|
+
except Exception as e:
|
|
109
|
+
self.logger.error(f"Failed to calculate {name}: {e}")
|
|
110
|
+
# Продолжаем вычисления остальных индикаторов
|
|
111
|
+
continue
|
|
112
|
+
|
|
113
|
+
return results
|
|
114
|
+
|
|
115
|
+
def get_result(self, indicator_name: str) -> Optional[IndicatorResult]:
|
|
116
|
+
"""
|
|
117
|
+
Get cached result for indicator.
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
indicator_name: Name of the indicator
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
IndicatorResult or None if not calculated
|
|
124
|
+
"""
|
|
125
|
+
return self.results.get(indicator_name)
|
|
126
|
+
|
|
127
|
+
def get_all_results(self) -> Dict[str, IndicatorResult]:
|
|
128
|
+
"""Get all cached results."""
|
|
129
|
+
return self.results.copy()
|
|
130
|
+
|
|
131
|
+
def combine_results(self, indicator_names: Optional[List[str]] = None) -> pd.DataFrame:
|
|
132
|
+
"""
|
|
133
|
+
Combine multiple indicator results into single DataFrame.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
indicator_names: List of indicators to include (None for all)
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
Combined DataFrame with all indicator data
|
|
140
|
+
"""
|
|
141
|
+
if indicator_names is None:
|
|
142
|
+
indicator_names = list(self.results.keys())
|
|
143
|
+
|
|
144
|
+
combined_data = self.data.copy()
|
|
145
|
+
|
|
146
|
+
for name in indicator_names:
|
|
147
|
+
if name in self.results:
|
|
148
|
+
result = self.results[name]
|
|
149
|
+
# Добавляем колонки с префиксом если необходимо
|
|
150
|
+
for col in result.data.columns:
|
|
151
|
+
if col not in combined_data.columns:
|
|
152
|
+
combined_data[col] = result.data[col]
|
|
153
|
+
else:
|
|
154
|
+
combined_data[f"{name}_{col}"] = result.data[col]
|
|
155
|
+
|
|
156
|
+
return combined_data
|
|
157
|
+
|
|
158
|
+
def clear_cache(self):
|
|
159
|
+
"""Clear all cached results."""
|
|
160
|
+
self.results.clear()
|
|
161
|
+
self.logger.info("Cleared all cached results")
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def calculate_indicator(data: pd.DataFrame, indicator_name: str, **kwargs) -> IndicatorResult:
|
|
165
|
+
"""
|
|
166
|
+
Convenience function to calculate single indicator.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
data: DataFrame with price data
|
|
170
|
+
indicator_name: Name of the indicator
|
|
171
|
+
**kwargs: Indicator parameters
|
|
172
|
+
|
|
173
|
+
Returns:
|
|
174
|
+
IndicatorResult with calculation results
|
|
175
|
+
"""
|
|
176
|
+
calculator = IndicatorCalculator(data, auto_load_libraries=False)
|
|
177
|
+
return calculator.calculate(indicator_name, **kwargs)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def calculate_macd(data: pd.DataFrame, fast: int = 12, slow: int = 26, signal: int = 9) -> pd.DataFrame:
|
|
181
|
+
"""
|
|
182
|
+
Convenience function to calculate MACD.
|
|
183
|
+
|
|
184
|
+
Args:
|
|
185
|
+
data: DataFrame with price data
|
|
186
|
+
fast: Fast EMA period
|
|
187
|
+
slow: Slow EMA period
|
|
188
|
+
signal: Signal line period
|
|
189
|
+
|
|
190
|
+
Returns:
|
|
191
|
+
DataFrame with MACD data
|
|
192
|
+
"""
|
|
193
|
+
result = calculate_indicator(data, 'macd', fast_period=fast, slow_period=slow, signal_period=signal)
|
|
194
|
+
return result.data
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def calculate_rsi(data: pd.DataFrame, period: int = 14) -> pd.Series:
|
|
198
|
+
"""
|
|
199
|
+
Convenience function to calculate RSI.
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
data: DataFrame with price data
|
|
203
|
+
period: RSI period
|
|
204
|
+
|
|
205
|
+
Returns:
|
|
206
|
+
Series with RSI values
|
|
207
|
+
"""
|
|
208
|
+
result = calculate_indicator(data, 'rsi', period=period)
|
|
209
|
+
return result.data.iloc[:, 0] # Возвращаем первую колонку как Series
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def calculate_bollinger_bands(data: pd.DataFrame, period: int = 20, std_dev: float = 2.0) -> pd.DataFrame:
|
|
213
|
+
"""
|
|
214
|
+
Convenience function to calculate Bollinger Bands.
|
|
215
|
+
|
|
216
|
+
Args:
|
|
217
|
+
data: DataFrame with price data
|
|
218
|
+
period: Period for calculation
|
|
219
|
+
std_dev: Standard deviation multiplier
|
|
220
|
+
|
|
221
|
+
Returns:
|
|
222
|
+
DataFrame with Bollinger Bands data
|
|
223
|
+
"""
|
|
224
|
+
result = calculate_indicator(data, 'bbands', period=period, std_dev=std_dev)
|
|
225
|
+
return result.data
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def calculate_moving_averages(data: pd.DataFrame, periods: List[int] = None) -> pd.DataFrame:
|
|
229
|
+
"""
|
|
230
|
+
Calculate multiple moving averages.
|
|
231
|
+
|
|
232
|
+
Args:
|
|
233
|
+
data: DataFrame with price data
|
|
234
|
+
periods: List of periods for moving averages
|
|
235
|
+
|
|
236
|
+
Returns:
|
|
237
|
+
DataFrame with moving averages
|
|
238
|
+
"""
|
|
239
|
+
if periods is None:
|
|
240
|
+
periods = [10, 20, 50, 200]
|
|
241
|
+
|
|
242
|
+
calculator = IndicatorCalculator(data, auto_load_libraries=False)
|
|
243
|
+
|
|
244
|
+
# Вычисляем SMA для каждого периода
|
|
245
|
+
sma_indicators = {f'sma_{period}': {'period': period} for period in periods}
|
|
246
|
+
|
|
247
|
+
# Вычисляем EMA для каждого периода
|
|
248
|
+
ema_indicators = {f'ema_{period}': {'period': period} for period in periods}
|
|
249
|
+
|
|
250
|
+
# Объединяем все индикаторы
|
|
251
|
+
all_indicators = {**sma_indicators, **ema_indicators}
|
|
252
|
+
|
|
253
|
+
results = calculator.calculate_multiple(all_indicators)
|
|
254
|
+
|
|
255
|
+
# Объединяем результаты
|
|
256
|
+
combined_data = pd.DataFrame(index=data.index)
|
|
257
|
+
for name, result in results.items():
|
|
258
|
+
for col in result.data.columns:
|
|
259
|
+
combined_data[col] = result.data[col]
|
|
260
|
+
|
|
261
|
+
return combined_data
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def create_indicator_suite(data: pd.DataFrame) -> Dict[str, IndicatorResult]:
|
|
265
|
+
"""
|
|
266
|
+
Calculate standard suite of technical indicators.
|
|
267
|
+
|
|
268
|
+
Args:
|
|
269
|
+
data: DataFrame with price data
|
|
270
|
+
|
|
271
|
+
Returns:
|
|
272
|
+
Dictionary with all calculated indicators
|
|
273
|
+
"""
|
|
274
|
+
calculator = IndicatorCalculator(data)
|
|
275
|
+
|
|
276
|
+
# Определяем стандартный набор индикаторов
|
|
277
|
+
standard_indicators = {
|
|
278
|
+
'sma_20': {'period': 20},
|
|
279
|
+
'sma_50': {'period': 50},
|
|
280
|
+
'ema_12': {'period': 12},
|
|
281
|
+
'ema_26': {'period': 26},
|
|
282
|
+
'rsi_14': {'period': 14},
|
|
283
|
+
'macd': {'fast_period': 12, 'slow_period': 26, 'signal_period': 9},
|
|
284
|
+
'bbands': {'period': 20, 'std_dev': 2.0},
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
# Вычисляем все индикаторы
|
|
288
|
+
results = calculator.calculate_multiple(standard_indicators)
|
|
289
|
+
|
|
290
|
+
logger.info(f"Calculated {len(results)} indicators in standard suite")
|
|
291
|
+
return results
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def get_available_indicators() -> Dict[str, str]:
|
|
295
|
+
"""
|
|
296
|
+
Get list of all available indicators.
|
|
297
|
+
|
|
298
|
+
Returns:
|
|
299
|
+
Dictionary {indicator_name: source}
|
|
300
|
+
"""
|
|
301
|
+
# Загружаем все индикаторы
|
|
302
|
+
register_builtin_indicators()
|
|
303
|
+
LibraryManager.load_all_libraries()
|
|
304
|
+
|
|
305
|
+
return IndicatorFactory.list_indicators()
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
def validate_indicator_data(data: pd.DataFrame, indicator_name: str, **kwargs) -> bool:
|
|
309
|
+
"""
|
|
310
|
+
Validate data for specific indicator without calculating.
|
|
311
|
+
|
|
312
|
+
Args:
|
|
313
|
+
data: DataFrame with price data
|
|
314
|
+
indicator_name: Name of the indicator
|
|
315
|
+
**kwargs: Indicator parameters
|
|
316
|
+
|
|
317
|
+
Returns:
|
|
318
|
+
True if data is valid for the indicator
|
|
319
|
+
"""
|
|
320
|
+
try:
|
|
321
|
+
indicator = IndicatorFactory.create_indicator(indicator_name, **kwargs)
|
|
322
|
+
return indicator.validate_data(data)
|
|
323
|
+
except Exception as e:
|
|
324
|
+
logger.warning(f"Data validation failed for {indicator_name}: {e}")
|
|
325
|
+
return False
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
class BatchCalculator:
|
|
329
|
+
"""
|
|
330
|
+
Calculator for batch processing of multiple datasets.
|
|
331
|
+
"""
|
|
332
|
+
|
|
333
|
+
def __init__(self, datasets: Dict[str, pd.DataFrame]):
|
|
334
|
+
"""
|
|
335
|
+
Initialize batch calculator.
|
|
336
|
+
|
|
337
|
+
Args:
|
|
338
|
+
datasets: Dictionary {dataset_name: DataFrame}
|
|
339
|
+
"""
|
|
340
|
+
self.datasets = datasets
|
|
341
|
+
self.results = {}
|
|
342
|
+
self.logger = get_logger(f"{__name__}.BatchCalculator")
|
|
343
|
+
|
|
344
|
+
def calculate_for_all(self, indicator_name: str, **kwargs) -> Dict[str, IndicatorResult]:
|
|
345
|
+
"""
|
|
346
|
+
Calculate indicator for all datasets.
|
|
347
|
+
|
|
348
|
+
Args:
|
|
349
|
+
indicator_name: Name of the indicator
|
|
350
|
+
**kwargs: Indicator parameters
|
|
351
|
+
|
|
352
|
+
Returns:
|
|
353
|
+
Dictionary {dataset_name: IndicatorResult}
|
|
354
|
+
"""
|
|
355
|
+
results = {}
|
|
356
|
+
|
|
357
|
+
for dataset_name, data in self.datasets.items():
|
|
358
|
+
try:
|
|
359
|
+
calculator = IndicatorCalculator(data, auto_load_libraries=False)
|
|
360
|
+
result = calculator.calculate(indicator_name, **kwargs)
|
|
361
|
+
results[dataset_name] = result
|
|
362
|
+
|
|
363
|
+
self.logger.info(f"Calculated {indicator_name} for {dataset_name}")
|
|
364
|
+
|
|
365
|
+
except Exception as e:
|
|
366
|
+
self.logger.error(f"Failed to calculate {indicator_name} for {dataset_name}: {e}")
|
|
367
|
+
|
|
368
|
+
return results
|
|
369
|
+
|
|
370
|
+
def calculate_suite_for_all(self) -> Dict[str, Dict[str, IndicatorResult]]:
|
|
371
|
+
"""
|
|
372
|
+
Calculate standard indicator suite for all datasets.
|
|
373
|
+
|
|
374
|
+
Returns:
|
|
375
|
+
Nested dictionary {dataset_name: {indicator_name: IndicatorResult}}
|
|
376
|
+
"""
|
|
377
|
+
results = {}
|
|
378
|
+
|
|
379
|
+
for dataset_name, data in self.datasets.items():
|
|
380
|
+
try:
|
|
381
|
+
suite_results = create_indicator_suite(data)
|
|
382
|
+
results[dataset_name] = suite_results
|
|
383
|
+
|
|
384
|
+
self.logger.info(f"Calculated indicator suite for {dataset_name}")
|
|
385
|
+
|
|
386
|
+
except Exception as e:
|
|
387
|
+
self.logger.error(f"Failed to calculate suite for {dataset_name}: {e}")
|
|
388
|
+
|
|
389
|
+
return results
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
# Экспорт
|
|
393
|
+
__all__ = [
|
|
394
|
+
'IndicatorCalculator',
|
|
395
|
+
'BatchCalculator',
|
|
396
|
+
'calculate_indicator',
|
|
397
|
+
'calculate_macd',
|
|
398
|
+
'calculate_rsi',
|
|
399
|
+
'calculate_bollinger_bands',
|
|
400
|
+
'calculate_moving_averages',
|
|
401
|
+
'create_indicator_suite',
|
|
402
|
+
'get_available_indicators',
|
|
403
|
+
'validate_indicator_data'
|
|
404
|
+
]
|