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,514 @@
1
+ """
2
+ BQuant built-in indicator library
3
+
4
+ This module contains preloaded technical indicators implemented specifically for BQuant.
5
+ """
6
+
7
+ import pandas as pd
8
+ import numpy as np
9
+ from typing import Dict, Any, Optional, List, Tuple
10
+
11
+ from .base import PreloadedIndicator, IndicatorResult, IndicatorConfig, IndicatorSource
12
+ from ..core.exceptions import IndicatorCalculationError
13
+ from ..core.logging_config import get_logger
14
+
15
+ logger = get_logger(__name__)
16
+
17
+
18
+ class SimpleMovingAverage(PreloadedIndicator):
19
+ """
20
+ Simple Moving Average (SMA) indicator.
21
+ """
22
+
23
+ def __init__(self, period: int = 20):
24
+ """
25
+ Initialize SMA indicator.
26
+
27
+ Args:
28
+ period: Period for moving average calculation
29
+ """
30
+ self.period = period
31
+ super().__init__('sma', {'period': period})
32
+
33
+ def get_output_columns(self) -> List[str]:
34
+ """Returns output columns."""
35
+ return [f'sma_{self.period}']
36
+
37
+ def get_description(self) -> str:
38
+ """Returns indicator description."""
39
+ return f"Simple Moving Average with {self.period} period"
40
+
41
+ def get_min_records(self) -> int:
42
+ """Returns minimum records required."""
43
+ return self.period
44
+
45
+ def calculate(self, data: pd.DataFrame, **kwargs) -> IndicatorResult:
46
+ """
47
+ Calculate SMA.
48
+
49
+ Args:
50
+ data: DataFrame with price data
51
+ **kwargs: Additional parameters
52
+
53
+ Returns:
54
+ IndicatorResult with SMA values
55
+ """
56
+ try:
57
+ self.validate_data(data)
58
+
59
+ # Получаем период из kwargs или используем значение по умолчанию
60
+ period = kwargs.get('period', self.period)
61
+
62
+ self.logger.info(f"Calculating SMA with period {period}")
63
+
64
+ # Вычисляем SMA
65
+ sma_values = data['close'].rolling(window=period).mean()
66
+
67
+ result_data = pd.DataFrame({
68
+ f'sma_{period}': sma_values
69
+ }, index=data.index)
70
+
71
+ return IndicatorResult(
72
+ name=self.name,
73
+ data=result_data,
74
+ config=self.config,
75
+ metadata={
76
+ 'period': period,
77
+ 'calculation_method': 'rolling_mean',
78
+ 'first_valid_index': result_data.first_valid_index(),
79
+ 'last_valid_index': result_data.last_valid_index()
80
+ }
81
+ )
82
+
83
+ except Exception as e:
84
+ raise IndicatorCalculationError(
85
+ f"Failed to calculate SMA: {e}",
86
+ {'indicator': self.name, 'period': period}
87
+ )
88
+
89
+
90
+ class ExponentialMovingAverage(PreloadedIndicator):
91
+ """
92
+ Exponential Moving Average (EMA) indicator.
93
+ """
94
+
95
+ def __init__(self, period: int = 20):
96
+ """
97
+ Initialize EMA indicator.
98
+
99
+ Args:
100
+ period: Period for exponential moving average calculation
101
+ """
102
+ self.period = period
103
+ super().__init__('ema', {'period': period})
104
+
105
+ def get_output_columns(self) -> List[str]:
106
+ """Returns output columns."""
107
+ return [f'ema_{self.period}']
108
+
109
+ def get_description(self) -> str:
110
+ """Returns indicator description."""
111
+ return f"Exponential Moving Average with {self.period} period"
112
+
113
+ def get_min_records(self) -> int:
114
+ """Returns minimum records required."""
115
+ return self.period
116
+
117
+ def calculate(self, data: pd.DataFrame, **kwargs) -> IndicatorResult:
118
+ """
119
+ Calculate EMA.
120
+
121
+ Args:
122
+ data: DataFrame with price data
123
+ **kwargs: Additional parameters
124
+
125
+ Returns:
126
+ IndicatorResult with EMA values
127
+ """
128
+ try:
129
+ self.validate_data(data)
130
+
131
+ period = kwargs.get('period', self.period)
132
+
133
+ self.logger.info(f"Calculating EMA with period {period}")
134
+
135
+ # Вычисляем EMA
136
+ ema_values = data['close'].ewm(span=period).mean()
137
+
138
+ result_data = pd.DataFrame({
139
+ f'ema_{period}': ema_values
140
+ }, index=data.index)
141
+
142
+ return IndicatorResult(
143
+ name=self.name,
144
+ data=result_data,
145
+ config=self.config,
146
+ metadata={
147
+ 'period': period,
148
+ 'calculation_method': 'exponential_weighted_mean',
149
+ 'alpha': 2 / (period + 1),
150
+ 'first_valid_index': result_data.first_valid_index(),
151
+ 'last_valid_index': result_data.last_valid_index()
152
+ }
153
+ )
154
+
155
+ except Exception as e:
156
+ raise IndicatorCalculationError(
157
+ f"Failed to calculate EMA: {e}",
158
+ {'indicator': self.name, 'period': period}
159
+ )
160
+
161
+
162
+ class RelativeStrengthIndex(PreloadedIndicator):
163
+ """
164
+ Relative Strength Index (RSI) indicator.
165
+ """
166
+
167
+ def __init__(self, period: int = 14):
168
+ """
169
+ Initialize RSI indicator.
170
+
171
+ Args:
172
+ period: Period for RSI calculation
173
+ """
174
+ self.period = period
175
+ super().__init__('rsi', {'period': period})
176
+
177
+ def get_output_columns(self) -> List[str]:
178
+ """Returns output columns."""
179
+ return [f'rsi_{self.period}']
180
+
181
+ def get_description(self) -> str:
182
+ """Returns indicator description."""
183
+ return f"Relative Strength Index with {self.period} period"
184
+
185
+ def get_min_records(self) -> int:
186
+ """Returns minimum records required."""
187
+ return self.period + 1
188
+
189
+ def calculate(self, data: pd.DataFrame, **kwargs) -> IndicatorResult:
190
+ """
191
+ Calculate RSI.
192
+
193
+ Args:
194
+ data: DataFrame with price data
195
+ **kwargs: Additional parameters
196
+
197
+ Returns:
198
+ IndicatorResult with RSI values
199
+ """
200
+ try:
201
+ self.validate_data(data)
202
+
203
+ period = kwargs.get('period', self.period)
204
+
205
+ self.logger.info(f"Calculating RSI with period {period}")
206
+
207
+ # Вычисляем изменения цен
208
+ price_changes = data['close'].diff()
209
+
210
+ # Разделяем на положительные и отрицательные изменения
211
+ gains = price_changes.where(price_changes > 0, 0)
212
+ losses = -price_changes.where(price_changes < 0, 0)
213
+
214
+ # Вычисляем средние значения методом экспоненциального сглаживания
215
+ avg_gains = gains.ewm(alpha=1/period).mean()
216
+ avg_losses = losses.ewm(alpha=1/period).mean()
217
+
218
+ # Вычисляем RS и RSI
219
+ rs = avg_gains / avg_losses
220
+ rsi_values = 100 - (100 / (1 + rs))
221
+
222
+ result_data = pd.DataFrame({
223
+ f'rsi_{period}': rsi_values
224
+ }, index=data.index)
225
+
226
+ return IndicatorResult(
227
+ name=self.name,
228
+ data=result_data,
229
+ config=self.config,
230
+ metadata={
231
+ 'period': period,
232
+ 'calculation_method': 'ewm_smoothing',
233
+ 'overbought_level': 70,
234
+ 'oversold_level': 30,
235
+ 'first_valid_index': result_data.first_valid_index(),
236
+ 'last_valid_index': result_data.last_valid_index()
237
+ }
238
+ )
239
+
240
+ except Exception as e:
241
+ raise IndicatorCalculationError(
242
+ f"Failed to calculate RSI: {e}",
243
+ {'indicator': self.name, 'period': period}
244
+ )
245
+
246
+
247
+ class MACD(PreloadedIndicator):
248
+ """
249
+ Moving Average Convergence Divergence (MACD) indicator.
250
+ """
251
+
252
+ def __init__(self, fast_period: int = 12, slow_period: int = 26, signal_period: int = 9):
253
+ """
254
+ Initialize MACD indicator.
255
+
256
+ Args:
257
+ fast_period: Fast EMA period
258
+ slow_period: Slow EMA period
259
+ signal_period: Signal line EMA period
260
+ """
261
+ self.fast_period = fast_period
262
+ self.slow_period = slow_period
263
+ self.signal_period = signal_period
264
+
265
+ super().__init__('macd', {
266
+ 'fast_period': fast_period,
267
+ 'slow_period': slow_period,
268
+ 'signal_period': signal_period
269
+ })
270
+
271
+ def get_output_columns(self) -> List[str]:
272
+ """Returns output columns."""
273
+ return ['macd', 'macd_signal', 'macd_hist']
274
+
275
+ def get_description(self) -> str:
276
+ """Returns indicator description."""
277
+ return f"MACD ({self.fast_period}, {self.slow_period}, {self.signal_period})"
278
+
279
+ def get_min_records(self) -> int:
280
+ """Returns minimum records required."""
281
+ return self.slow_period + self.signal_period
282
+
283
+ def get_required_columns(self) -> List[str]:
284
+ """Returns required input columns."""
285
+ return ['close']
286
+
287
+ def calculate(self, data: pd.DataFrame, **kwargs) -> IndicatorResult:
288
+ """
289
+ Calculate MACD.
290
+
291
+ Args:
292
+ data: DataFrame with price data
293
+ **kwargs: Additional parameters
294
+
295
+ Returns:
296
+ IndicatorResult with MACD values
297
+ """
298
+ try:
299
+ self.validate_data(data)
300
+
301
+ fast_period = kwargs.get('fast_period', self.fast_period)
302
+ slow_period = kwargs.get('slow_period', self.slow_period)
303
+ signal_period = kwargs.get('signal_period', self.signal_period)
304
+
305
+ self.logger.info(f"Calculating MACD ({fast_period}, {slow_period}, {signal_period})")
306
+
307
+ # Вычисляем быструю и медленную EMA
308
+ fast_ema = data['close'].ewm(span=fast_period).mean()
309
+ slow_ema = data['close'].ewm(span=slow_period).mean()
310
+
311
+ # Вычисляем MACD линию
312
+ macd_line = fast_ema - slow_ema
313
+
314
+ # Вычисляем сигнальную линию
315
+ signal_line = macd_line.ewm(span=signal_period).mean()
316
+
317
+ # Вычисляем гистограмму
318
+ histogram = macd_line - signal_line
319
+
320
+ result_data = pd.DataFrame({
321
+ 'macd': macd_line,
322
+ 'macd_signal': signal_line,
323
+ 'macd_hist': histogram
324
+ }, index=data.index)
325
+
326
+ return IndicatorResult(
327
+ name=self.name,
328
+ data=result_data,
329
+ config=self.config,
330
+ metadata={
331
+ 'fast_period': fast_period,
332
+ 'slow_period': slow_period,
333
+ 'signal_period': signal_period,
334
+ 'calculation_method': 'ema_difference',
335
+ 'first_valid_index': result_data.first_valid_index(),
336
+ 'last_valid_index': result_data.last_valid_index()
337
+ }
338
+ )
339
+
340
+ except Exception as e:
341
+ fast_period = kwargs.get('fast_period', self.fast_period)
342
+ slow_period = kwargs.get('slow_period', self.slow_period)
343
+ signal_period = kwargs.get('signal_period', self.signal_period)
344
+
345
+ raise IndicatorCalculationError(
346
+ f"Failed to calculate MACD: {e}",
347
+ {
348
+ 'indicator': self.name,
349
+ 'fast_period': fast_period,
350
+ 'slow_period': slow_period,
351
+ 'signal_period': signal_period
352
+ }
353
+ )
354
+
355
+
356
+ class BollingerBands(PreloadedIndicator):
357
+ """
358
+ Bollinger Bands indicator.
359
+ """
360
+
361
+ def __init__(self, period: int = 20, std_dev: float = 2.0):
362
+ """
363
+ Initialize Bollinger Bands indicator.
364
+
365
+ Args:
366
+ period: Period for moving average and standard deviation
367
+ std_dev: Standard deviation multiplier
368
+ """
369
+ self.period = period
370
+ self.std_dev = std_dev
371
+ super().__init__('bbands', {'period': period, 'std_dev': std_dev})
372
+
373
+ def get_output_columns(self) -> List[str]:
374
+ """Returns output columns."""
375
+ return ['bb_upper', 'bb_middle', 'bb_lower', 'bb_width', 'bb_percent']
376
+
377
+ def get_description(self) -> str:
378
+ """Returns indicator description."""
379
+ return f"Bollinger Bands ({self.period}, {self.std_dev})"
380
+
381
+ def get_min_records(self) -> int:
382
+ """Returns minimum records required."""
383
+ return self.period
384
+
385
+ def calculate(self, data: pd.DataFrame, **kwargs) -> IndicatorResult:
386
+ """
387
+ Calculate Bollinger Bands.
388
+
389
+ Args:
390
+ data: DataFrame with price data
391
+ **kwargs: Additional parameters
392
+
393
+ Returns:
394
+ IndicatorResult with Bollinger Bands values
395
+ """
396
+ try:
397
+ self.validate_data(data)
398
+
399
+ period = kwargs.get('period', self.period)
400
+ std_dev = kwargs.get('std_dev', self.std_dev)
401
+
402
+ self.logger.info(f"Calculating Bollinger Bands ({period}, {std_dev})")
403
+
404
+ # Вычисляем среднюю линию (SMA)
405
+ middle_band = data['close'].rolling(window=period).mean()
406
+
407
+ # Вычисляем стандартное отклонение
408
+ std = data['close'].rolling(window=period).std()
409
+
410
+ # Вычисляем верхнюю и нижнюю полосы
411
+ upper_band = middle_band + (std * std_dev)
412
+ lower_band = middle_band - (std * std_dev)
413
+
414
+ # Дополнительные метрики
415
+ bb_width = (upper_band - lower_band) / middle_band * 100
416
+ bb_percent = (data['close'] - lower_band) / (upper_band - lower_band) * 100
417
+
418
+ result_data = pd.DataFrame({
419
+ 'bb_upper': upper_band,
420
+ 'bb_middle': middle_band,
421
+ 'bb_lower': lower_band,
422
+ 'bb_width': bb_width,
423
+ 'bb_percent': bb_percent
424
+ }, index=data.index)
425
+
426
+ return IndicatorResult(
427
+ name=self.name,
428
+ data=result_data,
429
+ config=self.config,
430
+ metadata={
431
+ 'period': period,
432
+ 'std_dev': std_dev,
433
+ 'calculation_method': 'sma_plus_std',
434
+ 'first_valid_index': result_data.first_valid_index(),
435
+ 'last_valid_index': result_data.last_valid_index()
436
+ }
437
+ )
438
+
439
+ except Exception as e:
440
+ raise IndicatorCalculationError(
441
+ f"Failed to calculate Bollinger Bands: {e}",
442
+ {'indicator': self.name, 'period': period, 'std_dev': std_dev}
443
+ )
444
+
445
+
446
+ # Реестр встроенных индикаторов
447
+ BUILTIN_INDICATORS = {
448
+ 'sma': SimpleMovingAverage,
449
+ 'ema': ExponentialMovingAverage,
450
+ 'rsi': RelativeStrengthIndex,
451
+ 'macd': MACD,
452
+ 'bbands': BollingerBands,
453
+ }
454
+
455
+
456
+ def register_builtin_indicators():
457
+ """
458
+ Регистрация всех встроенных индикаторов в фабрике.
459
+ """
460
+ from .base import IndicatorFactory
461
+
462
+ registered_count = 0
463
+
464
+ for name, indicator_class in BUILTIN_INDICATORS.items():
465
+ try:
466
+ IndicatorFactory.register_indicator(name, indicator_class)
467
+ registered_count += 1
468
+ except Exception as e:
469
+ logger.error(f"Failed to register {name}: {e}")
470
+
471
+ logger.info(f"Registered {registered_count} builtin indicators")
472
+ return registered_count
473
+
474
+
475
+ def get_builtin_indicators() -> List[str]:
476
+ """
477
+ Получить список встроенных индикаторов.
478
+
479
+ Returns:
480
+ Список названий встроенных индикаторов
481
+ """
482
+ return list(BUILTIN_INDICATORS.keys())
483
+
484
+
485
+ def create_indicator(name: str, **kwargs):
486
+ """
487
+ Создать встроенный индикатор по имени.
488
+
489
+ Args:
490
+ name: Название индикатора
491
+ **kwargs: Параметры индикатора
492
+
493
+ Returns:
494
+ Экземпляр индикатора
495
+ """
496
+ if name.lower() not in BUILTIN_INDICATORS:
497
+ raise ValueError(f"Unknown builtin indicator: {name}")
498
+
499
+ indicator_class = BUILTIN_INDICATORS[name.lower()]
500
+ return indicator_class(**kwargs)
501
+
502
+
503
+ # Экспорт
504
+ __all__ = [
505
+ 'SimpleMovingAverage',
506
+ 'ExponentialMovingAverage',
507
+ 'RelativeStrengthIndex',
508
+ 'MACD',
509
+ 'BollingerBands',
510
+ 'BUILTIN_INDICATORS',
511
+ 'register_builtin_indicators',
512
+ 'get_builtin_indicators',
513
+ 'create_indicator'
514
+ ]