Refactor technical indicators to return DataFrames and enhance documentation

- Updated all technical indicators to return pandas DataFrames instead of lists, improving consistency and usability.
- Modified the `calculate` method in `TechnicalIndicators` to directly return DataFrames with relevant indicator values.
- Enhanced the `data_integration.py` to utilize the new DataFrame outputs for better integration with charting.
- Updated documentation to reflect the new DataFrame-centric approach, including usage examples and output structures.
- Improved error handling to ensure empty DataFrames are returned when insufficient data is available.

These changes streamline the indicator calculations and improve the overall architecture, aligning with project standards for maintainability and performance.
This commit is contained in:
Vasily.onl
2025-06-09 16:28:16 +08:00
parent fc3cac24bd
commit ec8f5514bb
14 changed files with 542 additions and 542 deletions

View File

@@ -11,6 +11,7 @@ from datetime import datetime, timezone
from decimal import Decimal
import json
from enum import Enum
import pandas as pd
from data.common.indicators import TechnicalIndicators, IndicatorResult, create_default_indicators_config, validate_indicator_config
from data.common.data_types import OHLCVCandle
@@ -475,7 +476,7 @@ def convert_database_candles_to_ohlcv(candles: List[Dict[str, Any]]) -> List[OHL
def calculate_indicators(candles: List[Dict[str, Any]],
indicator_configs: List[str],
custom_configs: Optional[Dict[str, ChartIndicatorConfig]] = None) -> Dict[str, List[IndicatorResult]]:
custom_configs: Optional[Dict[str, ChartIndicatorConfig]] = None) -> Dict[str, pd.DataFrame]:
"""
Calculate technical indicators for chart display.
@@ -485,7 +486,7 @@ def calculate_indicators(candles: List[Dict[str, Any]],
custom_configs: Optional custom indicator configurations
Returns:
Dictionary mapping indicator names to their calculation results
Dictionary mapping indicator names to their calculation results as DataFrames
"""
if not candles:
logger.warning("Indicator Definitions: No candles provided for indicator calculation")
@@ -520,6 +521,7 @@ def calculate_indicators(candles: List[Dict[str, Any]],
# Calculate indicators
try:
results = indicators_calc.calculate_multiple_indicators(ohlcv_candles, configs_to_calculate)
# results is now a dict of DataFrames
logger.debug(f"Indicator Definitions: Calculated {len(results)} indicators successfully")
return results

View File

@@ -466,7 +466,9 @@ class MarketDataIntegrator:
symbol: str,
exchange: str = "okx"
) -> Dict[str, pd.DataFrame]:
"""
Get indicator data for chart display. Returns a dict mapping indicator IDs to DataFrames.
"""
indicator_data_map = {}
if main_df.empty:
return indicator_data_map
@@ -504,27 +506,14 @@ class MarketDataIntegrator:
# Use main chart's dataframe
indicator_df = main_df
# Calculate the indicator
indicator_result_pkg = self.indicators.calculate(
# Calculate the indicator (now returns DataFrame)
result_df = self.indicators.calculate(
indicator.type,
indicator_df,
**indicator.parameters
)
if indicator_result_pkg and indicator_result_pkg.get('data'):
indicator_results = indicator_result_pkg['data']
if not indicator_results:
self.logger.warning(f"Indicator '{indicator.name}' produced no results.")
continue
result_df = pd.DataFrame([
{'timestamp': r.timestamp, **r.values}
for r in indicator_results
])
result_df['timestamp'] = pd.to_datetime(result_df['timestamp'])
result_df.set_index('timestamp', inplace=True)
if result_df is not None and not result_df.empty:
# Ensure timezone consistency before reindexing
if result_df.index.tz is None:
result_df = result_df.tz_localize('UTC')