640 lines
22 KiB
Python
640 lines
22 KiB
Python
"""
|
|
Strategy-Specific Chart Configuration System
|
|
|
|
This module provides complete chart configurations for different trading strategies,
|
|
including indicator combinations, chart layouts, subplot arrangements, and display settings.
|
|
"""
|
|
|
|
from typing import Dict, List, Any, Optional, Union
|
|
from dataclasses import dataclass, field
|
|
from enum import Enum
|
|
import json
|
|
from datetime import datetime
|
|
|
|
from .indicator_defs import ChartIndicatorConfig, create_indicator_config, validate_indicator_configuration
|
|
from .defaults import (
|
|
TradingStrategy,
|
|
IndicatorCategory,
|
|
get_all_default_indicators,
|
|
get_strategy_indicators,
|
|
get_strategy_info
|
|
)
|
|
from utils.logger import get_logger
|
|
|
|
# Initialize logger
|
|
logger = get_logger()
|
|
|
|
|
|
class ChartLayout(str, Enum):
|
|
"""Chart layout types."""
|
|
SINGLE_CHART = "single_chart"
|
|
MAIN_WITH_SUBPLOTS = "main_with_subplots"
|
|
MULTI_CHART = "multi_chart"
|
|
GRID_LAYOUT = "grid_layout"
|
|
|
|
|
|
class SubplotType(str, Enum):
|
|
"""Types of subplots available."""
|
|
VOLUME = "volume"
|
|
RSI = "rsi"
|
|
MACD = "macd"
|
|
MOMENTUM = "momentum"
|
|
CUSTOM = "custom"
|
|
|
|
|
|
@dataclass
|
|
class SubplotConfig:
|
|
"""Configuration for a chart subplot."""
|
|
subplot_type: SubplotType
|
|
height_ratio: float = 0.3
|
|
indicators: List[str] = field(default_factory=list)
|
|
title: Optional[str] = None
|
|
y_axis_label: Optional[str] = None
|
|
show_grid: bool = True
|
|
show_legend: bool = True
|
|
background_color: Optional[str] = None
|
|
|
|
|
|
@dataclass
|
|
class ChartStyle:
|
|
"""Chart styling configuration."""
|
|
theme: str = "plotly_white"
|
|
background_color: str = "#ffffff"
|
|
grid_color: str = "#e6e6e6"
|
|
text_color: str = "#2c3e50"
|
|
font_family: str = "Arial, sans-serif"
|
|
font_size: int = 12
|
|
candlestick_up_color: str = "#26a69a"
|
|
candlestick_down_color: str = "#ef5350"
|
|
volume_color: str = "#78909c"
|
|
show_volume: bool = True
|
|
show_grid: bool = True
|
|
show_legend: bool = True
|
|
show_toolbar: bool = True
|
|
|
|
|
|
@dataclass
|
|
class StrategyChartConfig:
|
|
"""Complete chart configuration for a trading strategy."""
|
|
strategy_name: str
|
|
strategy_type: TradingStrategy
|
|
description: str
|
|
timeframes: List[str]
|
|
|
|
# Chart layout
|
|
layout: ChartLayout = ChartLayout.MAIN_WITH_SUBPLOTS
|
|
main_chart_height: float = 0.7
|
|
|
|
# Indicators
|
|
overlay_indicators: List[str] = field(default_factory=list)
|
|
subplot_configs: List[SubplotConfig] = field(default_factory=list)
|
|
|
|
# Style
|
|
chart_style: ChartStyle = field(default_factory=ChartStyle)
|
|
|
|
# Metadata
|
|
created_at: Optional[datetime] = None
|
|
updated_at: Optional[datetime] = None
|
|
version: str = "1.0"
|
|
tags: List[str] = field(default_factory=list)
|
|
|
|
def validate(self) -> tuple[bool, List[str]]:
|
|
"""
|
|
Validate the strategy chart configuration.
|
|
|
|
Returns:
|
|
Tuple of (is_valid, list_of_error_messages)
|
|
"""
|
|
# Use the new comprehensive validation system
|
|
from .validation import validate_configuration
|
|
|
|
try:
|
|
report = validate_configuration(self)
|
|
|
|
# Convert validation report to simple format for backward compatibility
|
|
error_messages = [str(issue) for issue in report.errors]
|
|
return report.is_valid, error_messages
|
|
|
|
except ImportError:
|
|
# Fallback to original validation if new system unavailable
|
|
logger.warning("Strategy Charts: Enhanced validation system unavailable, using basic validation")
|
|
return self._basic_validate()
|
|
except Exception as e:
|
|
logger.error(f"Strategy Charts: Validation error: {e}")
|
|
return False, [f"Strategy Charts: Validation system error: {e}"]
|
|
|
|
def validate_comprehensive(self) -> 'ValidationReport':
|
|
"""
|
|
Perform comprehensive validation with detailed reporting.
|
|
|
|
Returns:
|
|
Detailed validation report with errors, warnings, and suggestions
|
|
"""
|
|
from .validation import validate_configuration
|
|
return validate_configuration(self)
|
|
|
|
def _basic_validate(self) -> tuple[bool, List[str]]:
|
|
"""
|
|
Basic validation method (fallback).
|
|
|
|
Returns:
|
|
Tuple of (is_valid, list_of_error_messages)
|
|
"""
|
|
errors = []
|
|
|
|
# Validate basic fields
|
|
if not self.strategy_name:
|
|
errors.append("Strategy name is required")
|
|
|
|
if not isinstance(self.strategy_type, TradingStrategy):
|
|
errors.append("Invalid strategy type")
|
|
|
|
if not self.timeframes:
|
|
errors.append("At least one timeframe must be specified")
|
|
|
|
# Validate height ratios
|
|
total_subplot_height = sum(config.height_ratio for config in self.subplot_configs)
|
|
if self.main_chart_height + total_subplot_height > 1.0:
|
|
errors.append("Total chart height ratios exceed 1.0")
|
|
|
|
if self.main_chart_height <= 0 or self.main_chart_height > 1.0:
|
|
errors.append("Main chart height must be between 0 and 1.0")
|
|
|
|
# Validate indicators exist
|
|
try:
|
|
all_default_indicators = get_all_default_indicators()
|
|
|
|
for indicator_name in self.overlay_indicators:
|
|
if indicator_name not in all_default_indicators:
|
|
errors.append(f"Overlay indicator '{indicator_name}' not found in defaults")
|
|
|
|
for subplot_config in self.subplot_configs:
|
|
for indicator_name in subplot_config.indicators:
|
|
if indicator_name not in all_default_indicators:
|
|
errors.append(f"Subplot indicator '{indicator_name}' not found in defaults")
|
|
except Exception as e:
|
|
logger.warning(f"Strategy Charts: Could not validate indicator existence: {e}")
|
|
|
|
# Validate subplot height ratios
|
|
for i, subplot_config in enumerate(self.subplot_configs):
|
|
if subplot_config.height_ratio <= 0 or subplot_config.height_ratio > 1.0:
|
|
errors.append(f"Subplot {i} height ratio must be between 0 and 1.0")
|
|
|
|
return len(errors) == 0, errors
|
|
|
|
def get_all_indicators(self) -> List[str]:
|
|
"""Get all indicators used in this strategy configuration."""
|
|
all_indicators = list(self.overlay_indicators)
|
|
for subplot_config in self.subplot_configs:
|
|
all_indicators.extend(subplot_config.indicators)
|
|
return list(set(all_indicators))
|
|
|
|
def get_indicator_configs(self) -> Dict[str, ChartIndicatorConfig]:
|
|
"""
|
|
Get the actual indicator configuration objects for all indicators.
|
|
|
|
Returns:
|
|
Dictionary mapping indicator names to their configurations
|
|
"""
|
|
all_default_indicators = get_all_default_indicators()
|
|
indicator_configs = {}
|
|
|
|
for indicator_name in self.get_all_indicators():
|
|
if indicator_name in all_default_indicators:
|
|
preset = all_default_indicators[indicator_name]
|
|
indicator_configs[indicator_name] = preset.config
|
|
|
|
return indicator_configs
|
|
|
|
|
|
def create_default_strategy_configurations() -> Dict[str, StrategyChartConfig]:
|
|
"""Create default chart configurations for all trading strategies."""
|
|
strategy_configs = {}
|
|
|
|
# Scalping Strategy
|
|
strategy_configs["scalping"] = StrategyChartConfig(
|
|
strategy_name="Scalping Strategy",
|
|
strategy_type=TradingStrategy.SCALPING,
|
|
description="Fast-paced trading with quick entry/exit on 1-5 minute charts",
|
|
timeframes=["1m", "5m"],
|
|
layout=ChartLayout.MAIN_WITH_SUBPLOTS,
|
|
main_chart_height=0.6,
|
|
overlay_indicators=["ema_5", "ema_12", "ema_21", "bb_10_15"],
|
|
subplot_configs=[
|
|
SubplotConfig(
|
|
subplot_type=SubplotType.RSI,
|
|
height_ratio=0.2,
|
|
indicators=["rsi_7"],
|
|
title="RSI (7)",
|
|
y_axis_label="RSI",
|
|
show_grid=True
|
|
),
|
|
SubplotConfig(
|
|
subplot_type=SubplotType.MACD,
|
|
height_ratio=0.2,
|
|
indicators=["macd_5_13_4"],
|
|
title="MACD Fast",
|
|
y_axis_label="MACD",
|
|
show_grid=True
|
|
)
|
|
],
|
|
chart_style=ChartStyle(
|
|
theme="plotly_white",
|
|
font_size=10,
|
|
show_volume=True,
|
|
candlestick_up_color="#00d4aa",
|
|
candlestick_down_color="#fe6a85"
|
|
),
|
|
tags=["scalping", "short-term", "fast"]
|
|
)
|
|
|
|
# Day Trading Strategy
|
|
strategy_configs["day_trading"] = StrategyChartConfig(
|
|
strategy_name="Day Trading Strategy",
|
|
strategy_type=TradingStrategy.DAY_TRADING,
|
|
description="Intraday trading with balanced indicator mix for 5m-1h charts",
|
|
timeframes=["5m", "15m", "1h"],
|
|
layout=ChartLayout.MAIN_WITH_SUBPLOTS,
|
|
main_chart_height=0.65,
|
|
overlay_indicators=["sma_20", "ema_12", "ema_26", "bb_20_20"],
|
|
subplot_configs=[
|
|
SubplotConfig(
|
|
subplot_type=SubplotType.RSI,
|
|
height_ratio=0.15,
|
|
indicators=["rsi_14"],
|
|
title="RSI (14)",
|
|
y_axis_label="RSI"
|
|
),
|
|
SubplotConfig(
|
|
subplot_type=SubplotType.MACD,
|
|
height_ratio=0.2,
|
|
indicators=["macd_12_26_9"],
|
|
title="MACD",
|
|
y_axis_label="MACD"
|
|
)
|
|
],
|
|
chart_style=ChartStyle(
|
|
theme="plotly_white",
|
|
font_size=12,
|
|
show_volume=True
|
|
),
|
|
tags=["day-trading", "intraday", "balanced"]
|
|
)
|
|
|
|
# Swing Trading Strategy
|
|
strategy_configs["swing_trading"] = StrategyChartConfig(
|
|
strategy_name="Swing Trading Strategy",
|
|
strategy_type=TradingStrategy.SWING_TRADING,
|
|
description="Medium-term trading for multi-day holds on 1h-1d charts",
|
|
timeframes=["1h", "4h", "1d"],
|
|
layout=ChartLayout.MAIN_WITH_SUBPLOTS,
|
|
main_chart_height=0.7,
|
|
overlay_indicators=["sma_50", "ema_21", "ema_50", "bb_20_20"],
|
|
subplot_configs=[
|
|
SubplotConfig(
|
|
subplot_type=SubplotType.RSI,
|
|
height_ratio=0.15,
|
|
indicators=["rsi_14", "rsi_21"],
|
|
title="RSI Comparison",
|
|
y_axis_label="RSI"
|
|
),
|
|
SubplotConfig(
|
|
subplot_type=SubplotType.MACD,
|
|
height_ratio=0.15,
|
|
indicators=["macd_12_26_9"],
|
|
title="MACD",
|
|
y_axis_label="MACD"
|
|
)
|
|
],
|
|
chart_style=ChartStyle(
|
|
theme="plotly_white",
|
|
font_size=12,
|
|
show_volume=True
|
|
),
|
|
tags=["swing-trading", "medium-term", "multi-day"]
|
|
)
|
|
|
|
# Position Trading Strategy
|
|
strategy_configs["position_trading"] = StrategyChartConfig(
|
|
strategy_name="Position Trading Strategy",
|
|
strategy_type=TradingStrategy.POSITION_TRADING,
|
|
description="Long-term trading for weeks/months holds on 4h-1w charts",
|
|
timeframes=["4h", "1d", "1w"],
|
|
layout=ChartLayout.MAIN_WITH_SUBPLOTS,
|
|
main_chart_height=0.75,
|
|
overlay_indicators=["sma_100", "sma_200", "ema_50", "ema_100", "bb_50_20"],
|
|
subplot_configs=[
|
|
SubplotConfig(
|
|
subplot_type=SubplotType.RSI,
|
|
height_ratio=0.12,
|
|
indicators=["rsi_21"],
|
|
title="RSI (21)",
|
|
y_axis_label="RSI"
|
|
),
|
|
SubplotConfig(
|
|
subplot_type=SubplotType.MACD,
|
|
height_ratio=0.13,
|
|
indicators=["macd_19_39_13"],
|
|
title="MACD Slow",
|
|
y_axis_label="MACD"
|
|
)
|
|
],
|
|
chart_style=ChartStyle(
|
|
theme="plotly_white",
|
|
font_size=14,
|
|
show_volume=False # Less important for long-term
|
|
),
|
|
tags=["position-trading", "long-term", "weeks-months"]
|
|
)
|
|
|
|
# Momentum Strategy
|
|
strategy_configs["momentum"] = StrategyChartConfig(
|
|
strategy_name="Momentum Strategy",
|
|
strategy_type=TradingStrategy.MOMENTUM,
|
|
description="Trend-following momentum strategy for strong directional moves",
|
|
timeframes=["15m", "1h", "4h"],
|
|
layout=ChartLayout.MAIN_WITH_SUBPLOTS,
|
|
main_chart_height=0.6,
|
|
overlay_indicators=["ema_12", "ema_26"],
|
|
subplot_configs=[
|
|
SubplotConfig(
|
|
subplot_type=SubplotType.RSI,
|
|
height_ratio=0.15,
|
|
indicators=["rsi_7", "rsi_14"],
|
|
title="RSI Momentum",
|
|
y_axis_label="RSI"
|
|
),
|
|
SubplotConfig(
|
|
subplot_type=SubplotType.MACD,
|
|
height_ratio=0.25,
|
|
indicators=["macd_8_17_6", "macd_12_26_9"],
|
|
title="MACD Momentum",
|
|
y_axis_label="MACD"
|
|
)
|
|
],
|
|
chart_style=ChartStyle(
|
|
theme="plotly_white",
|
|
font_size=12,
|
|
candlestick_up_color="#26a69a",
|
|
candlestick_down_color="#ef5350"
|
|
),
|
|
tags=["momentum", "trend-following", "directional"]
|
|
)
|
|
|
|
# Mean Reversion Strategy
|
|
strategy_configs["mean_reversion"] = StrategyChartConfig(
|
|
strategy_name="Mean Reversion Strategy",
|
|
strategy_type=TradingStrategy.MEAN_REVERSION,
|
|
description="Counter-trend strategy for oversold/overbought conditions",
|
|
timeframes=["15m", "1h", "4h"],
|
|
layout=ChartLayout.MAIN_WITH_SUBPLOTS,
|
|
main_chart_height=0.65,
|
|
overlay_indicators=["sma_20", "sma_50", "bb_20_20", "bb_20_25"],
|
|
subplot_configs=[
|
|
SubplotConfig(
|
|
subplot_type=SubplotType.RSI,
|
|
height_ratio=0.2,
|
|
indicators=["rsi_14", "rsi_21"],
|
|
title="RSI Mean Reversion",
|
|
y_axis_label="RSI"
|
|
),
|
|
SubplotConfig(
|
|
subplot_type=SubplotType.VOLUME,
|
|
height_ratio=0.15,
|
|
indicators=[],
|
|
title="Volume",
|
|
y_axis_label="Volume"
|
|
)
|
|
],
|
|
chart_style=ChartStyle(
|
|
theme="plotly_white",
|
|
font_size=12,
|
|
show_volume=True
|
|
),
|
|
tags=["mean-reversion", "counter-trend", "oversold-overbought"]
|
|
)
|
|
|
|
return strategy_configs
|
|
|
|
|
|
def validate_strategy_configuration(config: StrategyChartConfig) -> tuple[bool, List[str]]:
|
|
"""
|
|
Validate a strategy chart configuration.
|
|
|
|
Args:
|
|
config: Strategy chart configuration to validate
|
|
|
|
Returns:
|
|
Tuple of (is_valid, list_of_error_messages)
|
|
"""
|
|
return config.validate()
|
|
|
|
|
|
def create_custom_strategy_config(
|
|
strategy_name: str,
|
|
strategy_type: TradingStrategy,
|
|
description: str,
|
|
timeframes: List[str],
|
|
overlay_indicators: List[str],
|
|
subplot_configs: List[Dict[str, Any]],
|
|
chart_style: Optional[Dict[str, Any]] = None,
|
|
**kwargs
|
|
) -> tuple[Optional[StrategyChartConfig], List[str]]:
|
|
"""
|
|
Create a custom strategy chart configuration.
|
|
|
|
Args:
|
|
strategy_name: Name of the strategy
|
|
strategy_type: Type of trading strategy
|
|
description: Strategy description
|
|
timeframes: List of recommended timeframes
|
|
overlay_indicators: List of overlay indicator names
|
|
subplot_configs: List of subplot configuration dictionaries
|
|
chart_style: Optional chart style configuration
|
|
**kwargs: Additional configuration options
|
|
|
|
Returns:
|
|
Tuple of (config_object_or_None, list_of_error_messages)
|
|
"""
|
|
try:
|
|
# Create subplot configurations
|
|
subplots = []
|
|
for subplot_data in subplot_configs:
|
|
subplot_type = SubplotType(subplot_data.get("subplot_type", "custom"))
|
|
subplot = SubplotConfig(
|
|
subplot_type=subplot_type,
|
|
height_ratio=subplot_data.get("height_ratio", 0.2),
|
|
indicators=subplot_data.get("indicators", []),
|
|
title=subplot_data.get("title"),
|
|
y_axis_label=subplot_data.get("y_axis_label"),
|
|
show_grid=subplot_data.get("show_grid", True),
|
|
show_legend=subplot_data.get("show_legend", True),
|
|
background_color=subplot_data.get("background_color")
|
|
)
|
|
subplots.append(subplot)
|
|
|
|
# Create chart style
|
|
style = ChartStyle()
|
|
if chart_style:
|
|
for key, value in chart_style.items():
|
|
if hasattr(style, key):
|
|
setattr(style, key, value)
|
|
|
|
# Create configuration
|
|
config = StrategyChartConfig(
|
|
strategy_name=strategy_name,
|
|
strategy_type=strategy_type,
|
|
description=description,
|
|
timeframes=timeframes,
|
|
layout=ChartLayout(kwargs.get("layout", ChartLayout.MAIN_WITH_SUBPLOTS.value)),
|
|
main_chart_height=kwargs.get("main_chart_height", 0.7),
|
|
overlay_indicators=overlay_indicators,
|
|
subplot_configs=subplots,
|
|
chart_style=style,
|
|
created_at=datetime.now(),
|
|
version=kwargs.get("version", "1.0"),
|
|
tags=kwargs.get("tags", [])
|
|
)
|
|
|
|
# Validate configuration
|
|
is_valid, errors = config.validate()
|
|
if not is_valid:
|
|
return None, errors
|
|
|
|
return config, []
|
|
|
|
except Exception as e:
|
|
return None, [f"Error creating strategy configuration: {e}"]
|
|
|
|
|
|
def load_strategy_config_from_json(json_data: Union[str, Dict[str, Any]]) -> tuple[Optional[StrategyChartConfig], List[str]]:
|
|
"""
|
|
Load strategy configuration from JSON data.
|
|
|
|
Args:
|
|
json_data: JSON string or dictionary with configuration data
|
|
|
|
Returns:
|
|
Tuple of (config_object_or_None, list_of_error_messages)
|
|
"""
|
|
try:
|
|
if isinstance(json_data, str):
|
|
data = json.loads(json_data)
|
|
else:
|
|
data = json_data
|
|
|
|
# Extract required fields
|
|
required_fields = ["strategy_name", "strategy_type", "description", "timeframes"]
|
|
missing_fields = [field for field in required_fields if field not in data]
|
|
if missing_fields:
|
|
return None, [f"Missing required fields: {', '.join(missing_fields)}"]
|
|
|
|
# Convert strategy type
|
|
try:
|
|
strategy_type = TradingStrategy(data["strategy_type"])
|
|
except ValueError:
|
|
return None, [f"Invalid strategy type: {data['strategy_type']}"]
|
|
|
|
return create_custom_strategy_config(
|
|
strategy_name=data["strategy_name"],
|
|
strategy_type=strategy_type,
|
|
description=data["description"],
|
|
timeframes=data["timeframes"],
|
|
overlay_indicators=data.get("overlay_indicators", []),
|
|
subplot_configs=data.get("subplot_configs", []),
|
|
chart_style=data.get("chart_style"),
|
|
**{k: v for k, v in data.items() if k not in required_fields + ["overlay_indicators", "subplot_configs", "chart_style"]}
|
|
)
|
|
|
|
except json.JSONDecodeError as e:
|
|
return None, [f"Invalid JSON: {e}"]
|
|
except Exception as e:
|
|
return None, [f"Error loading configuration: {e}"]
|
|
|
|
|
|
def export_strategy_config_to_json(config: StrategyChartConfig) -> str:
|
|
"""
|
|
Export strategy configuration to JSON string.
|
|
|
|
Args:
|
|
config: Strategy configuration to export
|
|
|
|
Returns:
|
|
JSON string representation of the configuration
|
|
"""
|
|
# Convert to dictionary
|
|
config_dict = {
|
|
"strategy_name": config.strategy_name,
|
|
"strategy_type": config.strategy_type.value,
|
|
"description": config.description,
|
|
"timeframes": config.timeframes,
|
|
"layout": config.layout.value,
|
|
"main_chart_height": config.main_chart_height,
|
|
"overlay_indicators": config.overlay_indicators,
|
|
"subplot_configs": [
|
|
{
|
|
"subplot_type": subplot.subplot_type.value,
|
|
"height_ratio": subplot.height_ratio,
|
|
"indicators": subplot.indicators,
|
|
"title": subplot.title,
|
|
"y_axis_label": subplot.y_axis_label,
|
|
"show_grid": subplot.show_grid,
|
|
"show_legend": subplot.show_legend,
|
|
"background_color": subplot.background_color
|
|
}
|
|
for subplot in config.subplot_configs
|
|
],
|
|
"chart_style": {
|
|
"theme": config.chart_style.theme,
|
|
"background_color": config.chart_style.background_color,
|
|
"grid_color": config.chart_style.grid_color,
|
|
"text_color": config.chart_style.text_color,
|
|
"font_family": config.chart_style.font_family,
|
|
"font_size": config.chart_style.font_size,
|
|
"candlestick_up_color": config.chart_style.candlestick_up_color,
|
|
"candlestick_down_color": config.chart_style.candlestick_down_color,
|
|
"volume_color": config.chart_style.volume_color,
|
|
"show_volume": config.chart_style.show_volume,
|
|
"show_grid": config.chart_style.show_grid,
|
|
"show_legend": config.chart_style.show_legend,
|
|
"show_toolbar": config.chart_style.show_toolbar
|
|
},
|
|
"version": config.version,
|
|
"tags": config.tags
|
|
}
|
|
|
|
return json.dumps(config_dict, indent=2)
|
|
|
|
|
|
def get_strategy_config(strategy_name: str) -> Optional[StrategyChartConfig]:
|
|
"""
|
|
Get a default strategy configuration by name.
|
|
|
|
Args:
|
|
strategy_name: Name of the strategy
|
|
|
|
Returns:
|
|
Strategy configuration or None if not found
|
|
"""
|
|
default_configs = create_default_strategy_configurations()
|
|
return default_configs.get(strategy_name)
|
|
|
|
|
|
def get_all_strategy_configs() -> Dict[str, StrategyChartConfig]:
|
|
"""
|
|
Get all default strategy configurations.
|
|
|
|
Returns:
|
|
Dictionary mapping strategy names to their configurations
|
|
"""
|
|
return create_default_strategy_configurations()
|
|
|
|
|
|
def get_available_strategy_names() -> List[str]:
|
|
"""
|
|
Get list of available default strategy names.
|
|
|
|
Returns:
|
|
List of strategy names
|
|
"""
|
|
return list(create_default_strategy_configurations().keys()) |