- Introduced a new Strategy class to encapsulate trading strategies, including the Market Regime Strategy that adapts to different market conditions. - Refactored BollingerBands and RSI classes to accept configuration parameters for improved flexibility and maintainability. - Updated test_bbrsi.py to utilize the new strategy implementation and adjusted date ranges for testing. - Enhanced documentation to include details about the new Strategy class and its components.
76 lines
3.4 KiB
Python
76 lines
3.4 KiB
Python
import pandas as pd
|
|
|
|
class BollingerBands:
|
|
"""
|
|
Calculates Bollinger Bands for given financial data.
|
|
"""
|
|
def __init__(self, config):
|
|
"""
|
|
Initializes the BollingerBands calculator.
|
|
|
|
Args:
|
|
period (int): The period for the moving average and standard deviation.
|
|
std_dev_multiplier (float): The number of standard deviations for the upper and lower bands.
|
|
bb_width (float): The width of the Bollinger Bands.
|
|
"""
|
|
if config['bb_period'] <= 0:
|
|
raise ValueError("Period must be a positive integer.")
|
|
if config['trending']['bb_std_dev_multiplier'] <= 0 or config['sideways']['bb_std_dev_multiplier'] <= 0:
|
|
raise ValueError("Standard deviation multiplier must be positive.")
|
|
if config['bb_width'] <= 0:
|
|
raise ValueError("BB width must be positive.")
|
|
|
|
self.config = config
|
|
|
|
def calculate(self, data_df: pd.DataFrame, price_column: str = 'close', squeeze = False) -> pd.DataFrame:
|
|
"""
|
|
Calculates Bollinger Bands and adds them to the DataFrame.
|
|
|
|
Args:
|
|
data_df (pd.DataFrame): DataFrame with price data. Must include the price_column.
|
|
price_column (str): The name of the column containing the price data (e.g., 'close').
|
|
|
|
Returns:
|
|
pd.DataFrame: The original DataFrame with added columns:
|
|
'SMA' (Simple Moving Average),
|
|
'UpperBand',
|
|
'LowerBand'.
|
|
"""
|
|
if price_column not in data_df.columns:
|
|
raise ValueError(f"Price column '{price_column}' not found in DataFrame.")
|
|
|
|
if not squeeze:
|
|
# Calculate SMA
|
|
data_df['SMA'] = data_df[price_column].rolling(window=self.config['bb_period']).mean()
|
|
|
|
# Calculate Standard Deviation
|
|
std_dev = data_df[price_column].rolling(window=self.config['bb_period']).std()
|
|
|
|
# Calculate Upper and Lower Bands
|
|
data_df['UpperBand'] = data_df['SMA'] + (2.0* std_dev)
|
|
data_df['LowerBand'] = data_df['SMA'] - (2.0* std_dev)
|
|
|
|
# Calculate the width of the Bollinger Bands
|
|
data_df['BBWidth'] = (data_df['UpperBand'] - data_df['LowerBand']) / data_df['SMA']
|
|
|
|
# Calculate the market regime
|
|
# 1 = sideways, 0 = trending
|
|
data_df['MarketRegime'] = (data_df['BBWidth'] < self.config['bb_width']).astype(int)
|
|
|
|
if data_df['MarketRegime'].sum() > 0:
|
|
data_df['UpperBand'] = data_df['SMA'] + (self.config['trending']['bb_std_dev_multiplier'] * std_dev)
|
|
data_df['LowerBand'] = data_df['SMA'] - (self.config['trending']['bb_std_dev_multiplier'] * std_dev)
|
|
else:
|
|
data_df['UpperBand'] = data_df['SMA'] + (self.config['sideways']['bb_std_dev_multiplier'] * std_dev)
|
|
data_df['LowerBand'] = data_df['SMA'] - (self.config['sideways']['bb_std_dev_multiplier'] * std_dev)
|
|
|
|
else:
|
|
data_df['SMA'] = data_df[price_column].rolling(window=14).mean()
|
|
# Calculate Standard Deviation
|
|
std_dev = data_df[price_column].rolling(window=14).std()
|
|
# Calculate Upper and Lower Bands
|
|
data_df['UpperBand'] = data_df['SMA'] + 1.5* std_dev
|
|
data_df['LowerBand'] = data_df['SMA'] - 1.5* std_dev
|
|
|
|
return data_df
|