- 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.
46 lines
1.9 KiB
Python
46 lines
1.9 KiB
Python
"""
|
|
Bollinger Bands indicator implementation.
|
|
"""
|
|
|
|
import pandas as pd
|
|
|
|
from ..base import BaseIndicator
|
|
|
|
|
|
class BollingerBandsIndicator(BaseIndicator):
|
|
"""
|
|
Bollinger Bands technical indicator.
|
|
|
|
Calculates a set of lines plotted two standard deviations away from a simple moving average.
|
|
Handles sparse data appropriately without interpolation.
|
|
"""
|
|
|
|
def calculate(self, df: pd.DataFrame, period: int = 20,
|
|
std_dev: float = 2.0, price_column: str = 'close') -> pd.DataFrame:
|
|
"""
|
|
Calculate Bollinger Bands.
|
|
|
|
Args:
|
|
df: DataFrame with OHLCV data
|
|
period: Number of periods for moving average (default 20)
|
|
std_dev: Number of standard deviations (default 2.0)
|
|
price_column: Price column to use ('open', 'high', 'low', 'close')
|
|
|
|
Returns:
|
|
DataFrame with Bollinger Bands values and metadata, indexed by timestamp
|
|
"""
|
|
# Validate input data
|
|
if not self.validate_dataframe(df, period):
|
|
return pd.DataFrame()
|
|
try:
|
|
df = df.copy()
|
|
df['middle_band'] = df[price_column].rolling(window=period, min_periods=period).mean()
|
|
df['std'] = df[price_column].rolling(window=period, min_periods=period).std()
|
|
df['upper_band'] = df['middle_band'] + (df['std'] * std_dev)
|
|
df['lower_band'] = df['middle_band'] - (df['std'] * std_dev)
|
|
# Only keep rows with valid bands, and only 'timestamp', 'upper_band', 'middle_band', 'lower_band' columns
|
|
result_df = df.loc[df['middle_band'].notna() & df['upper_band'].notna() & df['lower_band'].notna(), ['timestamp', 'upper_band', 'middle_band', 'lower_band']].copy()
|
|
result_df.set_index('timestamp', inplace=True)
|
|
return result_df
|
|
except Exception:
|
|
return pd.DataFrame() |