- Introduced a new strategies module containing the StrategyManager class to orchestrate multiple trading strategies. - Implemented StrategyBase and StrategySignal as foundational components for strategy development. - Added DefaultStrategy for meta-trend analysis and BBRSStrategy for Bollinger Bands + RSI trading. - Enhanced documentation to provide clear usage examples and configuration guidelines for the new system. - Established a modular architecture to support future strategy additions and improvements.
162 lines
5.6 KiB
Python
162 lines
5.6 KiB
Python
"""
|
|
Base classes for the strategy management system.
|
|
|
|
This module contains the fundamental building blocks for all trading strategies:
|
|
- StrategySignal: Represents trading signals with confidence and metadata
|
|
- StrategyBase: Abstract base class that all strategies must inherit from
|
|
"""
|
|
|
|
from abc import ABC, abstractmethod
|
|
from typing import Dict, Optional
|
|
|
|
|
|
class StrategySignal:
|
|
"""
|
|
Represents a trading signal from a strategy.
|
|
|
|
A signal encapsulates the strategy's recommendation along with confidence
|
|
level, optional price target, and additional metadata.
|
|
|
|
Attributes:
|
|
signal_type (str): Type of signal - "ENTRY", "EXIT", or "HOLD"
|
|
confidence (float): Confidence level from 0.0 to 1.0
|
|
price (Optional[float]): Optional specific price for the signal
|
|
metadata (Dict): Additional signal data and context
|
|
|
|
Example:
|
|
# Entry signal with high confidence
|
|
signal = StrategySignal("ENTRY", confidence=0.8)
|
|
|
|
# Exit signal with stop loss price
|
|
signal = StrategySignal("EXIT", confidence=1.0, price=50000,
|
|
metadata={"type": "STOP_LOSS"})
|
|
"""
|
|
|
|
def __init__(self, signal_type: str, confidence: float = 1.0,
|
|
price: Optional[float] = None, metadata: Optional[Dict] = None):
|
|
"""
|
|
Initialize a strategy signal.
|
|
|
|
Args:
|
|
signal_type: Type of signal ("ENTRY", "EXIT", "HOLD")
|
|
confidence: Confidence level (0.0 to 1.0)
|
|
price: Optional specific price for the signal
|
|
metadata: Additional signal data and context
|
|
"""
|
|
self.signal_type = signal_type
|
|
self.confidence = max(0.0, min(1.0, confidence)) # Clamp to [0,1]
|
|
self.price = price
|
|
self.metadata = metadata or {}
|
|
|
|
def __repr__(self) -> str:
|
|
"""String representation of the signal."""
|
|
return (f"StrategySignal(type={self.signal_type}, "
|
|
f"confidence={self.confidence:.2f}, "
|
|
f"price={self.price}, metadata={self.metadata})")
|
|
|
|
|
|
class StrategyBase(ABC):
|
|
"""
|
|
Abstract base class for all trading strategies.
|
|
|
|
This class defines the interface that all strategies must implement:
|
|
- initialize(): Setup strategy with backtester data
|
|
- get_entry_signal(): Generate entry signals
|
|
- get_exit_signal(): Generate exit signals
|
|
- get_confidence(): Optional confidence calculation
|
|
|
|
Attributes:
|
|
name (str): Strategy name
|
|
weight (float): Strategy weight for combination
|
|
params (Dict): Strategy parameters
|
|
initialized (bool): Whether strategy has been initialized
|
|
|
|
Example:
|
|
class MyStrategy(StrategyBase):
|
|
def initialize(self, backtester):
|
|
# Setup strategy indicators
|
|
self.initialized = True
|
|
|
|
def get_entry_signal(self, backtester, df_index):
|
|
# Return StrategySignal based on analysis
|
|
if should_enter:
|
|
return StrategySignal("ENTRY", confidence=0.7)
|
|
return StrategySignal("HOLD", confidence=0.0)
|
|
"""
|
|
|
|
def __init__(self, name: str, weight: float = 1.0, params: Optional[Dict] = None):
|
|
"""
|
|
Initialize the strategy base.
|
|
|
|
Args:
|
|
name: Strategy name/identifier
|
|
weight: Strategy weight for combination (default: 1.0)
|
|
params: Strategy-specific parameters
|
|
"""
|
|
self.name = name
|
|
self.weight = weight
|
|
self.params = params or {}
|
|
self.initialized = False
|
|
|
|
@abstractmethod
|
|
def initialize(self, backtester) -> None:
|
|
"""
|
|
Initialize strategy with backtester data.
|
|
|
|
This method is called once before backtesting begins.
|
|
Strategies should setup indicators, validate data, and
|
|
set self.initialized = True when complete.
|
|
|
|
Args:
|
|
backtester: Backtest instance with data and configuration
|
|
"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def get_entry_signal(self, backtester, df_index: int) -> StrategySignal:
|
|
"""
|
|
Generate entry signal for the given data index.
|
|
|
|
Args:
|
|
backtester: Backtest instance with current state
|
|
df_index: Current index in the dataframe
|
|
|
|
Returns:
|
|
StrategySignal: Entry signal with confidence level
|
|
"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def get_exit_signal(self, backtester, df_index: int) -> StrategySignal:
|
|
"""
|
|
Generate exit signal for the given data index.
|
|
|
|
Args:
|
|
backtester: Backtest instance with current state
|
|
df_index: Current index in the dataframe
|
|
|
|
Returns:
|
|
StrategySignal: Exit signal with confidence level
|
|
"""
|
|
pass
|
|
|
|
def get_confidence(self, backtester, df_index: int) -> float:
|
|
"""
|
|
Get strategy confidence for the current market state.
|
|
|
|
Default implementation returns 1.0. Strategies can override
|
|
this to provide dynamic confidence based on market conditions.
|
|
|
|
Args:
|
|
backtester: Backtest instance with current state
|
|
df_index: Current index in the dataframe
|
|
|
|
Returns:
|
|
float: Confidence level (0.0 to 1.0)
|
|
"""
|
|
return 1.0
|
|
|
|
def __repr__(self) -> str:
|
|
"""String representation of the strategy."""
|
|
return (f"{self.__class__.__name__}(name={self.name}, "
|
|
f"weight={self.weight}, initialized={self.initialized})") |