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,487 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Base classes and architecture for BQuant indicators
|
|
3
|
+
|
|
4
|
+
This module provides the foundation for all technical indicators in BQuant.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import pandas as pd
|
|
8
|
+
import numpy as np
|
|
9
|
+
from abc import ABC, abstractmethod
|
|
10
|
+
from enum import Enum
|
|
11
|
+
from typing import Dict, Any, Optional, List, Union, Type, Callable
|
|
12
|
+
from dataclasses import dataclass
|
|
13
|
+
from datetime import datetime
|
|
14
|
+
|
|
15
|
+
from ..core.exceptions import IndicatorCalculationError
|
|
16
|
+
from ..core.logging_config import get_logger
|
|
17
|
+
from ..core.cache import cached, get_cache_manager
|
|
18
|
+
|
|
19
|
+
# Получаем логгер для модуля
|
|
20
|
+
logger = get_logger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class IndicatorSource(Enum):
|
|
24
|
+
"""
|
|
25
|
+
Источники индикаторов для BQuant.
|
|
26
|
+
|
|
27
|
+
PRELOADED - предзагруженные индикаторы (встроенные в BQuant)
|
|
28
|
+
LIBRARY - индикаторы из внешних библиотек (pandas-ta, talib)
|
|
29
|
+
CUSTOM - пользовательские индикаторы
|
|
30
|
+
"""
|
|
31
|
+
PRELOADED = "preloaded"
|
|
32
|
+
LIBRARY = "library"
|
|
33
|
+
CUSTOM = "custom"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass
|
|
37
|
+
class IndicatorConfig:
|
|
38
|
+
"""
|
|
39
|
+
Конфигурация для индикаторов.
|
|
40
|
+
|
|
41
|
+
Attributes:
|
|
42
|
+
name: Название индикатора
|
|
43
|
+
parameters: Параметры индикатора
|
|
44
|
+
source: Источник индикатора
|
|
45
|
+
columns: Ожидаемые колонки результата
|
|
46
|
+
description: Описание индикатора
|
|
47
|
+
"""
|
|
48
|
+
name: str
|
|
49
|
+
parameters: Dict[str, Any]
|
|
50
|
+
source: IndicatorSource
|
|
51
|
+
columns: List[str]
|
|
52
|
+
description: str = ""
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@dataclass
|
|
56
|
+
class IndicatorResult:
|
|
57
|
+
"""
|
|
58
|
+
Результат вычисления индикатора.
|
|
59
|
+
|
|
60
|
+
Attributes:
|
|
61
|
+
name: Название индикатора
|
|
62
|
+
data: DataFrame с результатами
|
|
63
|
+
config: Конфигурация индикатора
|
|
64
|
+
metadata: Дополнительная информация
|
|
65
|
+
"""
|
|
66
|
+
name: str
|
|
67
|
+
data: pd.DataFrame
|
|
68
|
+
config: IndicatorConfig
|
|
69
|
+
metadata: Dict[str, Any]
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class BaseIndicator(ABC):
|
|
73
|
+
"""
|
|
74
|
+
Базовый класс для всех индикаторов BQuant.
|
|
75
|
+
|
|
76
|
+
Этот класс определяет общий интерфейс для всех технических индикаторов.
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
def __init__(self, name: str, config: Optional[IndicatorConfig] = None):
|
|
80
|
+
"""
|
|
81
|
+
Инициализация базового индикатора.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
name: Название индикатора
|
|
85
|
+
config: Конфигурация индикатора
|
|
86
|
+
"""
|
|
87
|
+
self.name = name
|
|
88
|
+
self.config = config or IndicatorConfig(
|
|
89
|
+
name=name,
|
|
90
|
+
parameters={},
|
|
91
|
+
source=IndicatorSource.CUSTOM,
|
|
92
|
+
columns=[],
|
|
93
|
+
description=""
|
|
94
|
+
)
|
|
95
|
+
self.logger = get_logger(f"{__name__}.{name}")
|
|
96
|
+
|
|
97
|
+
# Кэширование результатов
|
|
98
|
+
self._cache = {}
|
|
99
|
+
self._cache_enabled = True
|
|
100
|
+
|
|
101
|
+
@abstractmethod
|
|
102
|
+
def calculate(self, data: pd.DataFrame, **kwargs) -> IndicatorResult:
|
|
103
|
+
"""
|
|
104
|
+
Абстрактный метод для вычисления индикатора.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
data: DataFrame с ценовыми данными
|
|
108
|
+
**kwargs: Дополнительные параметры
|
|
109
|
+
|
|
110
|
+
Returns:
|
|
111
|
+
IndicatorResult с результатами вычисления
|
|
112
|
+
"""
|
|
113
|
+
pass
|
|
114
|
+
|
|
115
|
+
def validate_data(self, data: pd.DataFrame) -> bool:
|
|
116
|
+
"""
|
|
117
|
+
Валидация входных данных.
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
data: DataFrame для валидации
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
True если данные корректны
|
|
124
|
+
|
|
125
|
+
Raises:
|
|
126
|
+
IndicatorCalculationError: Если данные некорректны
|
|
127
|
+
"""
|
|
128
|
+
if data.empty:
|
|
129
|
+
raise IndicatorCalculationError(
|
|
130
|
+
f"Empty DataFrame provided for indicator {self.name}",
|
|
131
|
+
{'indicator': self.name}
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
# Проверка минимального количества записей
|
|
135
|
+
min_records = self.get_min_records()
|
|
136
|
+
if len(data) < min_records:
|
|
137
|
+
raise IndicatorCalculationError(
|
|
138
|
+
f"Insufficient data for {self.name}: {len(data)} < {min_records}",
|
|
139
|
+
{'indicator': self.name, 'records': len(data), 'required': min_records}
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
# Проверка обязательных колонок
|
|
143
|
+
required_columns = self.get_required_columns()
|
|
144
|
+
missing_columns = [col for col in required_columns if col not in data.columns]
|
|
145
|
+
if missing_columns:
|
|
146
|
+
raise IndicatorCalculationError(
|
|
147
|
+
f"Missing required columns for {self.name}: {missing_columns}",
|
|
148
|
+
{'indicator': self.name, 'missing_columns': missing_columns}
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
return True
|
|
152
|
+
|
|
153
|
+
def get_min_records(self) -> int:
|
|
154
|
+
"""
|
|
155
|
+
Минимальное количество записей для вычисления индикатора.
|
|
156
|
+
|
|
157
|
+
Returns:
|
|
158
|
+
Минимальное количество записей
|
|
159
|
+
"""
|
|
160
|
+
return 1
|
|
161
|
+
|
|
162
|
+
def get_required_columns(self) -> List[str]:
|
|
163
|
+
"""
|
|
164
|
+
Обязательные колонки для вычисления индикатора.
|
|
165
|
+
|
|
166
|
+
Returns:
|
|
167
|
+
Список обязательных колонок
|
|
168
|
+
"""
|
|
169
|
+
return ['close']
|
|
170
|
+
|
|
171
|
+
def enable_cache(self, enabled: bool = True):
|
|
172
|
+
"""Включить/выключить кэширование результатов."""
|
|
173
|
+
self._cache_enabled = enabled
|
|
174
|
+
if not enabled:
|
|
175
|
+
self._cache.clear()
|
|
176
|
+
|
|
177
|
+
def clear_cache(self):
|
|
178
|
+
"""Очистить кэш результатов."""
|
|
179
|
+
self._cache.clear()
|
|
180
|
+
|
|
181
|
+
def _get_cache_key(self, data: pd.DataFrame, **kwargs) -> str:
|
|
182
|
+
"""Генерация ключа для кэширования."""
|
|
183
|
+
data_hash = pd.util.hash_pandas_object(data).sum()
|
|
184
|
+
params_str = str(sorted(kwargs.items()))
|
|
185
|
+
return f"{self.name}_{data_hash}_{hash(params_str)}"
|
|
186
|
+
|
|
187
|
+
def calculate_with_cache(self, data: pd.DataFrame, **kwargs) -> IndicatorResult:
|
|
188
|
+
"""
|
|
189
|
+
Вычисление индикатора с кэшированием.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
data: DataFrame с данными
|
|
193
|
+
**kwargs: Дополнительные параметры
|
|
194
|
+
|
|
195
|
+
Returns:
|
|
196
|
+
IndicatorResult с результатами
|
|
197
|
+
"""
|
|
198
|
+
# Используем новую систему кэширования
|
|
199
|
+
cache_manager = get_cache_manager()
|
|
200
|
+
|
|
201
|
+
# Генерируем ключ кэша
|
|
202
|
+
func_name = f"{self.__class__.__name__}.calculate"
|
|
203
|
+
cache_key = cache_manager.memory_cache._generate_key(func_name, (data,), kwargs)
|
|
204
|
+
|
|
205
|
+
# Проверяем кэш
|
|
206
|
+
cached_result = cache_manager.get(cache_key)
|
|
207
|
+
if cached_result is not None:
|
|
208
|
+
self.logger.debug(f"Cache hit for {self.name}")
|
|
209
|
+
return cached_result
|
|
210
|
+
|
|
211
|
+
# Вычисляем результат
|
|
212
|
+
self.logger.debug(f"Cache miss for {self.name}, calculating...")
|
|
213
|
+
result = self.calculate(data, **kwargs)
|
|
214
|
+
|
|
215
|
+
# Сохраняем в кэш (время жизни 1 час)
|
|
216
|
+
cache_manager.put(cache_key, result, ttl=3600, disk=True)
|
|
217
|
+
|
|
218
|
+
return result
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
class PreloadedIndicator(BaseIndicator):
|
|
222
|
+
"""
|
|
223
|
+
Базовый класс для предзагруженных (встроенных) индикаторов BQuant.
|
|
224
|
+
"""
|
|
225
|
+
|
|
226
|
+
def __init__(self, name: str, parameters: Dict[str, Any] = None):
|
|
227
|
+
"""
|
|
228
|
+
Инициализация предзагруженного индикатора.
|
|
229
|
+
|
|
230
|
+
Args:
|
|
231
|
+
name: Название индикатора
|
|
232
|
+
parameters: Параметры индикатора
|
|
233
|
+
"""
|
|
234
|
+
config = IndicatorConfig(
|
|
235
|
+
name=name,
|
|
236
|
+
parameters=parameters or {},
|
|
237
|
+
source=IndicatorSource.PRELOADED,
|
|
238
|
+
columns=self.get_output_columns(),
|
|
239
|
+
description=self.get_description()
|
|
240
|
+
)
|
|
241
|
+
super().__init__(name, config)
|
|
242
|
+
|
|
243
|
+
@abstractmethod
|
|
244
|
+
def get_output_columns(self) -> List[str]:
|
|
245
|
+
"""Возвращает список выходных колонок индикатора."""
|
|
246
|
+
pass
|
|
247
|
+
|
|
248
|
+
@abstractmethod
|
|
249
|
+
def get_description(self) -> str:
|
|
250
|
+
"""Возвращает описание индикатора."""
|
|
251
|
+
pass
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
class LibraryIndicator(BaseIndicator):
|
|
255
|
+
"""
|
|
256
|
+
Базовый класс для индикаторов из внешних библиотек.
|
|
257
|
+
"""
|
|
258
|
+
|
|
259
|
+
def __init__(self, name: str, library_func: Callable, parameters: Dict[str, Any] = None):
|
|
260
|
+
"""
|
|
261
|
+
Инициализация индикатора из библиотеки.
|
|
262
|
+
|
|
263
|
+
Args:
|
|
264
|
+
name: Название индикатора
|
|
265
|
+
library_func: Функция из библиотеки
|
|
266
|
+
parameters: Параметры для функции
|
|
267
|
+
"""
|
|
268
|
+
self.library_func = library_func
|
|
269
|
+
|
|
270
|
+
config = IndicatorConfig(
|
|
271
|
+
name=name,
|
|
272
|
+
parameters=parameters or {},
|
|
273
|
+
source=IndicatorSource.LIBRARY,
|
|
274
|
+
columns=[], # Будет определено динамически
|
|
275
|
+
description=f"Library indicator: {name}"
|
|
276
|
+
)
|
|
277
|
+
super().__init__(name, config)
|
|
278
|
+
|
|
279
|
+
def calculate(self, data: pd.DataFrame, **kwargs) -> IndicatorResult:
|
|
280
|
+
"""
|
|
281
|
+
Вычисление индикатора через библиотечную функцию.
|
|
282
|
+
|
|
283
|
+
Args:
|
|
284
|
+
data: DataFrame с данными
|
|
285
|
+
**kwargs: Дополнительные параметры
|
|
286
|
+
|
|
287
|
+
Returns:
|
|
288
|
+
IndicatorResult с результатами
|
|
289
|
+
"""
|
|
290
|
+
try:
|
|
291
|
+
self.validate_data(data)
|
|
292
|
+
|
|
293
|
+
# Объединяем параметры из конфига и kwargs
|
|
294
|
+
params = {**self.config.parameters, **kwargs}
|
|
295
|
+
|
|
296
|
+
self.logger.info(f"Calculating {self.name} using library function")
|
|
297
|
+
|
|
298
|
+
# Вызываем библиотечную функцию
|
|
299
|
+
result_data = self.library_func(data, **params)
|
|
300
|
+
|
|
301
|
+
# Убеждаемся, что результат - DataFrame
|
|
302
|
+
if not isinstance(result_data, pd.DataFrame):
|
|
303
|
+
if isinstance(result_data, pd.Series):
|
|
304
|
+
result_data = result_data.to_frame(name=self.name)
|
|
305
|
+
else:
|
|
306
|
+
raise IndicatorCalculationError(
|
|
307
|
+
f"Library function returned unexpected type: {type(result_data)}",
|
|
308
|
+
{'indicator': self.name}
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
# Обновляем конфигурацию с фактическими колонками
|
|
312
|
+
self.config.columns = list(result_data.columns)
|
|
313
|
+
|
|
314
|
+
return IndicatorResult(
|
|
315
|
+
name=self.name,
|
|
316
|
+
data=result_data,
|
|
317
|
+
config=self.config,
|
|
318
|
+
metadata={
|
|
319
|
+
'library_function': str(self.library_func),
|
|
320
|
+
'calculation_time': datetime.now(),
|
|
321
|
+
'data_shape': result_data.shape
|
|
322
|
+
}
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
except Exception as e:
|
|
326
|
+
raise IndicatorCalculationError(
|
|
327
|
+
f"Failed to calculate {self.name}: {e}",
|
|
328
|
+
{'indicator': self.name, 'error': str(e)}
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
class IndicatorFactory:
|
|
333
|
+
"""
|
|
334
|
+
Фабрика для создания индикаторов.
|
|
335
|
+
|
|
336
|
+
Предоставляет единый интерфейс для создания различных типов индикаторов.
|
|
337
|
+
"""
|
|
338
|
+
|
|
339
|
+
_registry = {}
|
|
340
|
+
_library_functions = {}
|
|
341
|
+
|
|
342
|
+
@classmethod
|
|
343
|
+
def register_indicator(cls, name: str, indicator_class: Type[BaseIndicator]):
|
|
344
|
+
"""
|
|
345
|
+
Регистрация индикатора в фабрике.
|
|
346
|
+
|
|
347
|
+
Args:
|
|
348
|
+
name: Название индикатора
|
|
349
|
+
indicator_class: Класс индикатора
|
|
350
|
+
"""
|
|
351
|
+
cls._registry[name.lower()] = indicator_class
|
|
352
|
+
logger.info(f"Registered indicator: {name}")
|
|
353
|
+
|
|
354
|
+
@classmethod
|
|
355
|
+
def register_library_function(cls, name: str, func: Callable):
|
|
356
|
+
"""
|
|
357
|
+
Регистрация функции из библиотеки.
|
|
358
|
+
|
|
359
|
+
Args:
|
|
360
|
+
name: Название индикатора
|
|
361
|
+
func: Функция из библиотеки
|
|
362
|
+
"""
|
|
363
|
+
cls._library_functions[name.lower()] = func
|
|
364
|
+
logger.info(f"Registered library function: {name}")
|
|
365
|
+
|
|
366
|
+
@classmethod
|
|
367
|
+
def create_indicator(cls, name: str, data: pd.DataFrame = None, **kwargs) -> BaseIndicator:
|
|
368
|
+
"""
|
|
369
|
+
Создание индикатора по имени.
|
|
370
|
+
|
|
371
|
+
Args:
|
|
372
|
+
name: Название индикатора
|
|
373
|
+
data: DataFrame с данными (для проверки)
|
|
374
|
+
**kwargs: Параметры индикатора
|
|
375
|
+
|
|
376
|
+
Returns:
|
|
377
|
+
Экземпляр индикатора
|
|
378
|
+
"""
|
|
379
|
+
name_lower = name.lower()
|
|
380
|
+
|
|
381
|
+
# Сначала ищем в зарегистрированных индикаторах
|
|
382
|
+
if name_lower in cls._registry:
|
|
383
|
+
return cls._registry[name_lower](**kwargs)
|
|
384
|
+
|
|
385
|
+
# Затем ищем в библиотечных функциях
|
|
386
|
+
if name_lower in cls._library_functions:
|
|
387
|
+
return LibraryIndicator(
|
|
388
|
+
name=name,
|
|
389
|
+
library_func=cls._library_functions[name_lower],
|
|
390
|
+
parameters=kwargs
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
# Если не найден, возвращаем заглушку
|
|
394
|
+
logger.warning(f"Indicator {name} not found, creating stub")
|
|
395
|
+
return _StubIndicator(name, **kwargs)
|
|
396
|
+
|
|
397
|
+
@classmethod
|
|
398
|
+
def list_indicators(cls) -> Dict[str, str]:
|
|
399
|
+
"""
|
|
400
|
+
Получить список доступных индикаторов.
|
|
401
|
+
|
|
402
|
+
Returns:
|
|
403
|
+
Словарь {название: источник}
|
|
404
|
+
"""
|
|
405
|
+
indicators = {}
|
|
406
|
+
|
|
407
|
+
for name in cls._registry:
|
|
408
|
+
indicators[name] = "preloaded"
|
|
409
|
+
|
|
410
|
+
for name in cls._library_functions:
|
|
411
|
+
indicators[name] = "library"
|
|
412
|
+
|
|
413
|
+
return indicators
|
|
414
|
+
|
|
415
|
+
@classmethod
|
|
416
|
+
def get_indicator_info(cls, name: str) -> Optional[Dict[str, Any]]:
|
|
417
|
+
"""
|
|
418
|
+
Получить информацию об индикаторе.
|
|
419
|
+
|
|
420
|
+
Args:
|
|
421
|
+
name: Название индикатора
|
|
422
|
+
|
|
423
|
+
Returns:
|
|
424
|
+
Информация об индикаторе или None
|
|
425
|
+
"""
|
|
426
|
+
name_lower = name.lower()
|
|
427
|
+
|
|
428
|
+
if name_lower in cls._registry:
|
|
429
|
+
indicator_class = cls._registry[name_lower]
|
|
430
|
+
return {
|
|
431
|
+
'name': name,
|
|
432
|
+
'source': 'preloaded',
|
|
433
|
+
'class': indicator_class.__name__,
|
|
434
|
+
'description': getattr(indicator_class, 'get_description', lambda: 'No description')()
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
if name_lower in cls._library_functions:
|
|
438
|
+
func = cls._library_functions[name_lower]
|
|
439
|
+
return {
|
|
440
|
+
'name': name,
|
|
441
|
+
'source': 'library',
|
|
442
|
+
'function': str(func),
|
|
443
|
+
'description': getattr(func, '__doc__', 'No description')
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
return None
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
class _StubIndicator(BaseIndicator):
|
|
450
|
+
"""
|
|
451
|
+
Заглушка для неизвестных индикаторов.
|
|
452
|
+
"""
|
|
453
|
+
|
|
454
|
+
def __init__(self, name: str, **kwargs):
|
|
455
|
+
super().__init__(name)
|
|
456
|
+
self.parameters = kwargs
|
|
457
|
+
|
|
458
|
+
def calculate(self, data: pd.DataFrame, **kwargs) -> IndicatorResult:
|
|
459
|
+
"""
|
|
460
|
+
Возвращает заглушку результата.
|
|
461
|
+
"""
|
|
462
|
+
self.logger.warning(f"Using stub for indicator {self.name}")
|
|
463
|
+
|
|
464
|
+
# Создаем DataFrame с NaN значениями
|
|
465
|
+
result_data = pd.DataFrame(
|
|
466
|
+
index=data.index,
|
|
467
|
+
data={f"{self.name}_value": np.nan}
|
|
468
|
+
)
|
|
469
|
+
|
|
470
|
+
return IndicatorResult(
|
|
471
|
+
name=self.name,
|
|
472
|
+
data=result_data,
|
|
473
|
+
config=self.config,
|
|
474
|
+
metadata={'stub': True, 'parameters': self.parameters}
|
|
475
|
+
)
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
# Экспорт основных классов
|
|
479
|
+
__all__ = [
|
|
480
|
+
'IndicatorSource',
|
|
481
|
+
'IndicatorConfig',
|
|
482
|
+
'IndicatorResult',
|
|
483
|
+
'BaseIndicator',
|
|
484
|
+
'PreloadedIndicator',
|
|
485
|
+
'LibraryIndicator',
|
|
486
|
+
'IndicatorFactory'
|
|
487
|
+
]
|