Enhance strategy output standardization and improve plotting logic

- Introduced a new method to standardize output column names across different strategies, ensuring consistency in data handling and plotting.
- Updated plotting logic in test_bbrsi.py to utilize standardized column names, improving clarity and maintainability.
- Enhanced error handling for missing data in plots and adjusted visual elements for better representation of trading signals.
- Improved the overall structure of strategy implementations to support additional indicators and metadata for better analysis.
This commit is contained in:
Ajasra
2025-05-22 18:16:23 +08:00
parent 3a9dec543c
commit 00873d593f
2 changed files with 107 additions and 39 deletions

View File

@@ -16,14 +16,66 @@ class Strategy:
def run(self, data, strategy_name):
if strategy_name == "MarketRegimeStrategy":
return self.MarketRegimeStrategy(data)
result = self.MarketRegimeStrategy(data)
return self.standardize_output(result, strategy_name)
elif strategy_name == "CryptoTradingStrategy":
return self.CryptoTradingStrategy(data)
result = self.CryptoTradingStrategy(data)
return self.standardize_output(result, strategy_name)
else:
if self.logging is not None:
self.logging.warning(f"Strategy {strategy_name} not found. Using no_strategy instead.")
return self.no_strategy(data)
def standardize_output(self, data, strategy_name):
"""
Standardize column names across different strategies to ensure consistent plotting and analysis
Args:
data (DataFrame): Strategy output DataFrame
strategy_name (str): Name of the strategy that generated this data
Returns:
DataFrame: Data with standardized column names
"""
if data.empty:
return data
# Create a copy to avoid modifying the original
standardized = data.copy()
# Standardize column names based on strategy
if strategy_name == "MarketRegimeStrategy":
# MarketRegimeStrategy already has standard column names for most fields
# Just ensure all standard columns exist
pass
elif strategy_name == "CryptoTradingStrategy":
# Map strategy-specific column names to standard names
column_mapping = {
'UpperBand_15m': 'UpperBand',
'LowerBand_15m': 'LowerBand',
'SMA_15m': 'SMA',
'RSI_15m': 'RSI',
'VolumeMA_15m': 'VolumeMA',
# Keep StopLoss and TakeProfit as they are
}
# Add standard columns from mapped columns
for old_col, new_col in column_mapping.items():
if old_col in standardized.columns and new_col not in standardized.columns:
standardized[new_col] = standardized[old_col]
# Add additional strategy-specific data as metadata columns
if 'UpperBand_1h' in standardized.columns:
standardized['UpperBand_1h_meta'] = standardized['UpperBand_1h']
if 'LowerBand_1h' in standardized.columns:
standardized['LowerBand_1h_meta'] = standardized['LowerBand_1h']
# Ensure all strategies have BBWidth if possible
if 'BBWidth' not in standardized.columns and 'UpperBand' in standardized.columns and 'LowerBand' in standardized.columns:
standardized['BBWidth'] = (standardized['UpperBand'] - standardized['LowerBand']) / standardized['SMA'] if 'SMA' in standardized.columns else np.nan
return standardized
def no_strategy(self, data):
"""No strategy: returns False for both buy and sell conditions"""
buy_condition = pd.Series([False] * len(data), index=data.index)
@@ -74,6 +126,7 @@ class Strategy:
DataFrame: A unified DataFrame containing original data, BB, RSI, and signals.
"""
# data = aggregate_to_hourly(data, 4)
data = aggregate_to_daily(data)
# Calculate Bollinger Bands