22 KiB
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
1. Trending Market Strategy
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
- Mean Reversion Accuracy: High success rate in ranging markets
- Volume Confirmation: Reduces false signals through volume analysis
- Market Adaptation: Adjusts strategy based on market regime
- Multi-Indicator Confirmation: Combines price, momentum, and volume
- Squeeze Detection: Identifies low volatility breakout opportunities
Weaknesses
- Trending Markets: May struggle in strong trending conditions
- Whipsaws: Vulnerable to false breakouts in volatile conditions
- Parameter Sensitivity: Performance depends on proper parameter tuning
- 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
-
No Signals Generated
- Check if RSI thresholds are too extreme
- Verify volume spike threshold is not too high
- Ensure sufficient data for indicator warmup
-
Too Many False Signals
- Increase volume spike threshold
- Tighten RSI overbought/oversold levels
- Use wider Bollinger Bands (higher std_dev)
-
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.