Enhance Bollinger Bands validation and add DatetimeIndex handling in strategies
- Added validation to ensure the specified price column exists in the DataFrame for Bollinger Bands calculations. - Introduced a new method to ensure the DataFrame has a proper DatetimeIndex, improving time-series operations in strategy processing. - Updated strategy run method to call the new DatetimeIndex validation method before processing data. - Improved logging for better traceability of data transformations and potential issues.
This commit is contained in:
parent
e5c2988d71
commit
7af8cdcb32
@ -37,12 +37,13 @@ class BollingerBands:
|
||||
'UpperBand',
|
||||
'LowerBand'.
|
||||
"""
|
||||
if price_column not in data_df.columns:
|
||||
raise ValueError(f"Price column '{price_column}' not found in DataFrame.")
|
||||
|
||||
# Work on a copy to avoid modifying the original DataFrame passed to the function
|
||||
data_df = data_df.copy()
|
||||
|
||||
if price_column not in data_df.columns:
|
||||
raise ValueError(f"Price column '{price_column}' not found in DataFrame.")
|
||||
|
||||
if not squeeze:
|
||||
period = self.config['bb_period']
|
||||
bb_width_threshold = self.config['bb_width']
|
||||
|
||||
@ -14,7 +14,56 @@ class Strategy:
|
||||
self.config = config
|
||||
self.logging = logging
|
||||
|
||||
def _ensure_datetime_index(self, data):
|
||||
"""
|
||||
Ensure the DataFrame has a DatetimeIndex for proper time-series operations.
|
||||
If the DataFrame has a 'timestamp' column but not a DatetimeIndex, convert it.
|
||||
|
||||
Args:
|
||||
data (DataFrame): Input DataFrame
|
||||
|
||||
Returns:
|
||||
DataFrame: DataFrame with proper DatetimeIndex
|
||||
"""
|
||||
if data.empty:
|
||||
return data
|
||||
|
||||
# Check if we have a DatetimeIndex already
|
||||
if isinstance(data.index, pd.DatetimeIndex):
|
||||
return data
|
||||
|
||||
# Check if we have a 'timestamp' column that we can use as index
|
||||
if 'timestamp' in data.columns:
|
||||
data_copy = data.copy()
|
||||
# Convert timestamp column to datetime if it's not already
|
||||
if not pd.api.types.is_datetime64_any_dtype(data_copy['timestamp']):
|
||||
data_copy['timestamp'] = pd.to_datetime(data_copy['timestamp'])
|
||||
# Set timestamp as index and drop the column
|
||||
data_copy = data_copy.set_index('timestamp')
|
||||
if self.logging:
|
||||
self.logging.info("Converted 'timestamp' column to DatetimeIndex for strategy processing.")
|
||||
return data_copy
|
||||
|
||||
# If we have a regular index but it might be datetime strings, try to convert
|
||||
try:
|
||||
if data.index.dtype == 'object':
|
||||
data_copy = data.copy()
|
||||
data_copy.index = pd.to_datetime(data_copy.index)
|
||||
if self.logging:
|
||||
self.logging.info("Converted index to DatetimeIndex for strategy processing.")
|
||||
return data_copy
|
||||
except:
|
||||
pass
|
||||
|
||||
# If we can't create a proper DatetimeIndex, warn and return as-is
|
||||
if self.logging:
|
||||
self.logging.warning("Could not create DatetimeIndex for strategy processing. Time-based operations may fail.")
|
||||
return data
|
||||
|
||||
def run(self, data, strategy_name):
|
||||
# Ensure proper DatetimeIndex before processing
|
||||
data = self._ensure_datetime_index(data)
|
||||
|
||||
if strategy_name == "MarketRegimeStrategy":
|
||||
result = self.MarketRegimeStrategy(data)
|
||||
return self.standardize_output(result, strategy_name)
|
||||
@ -126,8 +175,8 @@ class Strategy:
|
||||
DataFrame: A unified DataFrame containing original data, BB, RSI, and signals.
|
||||
"""
|
||||
|
||||
# data = aggregate_to_hourly(data, 4)
|
||||
data = aggregate_to_daily(data)
|
||||
data = aggregate_to_hourly(data, 1)
|
||||
# data = aggregate_to_daily(data)
|
||||
|
||||
# Calculate Bollinger Bands
|
||||
bb_calculator = BollingerBands(config=self.config)
|
||||
@ -264,6 +313,8 @@ class Strategy:
|
||||
self.logging.warning("CryptoTradingStrategy: Input data is empty or missing 'close'/'volume' columns.")
|
||||
return pd.DataFrame() # Return empty DataFrame if essential data is missing
|
||||
|
||||
print(f"data: {data.head()}")
|
||||
|
||||
# Aggregate data
|
||||
data_15m = aggregate_to_minutes(data.copy(), 15)
|
||||
data_1h = aggregate_to_hourly(data.copy(), 1)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user