573 lines
19 KiB
Markdown
573 lines
19 KiB
Markdown
# Random Strategy Documentation
|
|
|
|
## Overview
|
|
|
|
The Random Strategy is a testing and benchmarking strategy that generates random trading signals. While it may seem counterintuitive, this strategy serves crucial purposes in algorithmic trading: providing a baseline for performance comparison, testing framework robustness, and validating backtesting systems.
|
|
|
|
## Strategy Concept
|
|
|
|
### Core Philosophy
|
|
- **Baseline Comparison**: Provides a random baseline to compare other strategies against
|
|
- **Framework Testing**: Tests the robustness of the trading framework
|
|
- **Statistical Validation**: Helps validate that other strategies perform better than random chance
|
|
- **System Debugging**: Useful for debugging trading systems and backtesting frameworks
|
|
|
|
### Key Features
|
|
- **Configurable Randomness**: Adjustable probability distributions for signal generation
|
|
- **Seed Control**: Reproducible results for testing and validation
|
|
- **Signal Frequency Control**: Configurable frequency of signal generation
|
|
- **Confidence Simulation**: Realistic confidence levels for testing signal processing
|
|
|
|
## Algorithm Details
|
|
|
|
### Mathematical Foundation
|
|
|
|
The Random Strategy uses probability distributions to generate signals:
|
|
|
|
```
|
|
Signal Generation:
|
|
- Generate random number R ~ Uniform(0, 1)
|
|
- If R < buy_probability: Generate BUY signal
|
|
- Elif R < (buy_probability + sell_probability): Generate SELL signal
|
|
- Else: Generate HOLD signal
|
|
|
|
Confidence Generation:
|
|
- Confidence ~ Beta(alpha, beta) or Uniform(min_conf, max_conf)
|
|
- Ensures realistic confidence distributions for testing
|
|
```
|
|
|
|
### Signal Distribution
|
|
|
|
```python
|
|
# Default probability distribution
|
|
signal_probabilities = {
|
|
'BUY': 0.1, # 10% chance of BUY signal
|
|
'SELL': 0.1, # 10% chance of SELL signal
|
|
'HOLD': 0.8 # 80% chance of HOLD signal
|
|
}
|
|
|
|
# Confidence distribution
|
|
confidence_range = (0.5, 0.9) # Realistic confidence levels
|
|
```
|
|
|
|
## Process Flow Diagram
|
|
|
|
```
|
|
Data Input (OHLCV)
|
|
↓
|
|
TimeframeAggregator
|
|
↓
|
|
[15min aggregated data]
|
|
↓
|
|
┌─────────────────────────────────────┐
|
|
│ Random Strategy │
|
|
│ │
|
|
│ ┌─────────────────────────────────┐│
|
|
│ │ Random Number Generator ││
|
|
│ │ ││
|
|
│ │ • Seed Control ││
|
|
│ │ • Probability Distribution ││
|
|
│ │ • Signal Frequency Control ││
|
|
│ └─────────────────────────────────┘│
|
|
│ ↓ │
|
|
│ ┌─────────────────────────────────┐│
|
|
│ │ Signal Generation ││
|
|
│ │ ││
|
|
│ │ R = random() ││
|
|
│ │ if R < buy_prob: ││
|
|
│ │ signal = BUY ││
|
|
│ │ elif R < buy_prob + sell_prob: ││
|
|
│ │ signal = SELL ││
|
|
│ │ else: ││
|
|
│ │ signal = HOLD ││
|
|
│ └─────────────────────────────────┘│
|
|
│ ↓ │
|
|
│ ┌─────────────────────────────────┐│
|
|
│ │ Confidence Generation ││
|
|
│ │ ││
|
|
│ │ confidence = random_uniform( ││
|
|
│ │ min_confidence, ││
|
|
│ │ max_confidence ││
|
|
│ │ ) ││
|
|
│ └─────────────────────────────────┘│
|
|
└─────────────────────────────────────┘
|
|
↓
|
|
IncStrategySignal
|
|
↓
|
|
Trader Execution
|
|
```
|
|
|
|
## Implementation Architecture
|
|
|
|
### Class Hierarchy
|
|
|
|
```
|
|
IncStrategyBase
|
|
↓
|
|
RandomStrategy
|
|
├── TimeframeAggregator (inherited)
|
|
├── Random Number Generator
|
|
├── Probability Configuration
|
|
└── Signal Generation Logic
|
|
```
|
|
|
|
### Key Components
|
|
|
|
#### 1. Random Number Generator
|
|
```python
|
|
class RandomStrategy(IncStrategyBase):
|
|
def __init__(self, name: str, params: dict = None):
|
|
super().__init__(name, params)
|
|
|
|
# Initialize random seed for reproducibility
|
|
if self.params.get('seed') is not None:
|
|
random.seed(self.params['seed'])
|
|
np.random.seed(self.params['seed'])
|
|
|
|
self.signal_count = 0
|
|
self.last_signal_time = 0
|
|
```
|
|
|
|
#### 2. Signal Generation Process
|
|
```python
|
|
def _process_aggregated_data(self, timestamp: int, ohlcv: tuple) -> IncStrategySignal:
|
|
open_price, high, low, close, volume = ohlcv
|
|
|
|
# Check signal frequency constraint
|
|
if not self._should_generate_signal(timestamp):
|
|
return IncStrategySignal.HOLD()
|
|
|
|
# Generate random signal
|
|
rand_val = random.random()
|
|
|
|
if rand_val < self.params['buy_probability']:
|
|
signal_type = 'BUY'
|
|
elif rand_val < (self.params['buy_probability'] + self.params['sell_probability']):
|
|
signal_type = 'SELL'
|
|
else:
|
|
signal_type = 'HOLD'
|
|
|
|
# Generate random confidence
|
|
confidence = random.uniform(
|
|
self.params['min_confidence'],
|
|
self.params['max_confidence']
|
|
)
|
|
|
|
# Create signal with metadata
|
|
if signal_type == 'BUY':
|
|
self.signal_count += 1
|
|
self.last_signal_time = timestamp
|
|
return IncStrategySignal.BUY(
|
|
confidence=confidence,
|
|
metadata=self._create_metadata(timestamp, rand_val, signal_type)
|
|
)
|
|
elif signal_type == 'SELL':
|
|
self.signal_count += 1
|
|
self.last_signal_time = timestamp
|
|
return IncStrategySignal.SELL(
|
|
confidence=confidence,
|
|
metadata=self._create_metadata(timestamp, rand_val, signal_type)
|
|
)
|
|
|
|
return IncStrategySignal.HOLD()
|
|
```
|
|
|
|
#### 3. Signal Frequency Control
|
|
```python
|
|
def _should_generate_signal(self, timestamp: int) -> bool:
|
|
"""Control signal generation frequency."""
|
|
|
|
# Check minimum time between signals
|
|
min_interval = self.params.get('min_signal_interval_minutes', 0) * 60 * 1000
|
|
if timestamp - self.last_signal_time < min_interval:
|
|
return False
|
|
|
|
# Check maximum signals per day
|
|
max_daily_signals = self.params.get('max_daily_signals', float('inf'))
|
|
if self.signal_count >= max_daily_signals:
|
|
# Reset counter if new day (simplified)
|
|
if self._is_new_day(timestamp):
|
|
self.signal_count = 0
|
|
else:
|
|
return False
|
|
|
|
return True
|
|
```
|
|
|
|
## Configuration Parameters
|
|
|
|
### Default Parameters
|
|
```python
|
|
default_params = {
|
|
"timeframe": "15min", # Data aggregation timeframe
|
|
"buy_probability": 0.1, # Probability of generating BUY signal
|
|
"sell_probability": 0.1, # Probability of generating SELL signal
|
|
"min_confidence": 0.5, # Minimum confidence level
|
|
"max_confidence": 0.9, # Maximum confidence level
|
|
"seed": None, # Random seed (None for random)
|
|
"min_signal_interval_minutes": 0, # Minimum minutes between signals
|
|
"max_daily_signals": float('inf'), # Maximum signals per day
|
|
"signal_frequency": 1.0 # Signal generation frequency multiplier
|
|
}
|
|
```
|
|
|
|
### Parameter Descriptions
|
|
|
|
| Parameter | Type | Default | Description |
|
|
|-----------|------|---------|-------------|
|
|
| `timeframe` | str | "15min" | Data aggregation timeframe |
|
|
| `buy_probability` | float | 0.1 | Probability of generating BUY signal (0-1) |
|
|
| `sell_probability` | float | 0.1 | Probability of generating SELL signal (0-1) |
|
|
| `min_confidence` | float | 0.5 | Minimum confidence level for signals |
|
|
| `max_confidence` | float | 0.9 | Maximum confidence level for signals |
|
|
| `seed` | int | None | Random seed for reproducible results |
|
|
| `min_signal_interval_minutes` | int | 0 | Minimum minutes between signals |
|
|
| `max_daily_signals` | int | inf | Maximum signals per day |
|
|
|
|
### Parameter Optimization Ranges
|
|
|
|
```python
|
|
optimization_ranges = {
|
|
"buy_probability": [0.05, 0.1, 0.15, 0.2, 0.25],
|
|
"sell_probability": [0.05, 0.1, 0.15, 0.2, 0.25],
|
|
"min_confidence": [0.3, 0.4, 0.5, 0.6],
|
|
"max_confidence": [0.7, 0.8, 0.9, 1.0],
|
|
"signal_frequency": [0.5, 1.0, 1.5, 2.0],
|
|
"timeframe": ["5min", "15min", "30min", "1h"]
|
|
}
|
|
```
|
|
|
|
## Signal Generation Logic
|
|
|
|
### Signal Types and Probabilities
|
|
|
|
**Signal Distribution:**
|
|
- **BUY**: Configurable probability (default 10%)
|
|
- **SELL**: Configurable probability (default 10%)
|
|
- **HOLD**: Remaining probability (default 80%)
|
|
|
|
**Confidence Generation:**
|
|
- Uniform distribution between min_confidence and max_confidence
|
|
- Simulates realistic confidence levels for testing
|
|
|
|
### Signal Metadata
|
|
|
|
Each signal includes comprehensive metadata for testing:
|
|
```python
|
|
metadata = {
|
|
'random_value': 0.0847, # Random value that generated signal
|
|
'signal_number': 15, # Sequential signal number
|
|
'probability_used': 0.1, # Probability threshold used
|
|
'confidence_range': [0.5, 0.9], # Confidence range used
|
|
'seed_used': 12345, # Random seed if specified
|
|
'generation_method': 'uniform', # Random generation method
|
|
'signal_frequency': 1.0, # Signal frequency multiplier
|
|
'timestamp': 1640995200000 # Signal generation timestamp
|
|
}
|
|
```
|
|
|
|
## Performance Characteristics
|
|
|
|
### Expected Performance
|
|
|
|
1. **Random Walk**: Should approximate random walk performance
|
|
2. **Zero Alpha**: No systematic edge over random chance
|
|
3. **High Volatility**: Typically high volatility due to random signals
|
|
4. **50% Win Rate**: Expected win rate around 50% (before costs)
|
|
|
|
### Statistical Properties
|
|
|
|
- **Sharpe Ratio**: Expected to be around 0 (random performance)
|
|
- **Maximum Drawdown**: Highly variable, can be significant
|
|
- **Return Distribution**: Should approximate normal distribution over time
|
|
- **Signal Distribution**: Follows configured probability distribution
|
|
|
|
### Use Cases
|
|
|
|
1. **Baseline Comparison**: Compare other strategies against random performance
|
|
2. **Framework Testing**: Test trading framework with known signal patterns
|
|
3. **Statistical Validation**: Validate that other strategies beat random chance
|
|
4. **System Debugging**: Debug backtesting and trading systems
|
|
|
|
## Usage Examples
|
|
|
|
### Basic Usage
|
|
```python
|
|
from IncrementalTrader import RandomStrategy, IncTrader
|
|
|
|
# Create strategy with default parameters
|
|
strategy = RandomStrategy("random")
|
|
|
|
# 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"Random Signal: {signal.signal_type} (confidence: {signal.confidence:.2f})")
|
|
```
|
|
|
|
### Reproducible Testing
|
|
```python
|
|
# Create strategy with fixed seed for reproducible results
|
|
strategy = RandomStrategy("random_test", {
|
|
"seed": 12345,
|
|
"buy_probability": 0.15,
|
|
"sell_probability": 0.15,
|
|
"min_confidence": 0.6,
|
|
"max_confidence": 0.8
|
|
})
|
|
```
|
|
|
|
### Controlled Signal Frequency
|
|
```python
|
|
# Create strategy with controlled signal frequency
|
|
strategy = RandomStrategy("random_controlled", {
|
|
"buy_probability": 0.2,
|
|
"sell_probability": 0.2,
|
|
"min_signal_interval_minutes": 60, # At least 1 hour between signals
|
|
"max_daily_signals": 5 # Maximum 5 signals per day
|
|
})
|
|
```
|
|
|
|
## Advanced Features
|
|
|
|
### Custom Probability Distributions
|
|
```python
|
|
def custom_signal_generation(self, timestamp: int) -> str:
|
|
"""Custom signal generation with time-based probabilities."""
|
|
|
|
# Vary probabilities based on time of day
|
|
hour = datetime.fromtimestamp(timestamp / 1000).hour
|
|
|
|
if 9 <= hour <= 16: # Market hours
|
|
buy_prob = 0.15
|
|
sell_prob = 0.15
|
|
else: # After hours
|
|
buy_prob = 0.05
|
|
sell_prob = 0.05
|
|
|
|
rand_val = random.random()
|
|
if rand_val < buy_prob:
|
|
return 'BUY'
|
|
elif rand_val < buy_prob + sell_prob:
|
|
return 'SELL'
|
|
return 'HOLD'
|
|
```
|
|
|
|
### Confidence Distribution Modeling
|
|
```python
|
|
def generate_realistic_confidence(self) -> float:
|
|
"""Generate confidence using beta distribution for realism."""
|
|
|
|
# Beta distribution parameters for realistic confidence
|
|
alpha = 2.0 # Shape parameter
|
|
beta = 2.0 # Shape parameter
|
|
|
|
# Generate beta-distributed confidence
|
|
beta_sample = np.random.beta(alpha, beta)
|
|
|
|
# Scale to desired range
|
|
min_conf = self.params['min_confidence']
|
|
max_conf = self.params['max_confidence']
|
|
|
|
return min_conf + beta_sample * (max_conf - min_conf)
|
|
```
|
|
|
|
### Market Regime Simulation
|
|
```python
|
|
def simulate_market_regimes(self, timestamp: int) -> dict:
|
|
"""Simulate different market regimes for testing."""
|
|
|
|
# Simple regime switching based on time
|
|
regime_cycle = (timestamp // (24 * 60 * 60 * 1000)) % 3
|
|
|
|
if regime_cycle == 0: # Bull market
|
|
return {
|
|
'buy_probability': 0.2,
|
|
'sell_probability': 0.05,
|
|
'confidence_boost': 0.1
|
|
}
|
|
elif regime_cycle == 1: # Bear market
|
|
return {
|
|
'buy_probability': 0.05,
|
|
'sell_probability': 0.2,
|
|
'confidence_boost': 0.1
|
|
}
|
|
else: # Sideways market
|
|
return {
|
|
'buy_probability': 0.1,
|
|
'sell_probability': 0.1,
|
|
'confidence_boost': 0.0
|
|
}
|
|
```
|
|
|
|
## Backtesting Results
|
|
|
|
### Expected Performance Metrics
|
|
```
|
|
Timeframe: 15min
|
|
Period: 2024-01-01 to 2024-12-31
|
|
Initial Capital: $10,000
|
|
|
|
Expected Results:
|
|
Total Return: ~0% (random walk)
|
|
Sharpe Ratio: ~0.0
|
|
Max Drawdown: Variable (10-30%)
|
|
Win Rate: ~50%
|
|
Profit Factor: ~1.0 (before costs)
|
|
Total Trades: Variable based on probabilities
|
|
```
|
|
|
|
### Statistical Analysis
|
|
```
|
|
Signal Distribution Analysis:
|
|
BUY Signals: ~10% of total data points
|
|
SELL Signals: ~10% of total data points
|
|
HOLD Signals: ~80% of total data points
|
|
|
|
Confidence Distribution:
|
|
Mean Confidence: 0.7 (midpoint of range)
|
|
Std Confidence: Varies by distribution type
|
|
Min Confidence: 0.5
|
|
Max Confidence: 0.9
|
|
```
|
|
|
|
## Implementation Notes
|
|
|
|
### Memory Efficiency
|
|
- **Minimal State**: Only tracks signal count and timing
|
|
- **No Indicators**: No technical indicators to maintain
|
|
- **Constant Memory**: O(1) memory usage
|
|
|
|
### Real-time Capability
|
|
- **Ultra-Fast**: Minimal processing per data point
|
|
- **No Dependencies**: No indicator calculations required
|
|
- **Immediate Signals**: Instant signal generation
|
|
|
|
### Error Handling
|
|
```python
|
|
def _process_aggregated_data(self, timestamp: int, ohlcv: tuple) -> IncStrategySignal:
|
|
try:
|
|
# Validate basic data
|
|
if not self._validate_ohlcv(ohlcv):
|
|
self.logger.warning(f"Invalid OHLCV data: {ohlcv}")
|
|
return IncStrategySignal.HOLD()
|
|
|
|
# Generate random signal
|
|
return self._generate_random_signal(timestamp)
|
|
|
|
except Exception as e:
|
|
self.logger.error(f"Error in Random strategy: {e}")
|
|
return IncStrategySignal.HOLD()
|
|
```
|
|
|
|
## Testing and Validation
|
|
|
|
### Framework Testing
|
|
```python
|
|
def test_signal_distribution():
|
|
"""Test that signal distribution matches expected probabilities."""
|
|
|
|
strategy = RandomStrategy("test", {"seed": 12345})
|
|
signals = []
|
|
|
|
# Generate many signals
|
|
for i in range(10000):
|
|
signal = strategy._generate_random_signal(i)
|
|
signals.append(signal.signal_type)
|
|
|
|
# Analyze distribution
|
|
buy_ratio = signals.count('BUY') / len(signals)
|
|
sell_ratio = signals.count('SELL') / len(signals)
|
|
hold_ratio = signals.count('HOLD') / len(signals)
|
|
|
|
assert abs(buy_ratio - 0.1) < 0.02 # Within 2% of expected
|
|
assert abs(sell_ratio - 0.1) < 0.02 # Within 2% of expected
|
|
assert abs(hold_ratio - 0.8) < 0.02 # Within 2% of expected
|
|
```
|
|
|
|
### Reproducibility Testing
|
|
```python
|
|
def test_reproducibility():
|
|
"""Test that same seed produces same results."""
|
|
|
|
strategy1 = RandomStrategy("test1", {"seed": 12345})
|
|
strategy2 = RandomStrategy("test2", {"seed": 12345})
|
|
|
|
signals1 = []
|
|
signals2 = []
|
|
|
|
# Generate signals with both strategies
|
|
for i in range(1000):
|
|
sig1 = strategy1._generate_random_signal(i)
|
|
sig2 = strategy2._generate_random_signal(i)
|
|
signals1.append((sig1.signal_type, sig1.confidence))
|
|
signals2.append((sig2.signal_type, sig2.confidence))
|
|
|
|
# Should be identical
|
|
assert signals1 == signals2
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### Common Issues
|
|
|
|
1. **Non-Random Results**
|
|
- Check if seed is set (removes randomness)
|
|
- Verify probability parameters are correct
|
|
- Ensure random number generator is working
|
|
|
|
2. **Too Many/Few Signals**
|
|
- Adjust buy_probability and sell_probability
|
|
- Check signal frequency constraints
|
|
- Verify timeframe settings
|
|
|
|
3. **Unrealistic Performance**
|
|
- Random strategy should perform around 0% return
|
|
- If significantly positive/negative, check for bugs
|
|
- Verify transaction costs are included
|
|
|
|
### Debug Information
|
|
```python
|
|
# Enable debug logging
|
|
strategy.logger.setLevel(logging.DEBUG)
|
|
|
|
# Check signal statistics
|
|
print(f"Total signals generated: {strategy.signal_count}")
|
|
print(f"Buy probability: {strategy.params['buy_probability']}")
|
|
print(f"Sell probability: {strategy.params['sell_probability']}")
|
|
print(f"Current seed: {strategy.params.get('seed', 'None (random)')}")
|
|
```
|
|
|
|
## Integration with Testing Framework
|
|
|
|
### Benchmark Comparison
|
|
```python
|
|
def compare_with_random_baseline(strategy_results, random_results):
|
|
"""Compare strategy performance against random baseline."""
|
|
|
|
strategy_return = strategy_results['total_return']
|
|
random_return = random_results['total_return']
|
|
|
|
# Calculate excess return over random
|
|
excess_return = strategy_return - random_return
|
|
|
|
# Statistical significance test
|
|
t_stat, p_value = stats.ttest_ind(
|
|
strategy_results['daily_returns'],
|
|
random_results['daily_returns']
|
|
)
|
|
|
|
return {
|
|
'excess_return': excess_return,
|
|
'statistical_significance': p_value < 0.05,
|
|
't_statistic': t_stat,
|
|
'p_value': p_value
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
*The Random Strategy serves as a crucial testing and benchmarking tool, providing a baseline for performance comparison and validating that other strategies perform better than random chance. While it generates no alpha by design, it's invaluable for framework testing and statistical validation.* |