Vasily.onl ec8f5514bb 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.
2025-06-09 16:28:16 +08:00

52 lines
2.2 KiB
Python

"""
Moving Average Convergence Divergence (MACD) indicator implementation.
"""
import pandas as pd
from ..base import BaseIndicator
class MACDIndicator(BaseIndicator):
"""
Moving Average Convergence Divergence (MACD) technical indicator.
Calculates trend-following momentum indicator that shows the relationship
between two moving averages of a security's price.
Handles sparse data appropriately without interpolation.
"""
def calculate(self, df: pd.DataFrame, fast_period: int = 12,
slow_period: int = 26, signal_period: int = 9,
price_column: str = 'close') -> pd.DataFrame:
"""
Calculate Moving Average Convergence Divergence (MACD).
Args:
df: DataFrame with OHLCV data
fast_period: Fast EMA period (default 12)
slow_period: Slow EMA period (default 26)
signal_period: Signal line EMA period (default 9)
price_column: Price column to use ('open', 'high', 'low', 'close')
Returns:
DataFrame with MACD values and metadata, indexed by timestamp
"""
# Validate input data
if not self.validate_dataframe(df, slow_period):
return pd.DataFrame()
try:
df = df.copy()
df['macd'] = df[price_column].ewm(span=fast_period, adjust=False).mean() - \
df[price_column].ewm(span=slow_period, adjust=False).mean()
df['signal'] = df['macd'].ewm(span=signal_period, adjust=False).mean()
df['histogram'] = df['macd'] - df['signal']
# Only keep rows with valid MACD, and only 'timestamp', 'macd', 'signal', 'histogram' columns
result_df = df.loc[df['macd'].notna() & df['signal'].notna() & df['histogram'].notna(), ['timestamp', 'macd', 'signal', 'histogram']].copy()
# Only keep rows after enough data for MACD and signal
min_required = max(slow_period, signal_period)
result_df = result_df.iloc[min_required-1:]
result_df.set_index('timestamp', inplace=True)
return result_df
except Exception:
return pd.DataFrame()