2025-05-28 22:37:53 +08:00

22 KiB
Raw Blame History

BBRS Strategy Documentation

Overview

The BBRS (Bollinger Bands + RSI + Squeeze) Strategy is a sophisticated mean-reversion and momentum strategy that combines Bollinger Bands, RSI (Relative Strength Index), and volume analysis to identify optimal entry and exit points. The strategy adapts to different market regimes and uses volume confirmation to improve signal quality.

Strategy Concept

Core Philosophy

  • Mean Reversion: Capitalize on price reversals at Bollinger Band extremes
  • Momentum Confirmation: Use RSI to confirm oversold/overbought conditions
  • Volume Validation: Require volume spikes for signal confirmation
  • Market Regime Adaptation: Adjust parameters based on market conditions
  • Squeeze Detection: Identify low volatility periods before breakouts

Key Features

  • Multi-Indicator Fusion: Combines price, volatility, momentum, and volume
  • Adaptive Thresholds: Dynamic RSI and Bollinger Band parameters
  • Volume Analysis: Volume spike detection and moving average tracking
  • Market Regime Detection: Automatic switching between trending and sideways strategies
  • Squeeze Strategy: Special handling for Bollinger Band squeeze conditions

Algorithm Details

Mathematical Foundation

Bollinger Bands Calculation

Middle Band (SMA) = Sum(Close, period) / period
Standard Deviation = sqrt(Sum((Close - SMA)²) / period)
Upper Band = Middle Band + (std_dev × Standard Deviation)
Lower Band = Middle Band - (std_dev × Standard Deviation)

%B = (Close - Lower Band) / (Upper Band - Lower Band)
Bandwidth = (Upper Band - Lower Band) / Middle Band

RSI Calculation (Wilder's Smoothing)

Price Change = Close - Previous Close
Gain = Price Change if positive, else 0
Loss = |Price Change| if negative, else 0

Average Gain = Wilder's MA(Gain, period)
Average Loss = Wilder's MA(Loss, period)

RS = Average Gain / Average Loss
RSI = 100 - (100 / (1 + RS))

Volume Analysis

Volume MA = Simple MA(Volume, volume_ma_period)
Volume Spike = Current Volume > (Volume MA × spike_threshold)
Volume Ratio = Current Volume / Volume MA

Process Flow Diagram

Data Input (OHLCV)
        ↓
TimeframeAggregator
        ↓
[15min aggregated data]
        ↓
┌─────────────────────────────────────────────────────┐
│                BBRS Strategy                        │
│                                                     │
│  ┌─────────────────┐  ┌─────────────────┐          │
│  │ Bollinger Bands │  │      RSI        │          │
│  │                 │  │                 │          │
│  │ • Upper Band    │  │ • RSI Value     │          │
│  │ • Middle Band   │  │ • Overbought    │          │
│  │ • Lower Band    │  │ • Oversold      │          │
│  │ • %B Indicator  │  │ • Momentum      │          │
│  │ • Bandwidth     │  │                 │          │
│  └─────────────────┘  └─────────────────┘          │
│           ↓                     ↓                   │
│  ┌─────────────────────────────────────────────────┐│
│  │            Volume Analysis                      ││
│  │                                                 ││
│  │  • Volume Moving Average                        ││
│  │  • Volume Spike Detection                       ││
│  │  • Volume Ratio Calculation                     ││
│  └─────────────────────────────────────────────────┘│
│                          ↓                          │
│  ┌─────────────────────────────────────────────────┐│
│  │         Market Regime Detection                 ││
│  │                                                 ││
│  │  if bandwidth < squeeze_threshold:              ││
│  │      regime = "SQUEEZE"                         ││
│  │  elif trending_conditions:                      ││
│  │      regime = "TRENDING"                        ││
│  │  else:                                          ││
│  │      regime = "SIDEWAYS"                        ││
│  └─────────────────────────────────────────────────┘│
│                          ↓                          │
│  ┌─────────────────────────────────────────────────┐│
│  │            Signal Generation                    ││
│  │                                                 ││
│  │  TRENDING Market:                               ││
│  │  • Price < Lower Band + RSI < 50 + Volume Spike ││
│  │                                                 ││
│  │  SIDEWAYS Market:                               ││
│  │  • Price ≤ Lower Band + RSI ≤ 30                ││
│  │                                                 ││
│  │  SQUEEZE Market:                                ││
│  │  • Wait for breakout + Volume confirmation      ││
│  └─────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────┘
        ↓
IncStrategySignal
        ↓
Trader Execution

Implementation Architecture

Class Hierarchy

IncStrategyBase
    ↓
BBRSStrategy
    ├── TimeframeAggregator (inherited)
    ├── BollingerBandsState
    ├── RSIState
    ├── MovingAverageState (Volume MA)
    ├── Market Regime Logic
    └── Signal Generation Logic

Key Components

1. Bollinger Bands Analysis

class BollingerBandsState:
    def __init__(self, period: int, std_dev: float):
        self.period = period
        self.std_dev = std_dev
        self.sma = MovingAverageState(period)
        self.price_history = deque(maxlen=period)
    
    def update(self, price: float):
        self.sma.update(price)
        self.price_history.append(price)
    
    def get_bands(self) -> tuple:
        if not self.is_ready():
            return None, None, None
        
        middle = self.sma.get_value()
        std = self._calculate_std()
        upper = middle + (self.std_dev * std)
        lower = middle - (self.std_dev * std)
        
        return upper, middle, lower
    
    def get_percent_b(self, price: float) -> float:
        upper, middle, lower = self.get_bands()
        if upper == lower:
            return 0.5
        return (price - lower) / (upper - lower)
    
    def is_squeeze(self, threshold: float = 0.1) -> bool:
        upper, middle, lower = self.get_bands()
        bandwidth = (upper - lower) / middle
        return bandwidth < threshold

2. RSI Analysis

class RSIState:
    def __init__(self, period: int):
        self.period = period
        self.gains = deque(maxlen=period)
        self.losses = deque(maxlen=period)
        self.avg_gain = 0.0
        self.avg_loss = 0.0
        self.previous_close = None
    
    def update(self, price: float):
        if self.previous_close is not None:
            change = price - self.previous_close
            gain = max(change, 0)
            loss = max(-change, 0)
            
            # Wilder's smoothing
            if len(self.gains) == self.period:
                self.avg_gain = (self.avg_gain * (self.period - 1) + gain) / self.period
                self.avg_loss = (self.avg_loss * (self.period - 1) + loss) / self.period
            else:
                self.gains.append(gain)
                self.losses.append(loss)
                if len(self.gains) == self.period:
                    self.avg_gain = sum(self.gains) / self.period
                    self.avg_loss = sum(self.losses) / self.period
        
        self.previous_close = price
    
    def get_value(self) -> float:
        if self.avg_loss == 0:
            return 100
        rs = self.avg_gain / self.avg_loss
        return 100 - (100 / (1 + rs))

3. Market Regime Detection

def _detect_market_regime(self) -> str:
    """Detect current market regime."""
    
    # Check for Bollinger Band squeeze
    if self.bb.is_squeeze(threshold=0.1):
        return "SQUEEZE"
    
    # Check for trending conditions
    bb_bandwidth = self.bb.get_bandwidth()
    rsi_value = self.rsi.get_value()
    
    # Trending market indicators
    if (bb_bandwidth > 0.15 and  # Wide bands
        (rsi_value > 70 or rsi_value < 30)):  # Strong momentum
        return "TRENDING"
    
    # Default to sideways
    return "SIDEWAYS"

4. Signal Generation Process

def _process_aggregated_data(self, timestamp: int, ohlcv: tuple) -> IncStrategySignal:
    open_price, high, low, close, volume = ohlcv
    
    # Update all indicators
    self.bb.update(close)
    self.rsi.update(close)
    self.volume_ma.update(volume)
    
    # Check if indicators are ready
    if not all([self.bb.is_ready(), self.rsi.is_ready(), self.volume_ma.is_ready()]):
        return IncStrategySignal.HOLD()
    
    # Detect market regime
    regime = self._detect_market_regime()
    
    # Get indicator values
    upper, middle, lower = self.bb.get_bands()
    rsi_value = self.rsi.get_value()
    percent_b = self.bb.get_percent_b(close)
    volume_spike = volume > (self.volume_ma.get_value() * self.params['volume_spike_threshold'])
    
    # Generate signals based on regime
    if regime == "TRENDING":
        return self._generate_trending_signal(close, rsi_value, percent_b, volume_spike, lower, upper)
    elif regime == "SIDEWAYS":
        return self._generate_sideways_signal(close, rsi_value, percent_b, lower, upper)
    elif regime == "SQUEEZE":
        return self._generate_squeeze_signal(close, rsi_value, percent_b, volume_spike, lower, upper)
    
    return IncStrategySignal.HOLD()

Configuration Parameters

Default Parameters

default_params = {
    "timeframe": "15min",                    # Data aggregation timeframe
    "bb_period": 20,                         # Bollinger Bands period
    "bb_std": 2.0,                          # Bollinger Bands standard deviation
    "rsi_period": 14,                        # RSI calculation period
    "rsi_overbought": 70,                    # RSI overbought threshold
    "rsi_oversold": 30,                      # RSI oversold threshold
    "volume_ma_period": 20,                  # Volume moving average period
    "volume_spike_threshold": 1.5,           # Volume spike multiplier
    "squeeze_threshold": 0.1,                # Bollinger Band squeeze threshold
    "trending_rsi_threshold": [30, 70],      # RSI thresholds for trending market
    "sideways_rsi_threshold": [25, 75]       # RSI thresholds for sideways market
}

Parameter Descriptions

Parameter Type Default Description
timeframe str "15min" Data aggregation timeframe
bb_period int 20 Bollinger Bands calculation period
bb_std float 2.0 Standard deviation multiplier for bands
rsi_period int 14 RSI calculation period
rsi_overbought float 70 RSI overbought threshold
rsi_oversold float 30 RSI oversold threshold
volume_ma_period int 20 Volume moving average period
volume_spike_threshold float 1.5 Volume spike detection multiplier
squeeze_threshold float 0.1 Bollinger Band squeeze detection threshold

Parameter Optimization Ranges

optimization_ranges = {
    "bb_period": [15, 20, 25, 30],
    "bb_std": [1.5, 2.0, 2.5, 3.0],
    "rsi_period": [10, 14, 18, 21],
    "rsi_overbought": [65, 70, 75, 80],
    "rsi_oversold": [20, 25, 30, 35],
    "volume_spike_threshold": [1.2, 1.5, 2.0, 2.5],
    "squeeze_threshold": [0.05, 0.1, 0.15, 0.2],
    "timeframe": ["5min", "15min", "30min", "1h"]
}

Signal Generation Logic

Market Regime Strategies

Entry Conditions:

  • Price < Lower Bollinger Band
  • RSI < 50 (momentum confirmation)
  • Volume > 1.5× Volume MA (volume spike)
  • %B < 0 (price below lower band)

Exit Conditions:

  • Price > Upper Bollinger Band
  • RSI > 70 (overbought)
  • %B > 1.0 (price above upper band)

2. Sideways Market Strategy

Entry Conditions:

  • Price ≤ Lower Bollinger Band
  • RSI ≤ 30 (oversold)
  • %B ≤ 0.2 (near lower band)

Exit Conditions:

  • Price ≥ Upper Bollinger Band
  • RSI ≥ 70 (overbought)
  • %B ≥ 0.8 (near upper band)

3. Squeeze Strategy

Entry Conditions:

  • Bollinger Band squeeze detected (bandwidth < threshold)
  • Price breaks above/below middle band
  • Volume spike confirmation
  • RSI momentum alignment

Exit Conditions:

  • Bollinger Bands expand significantly
  • Price reaches opposite band
  • Volume dies down

Signal Confidence Calculation

def _calculate_confidence(self, regime: str, conditions_met: list) -> float:
    """Calculate signal confidence based on conditions met."""
    
    base_confidence = {
        "TRENDING": 0.7,
        "SIDEWAYS": 0.8,
        "SQUEEZE": 0.9
    }
    
    # Adjust based on conditions met
    condition_bonus = len([c for c in conditions_met if c]) * 0.05
    
    return min(1.0, base_confidence[regime] + condition_bonus)

Signal Metadata

Each signal includes comprehensive metadata:

metadata = {
    'regime': 'TRENDING',                    # Market regime
    'bb_percent_b': 0.15,                   # %B indicator value
    'rsi_value': 28.5,                      # Current RSI value
    'volume_ratio': 1.8,                    # Volume vs MA ratio
    'bb_bandwidth': 0.12,                   # Bollinger Band bandwidth
    'upper_band': 45234.56,                 # Upper Bollinger Band
    'middle_band': 45000.00,                # Middle Bollinger Band (SMA)
    'lower_band': 44765.44,                 # Lower Bollinger Band
    'volume_spike': True,                   # Volume spike detected
    'squeeze_detected': False,              # Bollinger Band squeeze
    'conditions_met': ['price_below_lower', 'rsi_oversold', 'volume_spike'],
    'timestamp': 1640995200000              # Signal generation timestamp
}

Performance Characteristics

Strengths

  1. Mean Reversion Accuracy: High success rate in ranging markets
  2. Volume Confirmation: Reduces false signals through volume analysis
  3. Market Adaptation: Adjusts strategy based on market regime
  4. Multi-Indicator Confirmation: Combines price, momentum, and volume
  5. Squeeze Detection: Identifies low volatility breakout opportunities

Weaknesses

  1. Trending Markets: May struggle in strong trending conditions
  2. Whipsaws: Vulnerable to false breakouts in volatile conditions
  3. Parameter Sensitivity: Performance depends on proper parameter tuning
  4. Lag: Multiple confirmations can delay entry points

Optimal Market Conditions

  • Ranging Markets: Best performance in sideways trading ranges
  • Moderate Volatility: Works well with normal volatility levels
  • Sufficient Volume: Requires adequate volume for confirmation
  • Clear Support/Resistance: Performs best with defined price levels

Usage Examples

Basic Usage

from IncrementalTrader import BBRSStrategy, IncTrader

# Create strategy with default parameters
strategy = BBRSStrategy("bbrs")

# Create trader
trader = IncTrader(strategy, initial_usd=10000)

# Process data
for timestamp, ohlcv in data_stream:
    signal = trader.process_data_point(timestamp, ohlcv)
    if signal.signal_type != 'HOLD':
        print(f"Signal: {signal.signal_type} (confidence: {signal.confidence:.2f})")
        print(f"Regime: {signal.metadata['regime']}")
        print(f"RSI: {signal.metadata['rsi_value']:.2f}")

Aggressive Configuration

# Aggressive parameters for active trading
strategy = BBRSStrategy("bbrs_aggressive", {
    "timeframe": "5min",
    "bb_period": 15,
    "bb_std": 1.5,
    "rsi_period": 10,
    "rsi_overbought": 65,
    "rsi_oversold": 35,
    "volume_spike_threshold": 1.2
})

Conservative Configuration

# Conservative parameters for stable signals
strategy = BBRSStrategy("bbrs_conservative", {
    "timeframe": "1h",
    "bb_period": 25,
    "bb_std": 2.5,
    "rsi_period": 21,
    "rsi_overbought": 75,
    "rsi_oversold": 25,
    "volume_spike_threshold": 2.0
})

Advanced Features

Dynamic Parameter Adjustment

def adjust_parameters_for_volatility(self, volatility: float):
    """Adjust parameters based on market volatility."""
    
    if volatility > 0.03:  # High volatility
        self.params['bb_std'] = 2.5  # Wider bands
        self.params['volume_spike_threshold'] = 2.0  # Higher volume requirement
    elif volatility < 0.01:  # Low volatility
        self.params['bb_std'] = 1.5  # Tighter bands
        self.params['volume_spike_threshold'] = 1.2  # Lower volume requirement

Multi-timeframe Analysis

# Combine multiple timeframes for better context
strategy_5m = BBRSStrategy("bbrs_5m", {"timeframe": "5min"})
strategy_15m = BBRSStrategy("bbrs_15m", {"timeframe": "15min"})
strategy_1h = BBRSStrategy("bbrs_1h", {"timeframe": "1h"})

# Use higher timeframe for trend context, lower for entry timing

Custom Regime Detection

def custom_regime_detection(self, price_data: list, volume_data: list) -> str:
    """Custom market regime detection logic."""
    
    # Calculate additional metrics
    price_volatility = np.std(price_data[-20:]) / np.mean(price_data[-20:])
    volume_trend = np.polyfit(range(10), volume_data[-10:], 1)[0]
    
    # Enhanced regime logic
    if price_volatility < 0.01 and self.bb.is_squeeze():
        return "SQUEEZE"
    elif price_volatility > 0.03 and volume_trend > 0:
        return "TRENDING"
    else:
        return "SIDEWAYS"

Backtesting Results

Performance Metrics (Example)

Timeframe: 15min
Period: 2024-01-01 to 2024-12-31
Initial Capital: $10,000

Total Return: 18.67%
Sharpe Ratio: 1.28
Max Drawdown: -6.45%
Win Rate: 62.1%
Profit Factor: 1.54
Total Trades: 156

Regime Performance Analysis

Performance by Market Regime:
TRENDING:  Return 12.3%, Win Rate 55.2%, Trades 45
SIDEWAYS:  Return 24.1%, Win Rate 68.7%, Trades 89  ← Best
SQUEEZE:   Return 31.2%, Win Rate 71.4%, Trades 22  ← Highest

Implementation Notes

Memory Efficiency

  • Constant Memory: O(1) memory usage for all indicators
  • Efficient Calculations: Incremental updates for all metrics
  • State Management: Minimal state storage for optimal performance

Real-time Capability

  • Low Latency: Fast indicator updates and signal generation
  • Incremental Processing: Designed for live trading applications
  • Stateful Design: Maintains indicator state between updates

Error Handling

def _process_aggregated_data(self, timestamp: int, ohlcv: tuple) -> IncStrategySignal:
    try:
        # Validate input data
        if not self._validate_ohlcv(ohlcv):
            self.logger.warning(f"Invalid OHLCV data: {ohlcv}")
            return IncStrategySignal.HOLD()
        
        # Validate volume data
        if ohlcv[4] <= 0:
            self.logger.warning(f"Invalid volume: {ohlcv[4]}")
            return IncStrategySignal.HOLD()
        
        # Process data
        # ... strategy logic ...
        
    except Exception as e:
        self.logger.error(f"Error in BBRS strategy: {e}")
        return IncStrategySignal.HOLD()

Troubleshooting

Common Issues

  1. No Signals Generated

    • Check if RSI thresholds are too extreme
    • Verify volume spike threshold is not too high
    • Ensure sufficient data for indicator warmup
  2. Too Many False Signals

    • Increase volume spike threshold
    • Tighten RSI overbought/oversold levels
    • Use wider Bollinger Bands (higher std_dev)
  3. Missed Opportunities

    • Lower volume spike threshold
    • Relax RSI thresholds
    • Use tighter Bollinger Bands

Debug Information

# Enable debug logging
strategy.logger.setLevel(logging.DEBUG)

# Access internal state
print(f"Current regime: {strategy._detect_market_regime()}")
print(f"BB bands: {strategy.bb.get_bands()}")
print(f"RSI value: {strategy.rsi.get_value()}")
print(f"Volume ratio: {volume / strategy.volume_ma.get_value()}")
print(f"Squeeze detected: {strategy.bb.is_squeeze()}")

Integration with Other Strategies

Strategy Combination

# Combine BBRS with trend-following strategy
bbrs_strategy = BBRSStrategy("bbrs")
metatrend_strategy = MetaTrendStrategy("metatrend")

# Use MetaTrend for trend direction, BBRS for entry timing
def combined_signal(bbrs_signal, metatrend_signal):
    if metatrend_signal.signal_type == 'BUY' and bbrs_signal.signal_type == 'BUY':
        return IncStrategySignal.BUY(confidence=0.9)
    elif metatrend_signal.signal_type == 'SELL' and bbrs_signal.signal_type == 'SELL':
        return IncStrategySignal.SELL(confidence=0.9)
    return IncStrategySignal.HOLD()

The BBRS Strategy provides sophisticated mean-reversion capabilities with market regime adaptation, making it particularly effective in ranging markets while maintaining the flexibility to adapt to different market conditions.