documentation

This commit is contained in:
Ajasra 2025-05-28 22:37:53 +08:00
parent 1861c336f9
commit 5c6e0598c0
15 changed files with 7537 additions and 25 deletions

View File

@ -0,0 +1,782 @@
# API Reference
This document provides a comprehensive API reference for the IncrementalTrader framework.
## Module Structure
```
IncrementalTrader/
├── strategies/ # Trading strategies and base classes
│ ├── base.py # Base strategy framework
│ ├── metatrend.py # MetaTrend strategy
│ ├── bbrs.py # BBRS strategy
│ ├── random.py # Random strategy
│ └── indicators/ # Technical indicators
├── trader/ # Trade execution
│ ├── trader.py # Main trader implementation
│ └── position.py # Position management
├── backtester/ # Backtesting framework
│ ├── backtester.py # Main backtesting engine
│ ├── config.py # Configuration classes
│ └── utils.py # Utilities and helpers
└── utils/ # General utilities
```
## Core Classes
### IncStrategySignal
Signal class for strategy outputs.
```python
class IncStrategySignal:
def __init__(self, signal_type: str, confidence: float = 1.0, metadata: dict = None)
```
**Parameters:**
- `signal_type` (str): Signal type ('BUY', 'SELL', 'HOLD')
- `confidence` (float): Signal confidence (0.0 to 1.0)
- `metadata` (dict): Additional signal information
**Factory Methods:**
```python
@classmethod
def BUY(cls, confidence: float = 1.0, metadata: dict = None) -> 'IncStrategySignal'
@classmethod
def SELL(cls, confidence: float = 1.0, metadata: dict = None) -> 'IncStrategySignal'
@classmethod
def HOLD(cls, metadata: dict = None) -> 'IncStrategySignal'
```
**Properties:**
- `signal_type` (str): The signal type
- `confidence` (float): Signal confidence level
- `metadata` (dict): Additional metadata
- `timestamp` (int): Signal generation timestamp
**Example:**
```python
# Create signals using factory methods
buy_signal = IncStrategySignal.BUY(confidence=0.8, metadata={'reason': 'golden_cross'})
sell_signal = IncStrategySignal.SELL(confidence=0.9)
hold_signal = IncStrategySignal.HOLD()
```
### TimeframeAggregator
Aggregates data points to different timeframes.
```python
class TimeframeAggregator:
def __init__(self, timeframe: str)
```
**Parameters:**
- `timeframe` (str): Target timeframe ('1min', '5min', '15min', '30min', '1h', '4h', '1d')
**Methods:**
```python
def add_data_point(self, timestamp: int, ohlcv: tuple) -> tuple | None
"""Add data point and return aggregated OHLCV if timeframe complete."""
def get_current_aggregated(self) -> tuple | None
"""Get current aggregated data without completing timeframe."""
def reset(self) -> None
"""Reset aggregator state."""
```
**Example:**
```python
aggregator = TimeframeAggregator("15min")
for timestamp, ohlcv in data_stream:
aggregated = aggregator.add_data_point(timestamp, ohlcv)
if aggregated:
timestamp_agg, ohlcv_agg = aggregated
# Process aggregated data
```
### IncStrategyBase
Base class for all trading strategies.
```python
class IncStrategyBase:
def __init__(self, name: str, params: dict = None)
```
**Parameters:**
- `name` (str): Strategy name
- `params` (dict): Strategy parameters
**Abstract Methods:**
```python
def _process_aggregated_data(self, timestamp: int, ohlcv: tuple) -> IncStrategySignal
"""Process aggregated data and return signal. Must be implemented by subclasses."""
```
**Public Methods:**
```python
def process_data_point(self, timestamp: int, ohlcv: tuple) -> IncStrategySignal
"""Process raw data point and return signal."""
def get_current_signal(self) -> IncStrategySignal
"""Get the most recent signal."""
def get_performance_metrics(self) -> dict
"""Get strategy performance metrics."""
def reset(self) -> None
"""Reset strategy state."""
```
**Properties:**
- `name` (str): Strategy name
- `params` (dict): Strategy parameters
- `logger` (Logger): Strategy logger
- `signal_history` (list): History of generated signals
**Example:**
```python
class MyStrategy(IncStrategyBase):
def __init__(self, name: str, params: dict = None):
super().__init__(name, params)
self.sma = MovingAverageState(period=20)
def _process_aggregated_data(self, timestamp: int, ohlcv: tuple) -> IncStrategySignal:
_, _, _, close, _ = ohlcv
self.sma.update(close)
if self.sma.is_ready():
return IncStrategySignal.BUY() if close > self.sma.get_value() else IncStrategySignal.SELL()
return IncStrategySignal.HOLD()
```
## Strategy Classes
### MetaTrendStrategy
Multi-Supertrend trend-following strategy.
```python
class MetaTrendStrategy(IncStrategyBase):
def __init__(self, name: str, params: dict = None)
```
**Default Parameters:**
```python
{
"timeframe": "15min",
"supertrend_periods": [10, 20, 30],
"supertrend_multipliers": [2.0, 3.0, 4.0],
"min_trend_agreement": 0.6
}
```
**Methods:**
- Inherits all methods from `IncStrategyBase`
- Uses `SupertrendCollection` for meta-trend analysis
**Example:**
```python
strategy = MetaTrendStrategy("metatrend", {
"timeframe": "15min",
"supertrend_periods": [10, 20, 30],
"min_trend_agreement": 0.7
})
```
### BBRSStrategy
Bollinger Bands + RSI strategy with market regime detection.
```python
class BBRSStrategy(IncStrategyBase):
def __init__(self, name: str, params: dict = None)
```
**Default Parameters:**
```python
{
"timeframe": "15min",
"bb_period": 20,
"bb_std": 2.0,
"rsi_period": 14,
"rsi_overbought": 70,
"rsi_oversold": 30,
"volume_ma_period": 20,
"volume_spike_threshold": 1.5
}
```
**Methods:**
- Inherits all methods from `IncStrategyBase`
- Implements market regime detection
- Uses volume analysis for signal confirmation
**Example:**
```python
strategy = BBRSStrategy("bbrs", {
"timeframe": "15min",
"bb_period": 20,
"rsi_period": 14
})
```
### RandomStrategy
Random signal generation for testing.
```python
class RandomStrategy(IncStrategyBase):
def __init__(self, name: str, params: dict = None)
```
**Default Parameters:**
```python
{
"timeframe": "15min",
"buy_probability": 0.1,
"sell_probability": 0.1,
"seed": None
}
```
**Example:**
```python
strategy = RandomStrategy("random", {
"buy_probability": 0.05,
"sell_probability": 0.05,
"seed": 42
})
```
## Indicator Classes
### Base Indicator Classes
#### IndicatorState
```python
class IndicatorState:
def __init__(self, period: int)
def update(self, value: float) -> None
def get_value(self) -> float
def is_ready(self) -> bool
def reset(self) -> None
```
#### SimpleIndicatorState
```python
class SimpleIndicatorState(IndicatorState):
def __init__(self)
```
#### OHLCIndicatorState
```python
class OHLCIndicatorState(IndicatorState):
def __init__(self, period: int)
def update_ohlc(self, high: float, low: float, close: float) -> None
```
### Moving Average Indicators
#### MovingAverageState
```python
class MovingAverageState(IndicatorState):
def __init__(self, period: int)
def update(self, value: float) -> None
def get_value(self) -> float
def is_ready(self) -> bool
```
#### ExponentialMovingAverageState
```python
class ExponentialMovingAverageState(IndicatorState):
def __init__(self, period: int, alpha: float = None)
def update(self, value: float) -> None
def get_value(self) -> float
def is_ready(self) -> bool
```
### Volatility Indicators
#### ATRState
```python
class ATRState(OHLCIndicatorState):
def __init__(self, period: int)
def update_ohlc(self, high: float, low: float, close: float) -> None
def get_value(self) -> float
def get_true_range(self) -> float
def is_ready(self) -> bool
```
#### SimpleATRState
```python
class SimpleATRState(IndicatorState):
def __init__(self, period: int)
def update_range(self, high: float, low: float) -> None
def get_value(self) -> float
def is_ready(self) -> bool
```
### Trend Indicators
#### SupertrendState
```python
class SupertrendState(OHLCIndicatorState):
def __init__(self, period: int, multiplier: float)
def update_ohlc(self, high: float, low: float, close: float) -> None
def get_value(self) -> float
def get_signal(self) -> str
def is_uptrend(self) -> bool
def get_upper_band(self) -> float
def get_lower_band(self) -> float
def is_ready(self) -> bool
```
#### SupertrendCollection
```python
class SupertrendCollection:
def __init__(self, periods: list, multipliers: list)
def update_ohlc(self, high: float, low: float, close: float) -> None
def get_signals(self) -> list
def get_meta_signal(self, min_agreement: float = 0.6) -> str
def get_agreement_ratio(self) -> float
def is_ready(self) -> bool
```
### Oscillator Indicators
#### RSIState
```python
class RSIState(IndicatorState):
def __init__(self, period: int)
def update(self, price: float) -> None
def get_value(self) -> float
def is_overbought(self, threshold: float = 70) -> bool
def is_oversold(self, threshold: float = 30) -> bool
def is_ready(self) -> bool
```
#### SimpleRSIState
```python
class SimpleRSIState(IndicatorState):
def __init__(self, period: int)
def update(self, price: float) -> None
def get_value(self) -> float
def is_ready(self) -> bool
```
### Bollinger Bands
#### BollingerBandsState
```python
class BollingerBandsState(IndicatorState):
def __init__(self, period: int, std_dev: float = 2.0)
def update(self, price: float) -> None
def get_bands(self) -> tuple # (upper, middle, lower)
def get_upper_band(self) -> float
def get_middle_band(self) -> float
def get_lower_band(self) -> float
def get_bandwidth(self) -> float
def get_percent_b(self, price: float) -> float
def is_squeeze(self, threshold: float = 0.1) -> bool
def is_ready(self) -> bool
```
#### BollingerBandsOHLCState
```python
class BollingerBandsOHLCState(OHLCIndicatorState):
def __init__(self, period: int, std_dev: float = 2.0)
def update_ohlc(self, high: float, low: float, close: float) -> None
def get_bands(self) -> tuple # (upper, middle, lower)
# ... same methods as BollingerBandsState
```
## Trading Classes
### IncTrader
Main trader class for executing strategies.
```python
class IncTrader:
def __init__(self, strategy: IncStrategyBase, initial_usd: float = 10000,
stop_loss_pct: float = None, take_profit_pct: float = None,
fee_pct: float = 0.001, slippage_pct: float = 0.0005)
```
**Parameters:**
- `strategy` (IncStrategyBase): Trading strategy instance
- `initial_usd` (float): Starting capital
- `stop_loss_pct` (float): Stop loss percentage
- `take_profit_pct` (float): Take profit percentage
- `fee_pct` (float): Trading fee percentage
- `slippage_pct` (float): Slippage percentage
**Methods:**
```python
def process_data_point(self, timestamp: int, ohlcv: tuple) -> None
"""Process new data point and execute trades."""
def get_results(self) -> dict
"""Get comprehensive trading results."""
def get_portfolio_value(self, current_price: float) -> float
"""Get current portfolio value."""
def get_position_info(self) -> dict
"""Get current position information."""
def reset(self) -> None
"""Reset trader state."""
```
**Example:**
```python
trader = IncTrader(
strategy=MetaTrendStrategy("metatrend"),
initial_usd=10000,
stop_loss_pct=0.03,
take_profit_pct=0.06
)
for timestamp, ohlcv in data_stream:
trader.process_data_point(timestamp, ohlcv)
results = trader.get_results()
```
### PositionManager
Manages trading positions and portfolio state.
```python
class PositionManager:
def __init__(self, initial_usd: float)
```
**Methods:**
```python
def execute_buy(self, price: float, timestamp: int, fee_pct: float = 0.001,
slippage_pct: float = 0.0005) -> TradeRecord | None
def execute_sell(self, price: float, timestamp: int, fee_pct: float = 0.001,
slippage_pct: float = 0.0005) -> TradeRecord | None
def get_portfolio_value(self, current_price: float) -> float
def get_position_info(self) -> dict
def reset(self) -> None
```
**Properties:**
- `usd_balance` (float): Current USD balance
- `coin_balance` (float): Current coin balance
- `position_type` (str): Current position ('LONG', 'SHORT', 'NONE')
- `entry_price` (float): Position entry price
- `entry_timestamp` (int): Position entry timestamp
### TradeRecord
Record of individual trades.
```python
class TradeRecord:
def __init__(self, side: str, price: float, quantity: float, timestamp: int,
fee: float = 0.0, slippage: float = 0.0, pnl: float = 0.0)
```
**Properties:**
- `side` (str): Trade side ('BUY', 'SELL')
- `price` (float): Execution price
- `quantity` (float): Trade quantity
- `timestamp` (int): Execution timestamp
- `fee` (float): Trading fee paid
- `slippage` (float): Slippage cost
- `pnl` (float): Profit/loss for the trade
## Backtesting Classes
### IncBacktester
Main backtesting engine.
```python
class IncBacktester:
def __init__(self)
```
**Methods:**
```python
def run_single_strategy(self, strategy_class: type, strategy_params: dict,
config: BacktestConfig, data_file: str) -> dict
"""Run backtest for single strategy."""
def optimize_strategy(self, strategy_class: type, optimization_config: OptimizationConfig,
data_file: str) -> dict
"""Optimize strategy parameters."""
```
**Example:**
```python
backtester = IncBacktester()
results = backtester.run_single_strategy(
strategy_class=MetaTrendStrategy,
strategy_params={"timeframe": "15min"},
config=BacktestConfig(initial_usd=10000),
data_file="data.csv"
)
```
### BacktestConfig
Configuration for backtesting.
```python
class BacktestConfig:
def __init__(self, initial_usd: float = 10000, stop_loss_pct: float = None,
take_profit_pct: float = None, start_date: str = None,
end_date: str = None, fee_pct: float = 0.001,
slippage_pct: float = 0.0005, output_dir: str = "backtest_results",
save_trades: bool = True, save_portfolio_history: bool = True,
risk_free_rate: float = 0.02)
```
**Properties:**
- `initial_usd` (float): Starting capital
- `stop_loss_pct` (float): Stop loss percentage
- `take_profit_pct` (float): Take profit percentage
- `start_date` (str): Start date (YYYY-MM-DD)
- `end_date` (str): End date (YYYY-MM-DD)
- `fee_pct` (float): Trading fee percentage
- `slippage_pct` (float): Slippage percentage
- `output_dir` (str): Output directory
- `save_trades` (bool): Save trade records
- `save_portfolio_history` (bool): Save portfolio history
- `risk_free_rate` (float): Risk-free rate for Sharpe ratio
### OptimizationConfig
Configuration for parameter optimization.
```python
class OptimizationConfig:
def __init__(self, base_config: BacktestConfig, param_ranges: dict,
max_workers: int = None, optimization_metric: str | callable = "sharpe_ratio",
save_all_results: bool = False)
```
**Properties:**
- `base_config` (BacktestConfig): Base configuration
- `param_ranges` (dict): Parameter ranges to test
- `max_workers` (int): Number of parallel workers
- `optimization_metric` (str | callable): Metric to optimize
- `save_all_results` (bool): Save all parameter combinations
## Utility Classes
### DataLoader
Loads and validates trading data.
```python
class DataLoader:
@staticmethod
def load_data(file_path: str, start_date: str = None, end_date: str = None) -> pd.DataFrame
"""Load and validate OHLCV data from CSV file."""
@staticmethod
def validate_data(data: pd.DataFrame) -> bool
"""Validate data format and consistency."""
```
### SystemUtils
System resource management utilities.
```python
class SystemUtils:
@staticmethod
def get_optimal_workers() -> int
"""Get optimal number of worker processes."""
@staticmethod
def get_memory_usage() -> dict
"""Get current memory usage statistics."""
```
### ResultsSaver
Save backtesting results to files.
```python
class ResultsSaver:
@staticmethod
def save_results(results: dict, output_dir: str) -> None
"""Save complete results to directory."""
@staticmethod
def save_performance_metrics(metrics: dict, file_path: str) -> None
"""Save performance metrics to JSON file."""
@staticmethod
def save_trades(trades: list, file_path: str) -> None
"""Save trade records to CSV file."""
@staticmethod
def save_portfolio_history(history: list, file_path: str) -> None
"""Save portfolio history to CSV file."""
```
### MarketFees
Trading fee calculation utilities.
```python
class MarketFees:
@staticmethod
def calculate_fee(trade_value: float, fee_pct: float) -> float
"""Calculate trading fee."""
@staticmethod
def calculate_slippage(trade_value: float, slippage_pct: float) -> float
"""Calculate slippage cost."""
@staticmethod
def get_binance_fees() -> dict
"""Get Binance fee structure."""
@staticmethod
def get_coinbase_fees() -> dict
"""Get Coinbase fee structure."""
```
## Performance Metrics
The framework calculates comprehensive performance metrics:
```python
performance_metrics = {
# Return metrics
'total_return_pct': float, # Total portfolio return percentage
'annualized_return_pct': float, # Annualized return percentage
'final_portfolio_value': float, # Final portfolio value
# Risk metrics
'volatility_pct': float, # Annualized volatility
'max_drawdown_pct': float, # Maximum drawdown percentage
'sharpe_ratio': float, # Sharpe ratio
'sortino_ratio': float, # Sortino ratio
'calmar_ratio': float, # Calmar ratio
# Trading metrics
'total_trades': int, # Total number of trades
'win_rate': float, # Percentage of winning trades
'profit_factor': float, # Gross profit / gross loss
'avg_trade_pct': float, # Average trade return percentage
'avg_win_pct': float, # Average winning trade percentage
'avg_loss_pct': float, # Average losing trade percentage
# Time metrics
'total_days': int, # Total trading days
'trades_per_day': float, # Average trades per day
# Additional metrics
'var_95': float, # Value at Risk (95%)
'es_95': float, # Expected Shortfall (95%)
'beta': float, # Beta vs benchmark
'alpha': float # Alpha vs benchmark
}
```
## Error Handling
The framework uses custom exceptions for better error handling:
```python
class IncrementalTraderError(Exception):
"""Base exception for IncrementalTrader."""
class StrategyError(IncrementalTraderError):
"""Strategy-related errors."""
class IndicatorError(IncrementalTraderError):
"""Indicator-related errors."""
class BacktestError(IncrementalTraderError):
"""Backtesting-related errors."""
class DataError(IncrementalTraderError):
"""Data-related errors."""
```
## Logging
The framework provides comprehensive logging:
```python
import logging
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
# Strategy logging
strategy = MetaTrendStrategy("metatrend")
strategy.logger.info("Strategy initialized")
# Trader logging
trader = IncTrader(strategy)
trader.logger.info("Trader initialized")
```
## Type Hints
The framework uses comprehensive type hints:
```python
from typing import Dict, List, Tuple, Optional, Union, Callable
from abc import ABC, abstractmethod
# Example type hints used throughout the framework
def process_data_point(self, timestamp: int, ohlcv: Tuple[float, float, float, float, float]) -> IncStrategySignal:
pass
def get_results(self) -> Dict[str, Union[float, int, List, Dict]]:
pass
```
This API reference provides comprehensive documentation for all public classes, methods, and functions in the IncrementalTrader framework. For detailed usage examples, see the other documentation files.

View File

@ -0,0 +1,626 @@
# Backtesting Guide
This guide explains how to use the IncrementalTrader backtesting framework for comprehensive strategy testing and optimization.
## Overview
The IncrementalTrader backtesting framework provides:
- **Single Strategy Testing**: Test individual strategies with detailed metrics
- **Parameter Optimization**: Systematic parameter sweeps with parallel execution
- **Performance Analysis**: Comprehensive performance metrics and reporting
- **Data Management**: Flexible data loading and validation
- **Result Export**: Multiple output formats for analysis
## Quick Start
### Basic Backtesting
```python
from IncrementalTrader import IncBacktester, BacktestConfig, MetaTrendStrategy
# Configure backtest
config = BacktestConfig(
initial_usd=10000,
stop_loss_pct=0.03,
take_profit_pct=0.06,
start_date="2024-01-01",
end_date="2024-12-31"
)
# Create backtester
backtester = IncBacktester()
# Run single strategy test
results = backtester.run_single_strategy(
strategy_class=MetaTrendStrategy,
strategy_params={"timeframe": "15min"},
config=config,
data_file="data/BTCUSDT_1m.csv"
)
# Print results
print(f"Total Return: {results['performance_metrics']['total_return_pct']:.2f}%")
print(f"Sharpe Ratio: {results['performance_metrics']['sharpe_ratio']:.2f}")
print(f"Max Drawdown: {results['performance_metrics']['max_drawdown_pct']:.2f}%")
```
## Configuration
### BacktestConfig
The main configuration class for backtesting parameters.
```python
from IncrementalTrader import BacktestConfig
config = BacktestConfig(
# Portfolio settings
initial_usd=10000, # Starting capital
# Risk management
stop_loss_pct=0.03, # 3% stop loss
take_profit_pct=0.06, # 6% take profit
# Time range
start_date="2024-01-01", # Start date (YYYY-MM-DD)
end_date="2024-12-31", # End date (YYYY-MM-DD)
# Trading settings
fee_pct=0.001, # 0.1% trading fee
slippage_pct=0.0005, # 0.05% slippage
# Output settings
output_dir="backtest_results",
save_trades=True,
save_portfolio_history=True,
# Performance settings
risk_free_rate=0.02 # 2% annual risk-free rate
)
```
**Parameters:**
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `initial_usd` | float | 10000 | Starting capital in USD |
| `stop_loss_pct` | float | None | Stop loss percentage (0.03 = 3%) |
| `take_profit_pct` | float | None | Take profit percentage (0.06 = 6%) |
| `start_date` | str | None | Start date in YYYY-MM-DD format |
| `end_date` | str | None | End date in YYYY-MM-DD format |
| `fee_pct` | float | 0.001 | Trading fee percentage |
| `slippage_pct` | float | 0.0005 | Slippage percentage |
| `output_dir` | str | "backtest_results" | Output directory |
| `save_trades` | bool | True | Save individual trades |
| `save_portfolio_history` | bool | True | Save portfolio history |
| `risk_free_rate` | float | 0.02 | Annual risk-free rate for Sharpe ratio |
### OptimizationConfig
Configuration for parameter optimization.
```python
from IncrementalTrader import OptimizationConfig
# Define parameter ranges
param_ranges = {
"supertrend_periods": [[10, 20, 30], [15, 25, 35], [20, 30, 40]],
"supertrend_multipliers": [[2.0, 3.0, 4.0], [1.5, 2.5, 3.5]],
"min_trend_agreement": [0.5, 0.6, 0.7, 0.8]
}
# Create optimization config
opt_config = OptimizationConfig(
base_config=config, # Base BacktestConfig
param_ranges=param_ranges, # Parameter combinations to test
max_workers=4, # Number of parallel workers
optimization_metric="sharpe_ratio", # Metric to optimize
save_all_results=True # Save all parameter combinations
)
```
## Single Strategy Testing
### Basic Usage
```python
# Test MetaTrend strategy
results = backtester.run_single_strategy(
strategy_class=MetaTrendStrategy,
strategy_params={
"timeframe": "15min",
"supertrend_periods": [10, 20, 30],
"supertrend_multipliers": [2.0, 3.0, 4.0],
"min_trend_agreement": 0.6
},
config=config,
data_file="data/BTCUSDT_1m.csv"
)
```
### Results Structure
```python
# Access different result components
performance = results['performance_metrics']
trades = results['trades']
portfolio_history = results['portfolio_history']
config_used = results['config']
# Performance metrics
print(f"Total Trades: {performance['total_trades']}")
print(f"Win Rate: {performance['win_rate']:.2f}%")
print(f"Profit Factor: {performance['profit_factor']:.2f}")
print(f"Sharpe Ratio: {performance['sharpe_ratio']:.2f}")
print(f"Sortino Ratio: {performance['sortino_ratio']:.2f}")
print(f"Max Drawdown: {performance['max_drawdown_pct']:.2f}%")
print(f"Calmar Ratio: {performance['calmar_ratio']:.2f}")
# Trade analysis
winning_trades = [t for t in trades if t['pnl'] > 0]
losing_trades = [t for t in trades if t['pnl'] < 0]
print(f"Average Win: ${sum(t['pnl'] for t in winning_trades) / len(winning_trades):.2f}")
print(f"Average Loss: ${sum(t['pnl'] for t in losing_trades) / len(losing_trades):.2f}")
```
### Performance Metrics
The backtester calculates comprehensive performance metrics:
| Metric | Description | Formula |
|--------|-------------|---------|
| Total Return | Overall portfolio return | (Final Value - Initial Value) / Initial Value |
| Annualized Return | Yearly return rate | (Total Return + 1)^(365/days) - 1 |
| Volatility | Annualized standard deviation | std(daily_returns) × √365 |
| Sharpe Ratio | Risk-adjusted return | (Return - Risk Free Rate) / Volatility |
| Sortino Ratio | Downside risk-adjusted return | (Return - Risk Free Rate) / Downside Deviation |
| Max Drawdown | Maximum peak-to-trough decline | max((Peak - Trough) / Peak) |
| Calmar Ratio | Return to max drawdown ratio | Annualized Return / Max Drawdown |
| Win Rate | Percentage of profitable trades | Winning Trades / Total Trades |
| Profit Factor | Ratio of gross profit to loss | Gross Profit / Gross Loss |
## Parameter Optimization
### Basic Optimization
```python
# Define parameter ranges to test
param_ranges = {
"timeframe": ["5min", "15min", "30min"],
"supertrend_periods": [[10, 20, 30], [15, 25, 35]],
"min_trend_agreement": [0.5, 0.6, 0.7]
}
# Create optimization config
opt_config = OptimizationConfig(
base_config=config,
param_ranges=param_ranges,
max_workers=4,
optimization_metric="sharpe_ratio"
)
# Run optimization
optimization_results = backtester.optimize_strategy(
strategy_class=MetaTrendStrategy,
optimization_config=opt_config,
data_file="data/BTCUSDT_1m.csv"
)
# Get best parameters
best_params = optimization_results['best_params']
best_performance = optimization_results['best_performance']
all_results = optimization_results['all_results']
print(f"Best Parameters: {best_params}")
print(f"Best Sharpe Ratio: {best_performance['sharpe_ratio']:.2f}")
```
### Advanced Optimization
```python
# More complex parameter optimization
param_ranges = {
# Strategy parameters
"timeframe": ["5min", "15min", "30min"],
"supertrend_periods": [
[10, 20, 30], [15, 25, 35], [20, 30, 40],
[10, 15, 20], [25, 35, 45]
],
"supertrend_multipliers": [
[2.0, 3.0, 4.0], [1.5, 2.5, 3.5], [2.5, 3.5, 4.5]
],
"min_trend_agreement": [0.4, 0.5, 0.6, 0.7, 0.8],
# Risk management (will override config values)
"stop_loss_pct": [0.02, 0.03, 0.04, 0.05],
"take_profit_pct": [0.04, 0.06, 0.08, 0.10]
}
# Optimization with custom metric
def custom_metric(performance):
"""Custom optimization metric combining return and drawdown."""
return performance['total_return_pct'] / max(performance['max_drawdown_pct'], 1.0)
opt_config = OptimizationConfig(
base_config=config,
param_ranges=param_ranges,
max_workers=8,
optimization_metric=custom_metric, # Custom function
save_all_results=True
)
results = backtester.optimize_strategy(
strategy_class=MetaTrendStrategy,
optimization_config=opt_config,
data_file="data/BTCUSDT_1m.csv"
)
```
### Optimization Metrics
You can optimize for different metrics:
```python
# Built-in metrics (string names)
optimization_metrics = [
"total_return_pct",
"sharpe_ratio",
"sortino_ratio",
"calmar_ratio",
"profit_factor",
"win_rate"
]
# Custom metric function
def risk_adjusted_return(performance):
return (performance['total_return_pct'] /
max(performance['max_drawdown_pct'], 1.0))
opt_config = OptimizationConfig(
base_config=config,
param_ranges=param_ranges,
optimization_metric=risk_adjusted_return # Custom function
)
```
## Data Management
### Data Format
The backtester expects CSV data with the following columns:
```csv
timestamp,open,high,low,close,volume
1640995200000,46222.5,46850.0,46150.0,46800.0,1250.5
1640995260000,46800.0,47000.0,46750.0,46950.0,980.2
...
```
**Required Columns:**
- `timestamp`: Unix timestamp in milliseconds
- `open`: Opening price
- `high`: Highest price
- `low`: Lowest price
- `close`: Closing price
- `volume`: Trading volume
### Data Loading
```python
# The backtester automatically loads and validates data
results = backtester.run_single_strategy(
strategy_class=MetaTrendStrategy,
strategy_params={"timeframe": "15min"},
config=config,
data_file="data/BTCUSDT_1m.csv" # Automatically loaded and validated
)
# Data is automatically filtered by start_date and end_date from config
```
### Data Validation
The backtester performs automatic data validation:
```python
# Validation checks performed:
# 1. Required columns present
# 2. No missing values
# 3. Timestamps in ascending order
# 4. Price consistency (high >= low, etc.)
# 5. Date range filtering
# 6. Data type validation
```
## Advanced Features
### Custom Strategy Testing
```python
# Test your custom strategy
class MyCustomStrategy(IncStrategyBase):
def __init__(self, name: str, params: dict = None):
super().__init__(name, params)
# Your strategy implementation
def _process_aggregated_data(self, timestamp: int, ohlcv: tuple):
# Your strategy logic
return IncStrategySignal.HOLD()
# Test custom strategy
results = backtester.run_single_strategy(
strategy_class=MyCustomStrategy,
strategy_params={"timeframe": "15min", "custom_param": 42},
config=config,
data_file="data/BTCUSDT_1m.csv"
)
```
### Multiple Strategy Comparison
```python
# Compare different strategies
strategies_to_test = [
(MetaTrendStrategy, {"timeframe": "15min"}),
(BBRSStrategy, {"timeframe": "15min"}),
(RandomStrategy, {"timeframe": "15min"})
]
comparison_results = {}
for strategy_class, params in strategies_to_test:
results = backtester.run_single_strategy(
strategy_class=strategy_class,
strategy_params=params,
config=config,
data_file="data/BTCUSDT_1m.csv"
)
strategy_name = strategy_class.__name__
comparison_results[strategy_name] = results['performance_metrics']
# Compare results
for name, performance in comparison_results.items():
print(f"{name}:")
print(f" Return: {performance['total_return_pct']:.2f}%")
print(f" Sharpe: {performance['sharpe_ratio']:.2f}")
print(f" Max DD: {performance['max_drawdown_pct']:.2f}%")
```
### Walk-Forward Analysis
```python
# Implement walk-forward analysis
import pandas as pd
from datetime import datetime, timedelta
def walk_forward_analysis(strategy_class, params, data_file,
train_months=6, test_months=1):
"""Perform walk-forward analysis."""
# Load full dataset to determine date range
data = pd.read_csv(data_file)
data['timestamp'] = pd.to_datetime(data['timestamp'], unit='ms')
start_date = data['timestamp'].min()
end_date = data['timestamp'].max()
results = []
current_date = start_date
while current_date + timedelta(days=30*(train_months + test_months)) <= end_date:
# Define train and test periods
train_start = current_date
train_end = current_date + timedelta(days=30*train_months)
test_start = train_end
test_end = test_start + timedelta(days=30*test_months)
# Optimize on training data
train_config = BacktestConfig(
initial_usd=10000,
start_date=train_start.strftime("%Y-%m-%d"),
end_date=train_end.strftime("%Y-%m-%d")
)
# Simple parameter optimization (you can expand this)
best_params = params # In practice, optimize here
# Test on out-of-sample data
test_config = BacktestConfig(
initial_usd=10000,
start_date=test_start.strftime("%Y-%m-%d"),
end_date=test_end.strftime("%Y-%m-%d")
)
test_results = backtester.run_single_strategy(
strategy_class=strategy_class,
strategy_params=best_params,
config=test_config,
data_file=data_file
)
results.append({
'test_start': test_start,
'test_end': test_end,
'performance': test_results['performance_metrics']
})
# Move to next period
current_date = test_start
return results
# Run walk-forward analysis
wf_results = walk_forward_analysis(
MetaTrendStrategy,
{"timeframe": "15min"},
"data/BTCUSDT_1m.csv"
)
# Analyze walk-forward results
total_returns = [r['performance']['total_return_pct'] for r in wf_results]
avg_return = sum(total_returns) / len(total_returns)
print(f"Average out-of-sample return: {avg_return:.2f}%")
```
## Result Analysis
### Detailed Performance Analysis
```python
# Comprehensive result analysis
def analyze_results(results):
"""Analyze backtest results in detail."""
performance = results['performance_metrics']
trades = results['trades']
portfolio_history = results['portfolio_history']
print("=== PERFORMANCE SUMMARY ===")
print(f"Total Return: {performance['total_return_pct']:.2f}%")
print(f"Annualized Return: {performance['annualized_return_pct']:.2f}%")
print(f"Volatility: {performance['volatility_pct']:.2f}%")
print(f"Sharpe Ratio: {performance['sharpe_ratio']:.2f}")
print(f"Sortino Ratio: {performance['sortino_ratio']:.2f}")
print(f"Max Drawdown: {performance['max_drawdown_pct']:.2f}%")
print(f"Calmar Ratio: {performance['calmar_ratio']:.2f}")
print("\n=== TRADING STATISTICS ===")
print(f"Total Trades: {performance['total_trades']}")
print(f"Win Rate: {performance['win_rate']:.2f}%")
print(f"Profit Factor: {performance['profit_factor']:.2f}")
# Trade analysis
if trades:
winning_trades = [t for t in trades if t['pnl'] > 0]
losing_trades = [t for t in trades if t['pnl'] < 0]
if winning_trades:
avg_win = sum(t['pnl'] for t in winning_trades) / len(winning_trades)
max_win = max(t['pnl'] for t in winning_trades)
print(f"Average Win: ${avg_win:.2f}")
print(f"Largest Win: ${max_win:.2f}")
if losing_trades:
avg_loss = sum(t['pnl'] for t in losing_trades) / len(losing_trades)
max_loss = min(t['pnl'] for t in losing_trades)
print(f"Average Loss: ${avg_loss:.2f}")
print(f"Largest Loss: ${max_loss:.2f}")
print("\n=== RISK METRICS ===")
print(f"Value at Risk (95%): {performance.get('var_95', 'N/A')}")
print(f"Expected Shortfall (95%): {performance.get('es_95', 'N/A')}")
return performance
# Analyze results
performance = analyze_results(results)
```
### Export Results
```python
# Export results to different formats
def export_results(results, output_dir="backtest_results"):
"""Export backtest results to files."""
import os
import json
import pandas as pd
os.makedirs(output_dir, exist_ok=True)
# Export performance metrics
with open(f"{output_dir}/performance_metrics.json", 'w') as f:
json.dump(results['performance_metrics'], f, indent=2)
# Export trades
if results['trades']:
trades_df = pd.DataFrame(results['trades'])
trades_df.to_csv(f"{output_dir}/trades.csv", index=False)
# Export portfolio history
if results['portfolio_history']:
portfolio_df = pd.DataFrame(results['portfolio_history'])
portfolio_df.to_csv(f"{output_dir}/portfolio_history.csv", index=False)
# Export configuration
config_dict = {
'initial_usd': results['config'].initial_usd,
'stop_loss_pct': results['config'].stop_loss_pct,
'take_profit_pct': results['config'].take_profit_pct,
'start_date': results['config'].start_date,
'end_date': results['config'].end_date,
'fee_pct': results['config'].fee_pct,
'slippage_pct': results['config'].slippage_pct
}
with open(f"{output_dir}/config.json", 'w') as f:
json.dump(config_dict, f, indent=2)
print(f"Results exported to {output_dir}/")
# Export results
export_results(results)
```
## Best Practices
### 1. Data Quality
```python
# Ensure high-quality data
# - Use clean, validated OHLCV data
# - Check for gaps and inconsistencies
# - Use appropriate timeframes for your strategy
# - Include sufficient history for indicator warmup
```
### 2. Realistic Parameters
```python
# Use realistic trading parameters
config = BacktestConfig(
initial_usd=10000,
fee_pct=0.001, # Realistic trading fees
slippage_pct=0.0005, # Account for slippage
stop_loss_pct=0.03, # Reasonable stop loss
take_profit_pct=0.06 # Reasonable take profit
)
```
### 3. Overfitting Prevention
```python
# Prevent overfitting
# - Use out-of-sample testing
# - Implement walk-forward analysis
# - Limit parameter optimization ranges
# - Use cross-validation techniques
# - Test on multiple time periods and market conditions
```
### 4. Performance Validation
```python
# Validate performance metrics
# - Check for statistical significance
# - Analyze trade distribution
# - Examine drawdown periods
# - Verify risk-adjusted returns
# - Compare to benchmarks
```
### 5. Strategy Robustness
```python
# Test strategy robustness
# - Test on different market conditions
# - Vary parameter ranges
# - Check sensitivity to transaction costs
# - Analyze performance across different timeframes
# - Test with different data sources
```
This comprehensive backtesting guide provides everything you need to thoroughly test and optimize your trading strategies using the IncrementalTrader framework. Remember that backtesting is just one part of strategy development - always validate results with forward testing before live trading.

View File

@ -0,0 +1,364 @@
# Base Indicator Classes
## Overview
All indicators in IncrementalTrader are built on a foundation of base classes that provide common functionality for incremental computation. These base classes ensure consistent behavior, memory efficiency, and real-time capability across all indicators.
## Available indicators
- [Moving Averages](moving_averages.md)
- [Volatility](volatility.md) - ATR
- [Trend](trend.md) - Supertrend
- [Oscillators](oscillators.md) - RSI
- [Bollinger Bands](bollinger_bands.md) - Bollinger Bands
## IndicatorState
The foundation class for all indicators in the framework.
### Features
- **Incremental Computation**: O(1) time complexity per update
- **Constant Memory**: O(1) space complexity regardless of data history
- **State Management**: Maintains internal state efficiently
- **Ready State Tracking**: Indicates when indicator has sufficient data
### Class Definition
```python
from IncrementalTrader.strategies.indicators import IndicatorState
class IndicatorState:
def __init__(self, period: int):
self.period = period
self.data_count = 0
def update(self, value: float):
"""Update indicator with new value."""
raise NotImplementedError("Subclasses must implement update method")
def get_value(self) -> float:
"""Get current indicator value."""
raise NotImplementedError("Subclasses must implement get_value method")
def is_ready(self) -> bool:
"""Check if indicator has enough data."""
return self.data_count >= self.period
def reset(self):
"""Reset indicator state."""
self.data_count = 0
```
### Methods
| Method | Description | Returns |
|--------|-------------|---------|
| `update(value: float)` | Update indicator with new value | None |
| `get_value() -> float` | Get current indicator value | float |
| `is_ready() -> bool` | Check if indicator has enough data | bool |
| `reset()` | Reset indicator state | None |
### Usage Example
```python
class MyCustomIndicator(IndicatorState):
def __init__(self, period: int):
super().__init__(period)
self.sum = 0.0
self.values = []
def update(self, value: float):
self.values.append(value)
self.sum += value
if len(self.values) > self.period:
old_value = self.values.pop(0)
self.sum -= old_value
self.data_count += 1
def get_value(self) -> float:
if not self.is_ready():
return 0.0
return self.sum / min(len(self.values), self.period)
# Usage
indicator = MyCustomIndicator(period=10)
for price in [100, 101, 99, 102, 98]:
indicator.update(price)
if indicator.is_ready():
print(f"Value: {indicator.get_value():.2f}")
```
## SimpleIndicatorState
For indicators that only need the current value and don't require a period.
### Features
- **Immediate Ready**: Always ready after first update
- **No Period Requirement**: Doesn't need historical data
- **Minimal State**: Stores only current value
### Class Definition
```python
class SimpleIndicatorState(IndicatorState):
def __init__(self):
super().__init__(period=1)
self.current_value = 0.0
def update(self, value: float):
self.current_value = value
self.data_count = 1 # Always ready
def get_value(self) -> float:
return self.current_value
```
### Usage Example
```python
# Simple price tracker
price_tracker = SimpleIndicatorState()
for price in [100, 101, 99, 102]:
price_tracker.update(price)
print(f"Current price: {price_tracker.get_value():.2f}")
```
## OHLCIndicatorState
For indicators that require OHLC (Open, High, Low, Close) data instead of just a single price value.
### Features
- **OHLC Data Support**: Handles high, low, close data
- **Flexible Updates**: Can update with individual OHLC components
- **Typical Price Calculation**: Built-in typical price (HLC/3) calculation
### Class Definition
```python
class OHLCIndicatorState(IndicatorState):
def __init__(self, period: int):
super().__init__(period)
self.current_high = 0.0
self.current_low = 0.0
self.current_close = 0.0
def update_ohlc(self, high: float, low: float, close: float):
"""Update with OHLC data."""
self.current_high = high
self.current_low = low
self.current_close = close
self._process_ohlc_data(high, low, close)
self.data_count += 1
def _process_ohlc_data(self, high: float, low: float, close: float):
"""Process OHLC data - to be implemented by subclasses."""
raise NotImplementedError("Subclasses must implement _process_ohlc_data")
def get_typical_price(self) -> float:
"""Calculate typical price (HLC/3)."""
return (self.current_high + self.current_low + self.current_close) / 3.0
def get_true_range(self, prev_close: float = None) -> float:
"""Calculate True Range."""
if prev_close is None:
return self.current_high - self.current_low
return max(
self.current_high - self.current_low,
abs(self.current_high - prev_close),
abs(self.current_low - prev_close)
)
```
### Methods
| Method | Description | Returns |
|--------|-------------|---------|
| `update_ohlc(high, low, close)` | Update with OHLC data | None |
| `get_typical_price()` | Get typical price (HLC/3) | float |
| `get_true_range(prev_close)` | Calculate True Range | float |
### Usage Example
```python
class MyOHLCIndicator(OHLCIndicatorState):
def __init__(self, period: int):
super().__init__(period)
self.hl_sum = 0.0
self.count = 0
def _process_ohlc_data(self, high: float, low: float, close: float):
self.hl_sum += (high - low)
self.count += 1
def get_value(self) -> float:
if self.count == 0:
return 0.0
return self.hl_sum / self.count
# Usage
ohlc_indicator = MyOHLCIndicator(period=10)
ohlc_data = [(105, 95, 100), (108, 98, 102), (110, 100, 105)]
for high, low, close in ohlc_data:
ohlc_indicator.update_ohlc(high, low, close)
if ohlc_indicator.is_ready():
print(f"Average Range: {ohlc_indicator.get_value():.2f}")
print(f"Typical Price: {ohlc_indicator.get_typical_price():.2f}")
```
## Best Practices
### 1. Always Check Ready State
```python
indicator = MovingAverageState(period=20)
for price in price_data:
indicator.update(price)
# Always check if ready before using value
if indicator.is_ready():
value = indicator.get_value()
# Use the value...
```
### 2. Initialize Once, Reuse Many Times
```python
# Good: Initialize once
sma = MovingAverageState(period=20)
# Process many data points
for price in large_dataset:
sma.update(price)
if sma.is_ready():
process_signal(sma.get_value())
# Bad: Don't recreate indicators
for price in large_dataset:
sma = MovingAverageState(period=20) # Wasteful!
sma.update(price)
```
### 3. Handle Edge Cases
```python
def safe_indicator_update(indicator, value):
"""Safely update indicator with error handling."""
try:
if value is not None and not math.isnan(value):
indicator.update(value)
return True
except Exception as e:
logger.error(f"Error updating indicator: {e}")
return False
```
### 4. Batch Updates for Multiple Indicators
```python
# Update all indicators together
indicators = [sma_20, ema_12, rsi_14]
for price in price_stream:
# Update all indicators
for indicator in indicators:
indicator.update(price)
# Check if all are ready
if all(ind.is_ready() for ind in indicators):
# Use all indicator values
values = [ind.get_value() for ind in indicators]
process_signals(values)
```
## Performance Characteristics
### Memory Usage
- **IndicatorState**: O(period) memory usage
- **SimpleIndicatorState**: O(1) memory usage
- **OHLCIndicatorState**: O(period) memory usage
### Processing Speed
- **Update Time**: O(1) per data point for all base classes
- **Value Retrieval**: O(1) for getting current value
- **Ready Check**: O(1) for checking ready state
### Scalability
```python
# Memory usage remains constant regardless of data volume
indicator = MovingAverageState(period=20)
# Process 1 million data points - memory usage stays O(20)
for i in range(1_000_000):
indicator.update(i)
if indicator.is_ready():
value = indicator.get_value() # Always O(1)
```
## Error Handling
### Common Patterns
```python
class RobustIndicator(IndicatorState):
def update(self, value: float):
try:
# Validate input
if value is None or math.isnan(value) or math.isinf(value):
self.logger.warning(f"Invalid value: {value}")
return
# Process value
self._process_value(value)
self.data_count += 1
except Exception as e:
self.logger.error(f"Error in indicator update: {e}")
def get_value(self) -> float:
try:
if not self.is_ready():
return 0.0
return self._calculate_value()
except Exception as e:
self.logger.error(f"Error calculating indicator value: {e}")
return 0.0
```
## Integration with Strategies
### Strategy Usage Pattern
```python
class MyStrategy(IncStrategyBase):
def __init__(self, name: str, params: dict = None):
super().__init__(name, params)
# Initialize indicators
self.sma = MovingAverageState(period=20)
self.rsi = RSIState(period=14)
self.atr = ATRState(period=14)
def _process_aggregated_data(self, timestamp: int, ohlcv: tuple) -> IncStrategySignal:
open_price, high, low, close, volume = ohlcv
# Update all indicators
self.sma.update(close)
self.rsi.update(close)
self.atr.update_ohlc(high, low, close)
# Check if all indicators are ready
if not all([self.sma.is_ready(), self.rsi.is_ready(), self.atr.is_ready()]):
return IncStrategySignal.HOLD()
# Use indicator values for signal generation
sma_value = self.sma.get_value()
rsi_value = self.rsi.get_value()
atr_value = self.atr.get_value()
# Generate signals based on indicator values
return self._generate_signal(close, sma_value, rsi_value, atr_value)
```
---
*The base indicator classes provide a solid foundation for building efficient, real-time indicators that maintain constant memory usage and processing time regardless of data history length.*

View File

@ -0,0 +1,702 @@
# Bollinger Bands Indicators
## Overview
Bollinger Bands are volatility indicators that consist of a moving average (middle band) and two standard deviation bands (upper and lower bands). They help identify overbought/oversold conditions and potential breakout opportunities. IncrementalTrader provides both simple price-based and OHLC-based implementations.
## BollingerBandsState
Standard Bollinger Bands implementation using closing prices and simple moving average.
### Features
- **Three Bands**: Upper, middle (SMA), and lower bands
- **Volatility Measurement**: Bands expand/contract with volatility
- **Mean Reversion Signals**: Price touching bands indicates potential reversal
- **Breakout Detection**: Price breaking through bands signals trend continuation
### Mathematical Formula
```
Middle Band = Simple Moving Average (SMA)
Upper Band = SMA + (Standard Deviation × Multiplier)
Lower Band = SMA - (Standard Deviation × Multiplier)
Standard Deviation = √(Σ(Price - SMA)² / Period)
```
### Class Definition
```python
from IncrementalTrader.strategies.indicators import BollingerBandsState
class BollingerBandsState(IndicatorState):
def __init__(self, period: int, std_dev_multiplier: float = 2.0):
super().__init__(period)
self.std_dev_multiplier = std_dev_multiplier
self.values = []
self.sum = 0.0
self.sum_squares = 0.0
# Band values
self.middle_band = 0.0
self.upper_band = 0.0
self.lower_band = 0.0
def update(self, value: float):
self.values.append(value)
self.sum += value
self.sum_squares += value * value
if len(self.values) > self.period:
old_value = self.values.pop(0)
self.sum -= old_value
self.sum_squares -= old_value * old_value
self.data_count += 1
self._calculate_bands()
def _calculate_bands(self):
if not self.is_ready():
return
n = len(self.values)
# Calculate SMA (middle band)
self.middle_band = self.sum / n
# Calculate standard deviation
variance = (self.sum_squares / n) - (self.middle_band * self.middle_band)
std_dev = math.sqrt(max(variance, 0))
# Calculate upper and lower bands
band_width = std_dev * self.std_dev_multiplier
self.upper_band = self.middle_band + band_width
self.lower_band = self.middle_band - band_width
def get_value(self) -> float:
"""Returns middle band (SMA) value."""
return self.middle_band
def get_upper_band(self) -> float:
return self.upper_band
def get_lower_band(self) -> float:
return self.lower_band
def get_middle_band(self) -> float:
return self.middle_band
def get_band_width(self) -> float:
"""Get the width between upper and lower bands."""
return self.upper_band - self.lower_band
def get_percent_b(self, price: float) -> float:
"""Calculate %B: position of price within the bands."""
if self.get_band_width() == 0:
return 0.5
return (price - self.lower_band) / self.get_band_width()
```
### Usage Examples
#### Basic Bollinger Bands Usage
```python
# Create 20-period Bollinger Bands with 2.0 standard deviation
bb = BollingerBandsState(period=20, std_dev_multiplier=2.0)
# Price data
prices = [100, 101, 99, 102, 98, 103, 97, 104, 96, 105, 95, 106, 94, 107, 93]
for price in prices:
bb.update(price)
if bb.is_ready():
print(f"Price: {price:.2f}")
print(f" Upper: {bb.get_upper_band():.2f}")
print(f" Middle: {bb.get_middle_band():.2f}")
print(f" Lower: {bb.get_lower_band():.2f}")
print(f" %B: {bb.get_percent_b(price):.2f}")
print(f" Width: {bb.get_band_width():.2f}")
```
#### Bollinger Bands Trading Signals
```python
class BollingerBandsSignals:
def __init__(self, period: int = 20, std_dev: float = 2.0):
self.bb = BollingerBandsState(period, std_dev)
self.previous_price = None
self.previous_percent_b = None
def update(self, price: float):
self.bb.update(price)
self.previous_price = price
def get_mean_reversion_signal(self, current_price: float) -> str:
"""Get mean reversion signals based on band touches."""
if not self.bb.is_ready():
return "HOLD"
percent_b = self.bb.get_percent_b(current_price)
# Oversold: price near or below lower band
if percent_b <= 0.1:
return "BUY"
# Overbought: price near or above upper band
elif percent_b >= 0.9:
return "SELL"
# Return to middle: exit positions
elif 0.4 <= percent_b <= 0.6:
return "EXIT"
return "HOLD"
def get_breakout_signal(self, current_price: float) -> str:
"""Get breakout signals based on band penetration."""
if not self.bb.is_ready() or self.previous_price is None:
return "HOLD"
upper_band = self.bb.get_upper_band()
lower_band = self.bb.get_lower_band()
# Bullish breakout: price breaks above upper band
if self.previous_price <= upper_band and current_price > upper_band:
return "BUY_BREAKOUT"
# Bearish breakout: price breaks below lower band
elif self.previous_price >= lower_band and current_price < lower_band:
return "SELL_BREAKOUT"
return "HOLD"
def get_squeeze_condition(self) -> bool:
"""Detect Bollinger Band squeeze (low volatility)."""
if not self.bb.is_ready():
return False
# Simple squeeze detection: band width below threshold
# You might want to compare with historical band width
band_width = self.bb.get_band_width()
middle_band = self.bb.get_middle_band()
# Squeeze when band width is less than 4% of middle band
return (band_width / middle_band) < 0.04
# Usage
bb_signals = BollingerBandsSignals(period=20, std_dev=2.0)
for price in prices:
bb_signals.update(price)
mean_reversion = bb_signals.get_mean_reversion_signal(price)
breakout = bb_signals.get_breakout_signal(price)
squeeze = bb_signals.get_squeeze_condition()
if mean_reversion != "HOLD":
print(f"Mean Reversion Signal: {mean_reversion} at {price:.2f}")
if breakout != "HOLD":
print(f"Breakout Signal: {breakout} at {price:.2f}")
if squeeze:
print(f"Bollinger Band Squeeze detected at {price:.2f}")
```
### Performance Characteristics
- **Time Complexity**: O(1) per update (after initial period)
- **Space Complexity**: O(period)
- **Memory Usage**: ~8 bytes per period + constant overhead
## BollingerBandsOHLCState
OHLC-based Bollinger Bands implementation using typical price (HLC/3) for more accurate volatility measurement.
### Features
- **OHLC Data Support**: Uses high, low, close for typical price calculation
- **Better Volatility Measurement**: More accurate than close-only bands
- **Intraday Analysis**: Accounts for intraday price action
- **Enhanced Signals**: More reliable signals due to complete price information
### Mathematical Formula
```
Typical Price = (High + Low + Close) / 3
Middle Band = SMA(Typical Price)
Upper Band = Middle Band + (Standard Deviation × Multiplier)
Lower Band = Middle Band - (Standard Deviation × Multiplier)
```
### Class Definition
```python
class BollingerBandsOHLCState(OHLCIndicatorState):
def __init__(self, period: int, std_dev_multiplier: float = 2.0):
super().__init__(period)
self.std_dev_multiplier = std_dev_multiplier
self.typical_prices = []
self.sum = 0.0
self.sum_squares = 0.0
# Band values
self.middle_band = 0.0
self.upper_band = 0.0
self.lower_band = 0.0
def _process_ohlc_data(self, high: float, low: float, close: float):
# Calculate typical price
typical_price = (high + low + close) / 3.0
self.typical_prices.append(typical_price)
self.sum += typical_price
self.sum_squares += typical_price * typical_price
if len(self.typical_prices) > self.period:
old_price = self.typical_prices.pop(0)
self.sum -= old_price
self.sum_squares -= old_price * old_price
self._calculate_bands()
def _calculate_bands(self):
if not self.is_ready():
return
n = len(self.typical_prices)
# Calculate SMA (middle band)
self.middle_band = self.sum / n
# Calculate standard deviation
variance = (self.sum_squares / n) - (self.middle_band * self.middle_band)
std_dev = math.sqrt(max(variance, 0))
# Calculate upper and lower bands
band_width = std_dev * self.std_dev_multiplier
self.upper_band = self.middle_band + band_width
self.lower_band = self.middle_band - band_width
def get_value(self) -> float:
"""Returns middle band (SMA) value."""
return self.middle_band
def get_upper_band(self) -> float:
return self.upper_band
def get_lower_band(self) -> float:
return self.lower_band
def get_middle_band(self) -> float:
return self.middle_band
def get_band_width(self) -> float:
return self.upper_band - self.lower_band
def get_percent_b_ohlc(self, high: float, low: float, close: float) -> float:
"""Calculate %B using OHLC data."""
typical_price = (high + low + close) / 3.0
if self.get_band_width() == 0:
return 0.5
return (typical_price - self.lower_band) / self.get_band_width()
```
### Usage Examples
#### OHLC Bollinger Bands Analysis
```python
# Create OHLC-based Bollinger Bands
bb_ohlc = BollingerBandsOHLCState(period=20, std_dev_multiplier=2.0)
# OHLC data: (high, low, close)
ohlc_data = [
(105.0, 102.0, 104.0),
(106.0, 103.0, 105.5),
(107.0, 104.0, 106.0),
(108.0, 105.0, 107.5),
(109.0, 106.0, 108.0)
]
for high, low, close in ohlc_data:
bb_ohlc.update_ohlc(high, low, close)
if bb_ohlc.is_ready():
typical_price = (high + low + close) / 3.0
percent_b = bb_ohlc.get_percent_b_ohlc(high, low, close)
print(f"OHLC: H={high:.2f}, L={low:.2f}, C={close:.2f}")
print(f" Typical Price: {typical_price:.2f}")
print(f" Upper: {bb_ohlc.get_upper_band():.2f}")
print(f" Middle: {bb_ohlc.get_middle_band():.2f}")
print(f" Lower: {bb_ohlc.get_lower_band():.2f}")
print(f" %B: {percent_b:.2f}")
```
#### Advanced OHLC Bollinger Bands Strategy
```python
class OHLCBollingerStrategy:
def __init__(self, period: int = 20, std_dev: float = 2.0):
self.bb = BollingerBandsOHLCState(period, std_dev)
self.previous_ohlc = None
def update(self, high: float, low: float, close: float):
self.bb.update_ohlc(high, low, close)
self.previous_ohlc = (high, low, close)
def analyze_candle_position(self, high: float, low: float, close: float) -> dict:
"""Analyze candle position relative to Bollinger Bands."""
if not self.bb.is_ready():
return {"analysis": "NOT_READY"}
upper_band = self.bb.get_upper_band()
lower_band = self.bb.get_lower_band()
middle_band = self.bb.get_middle_band()
# Analyze different price levels
analysis = {
"high_above_upper": high > upper_band,
"low_below_lower": low < lower_band,
"close_above_middle": close > middle_band,
"body_outside_bands": high > upper_band and low < lower_band,
"squeeze_breakout": False,
"signal": "HOLD"
}
# Detect squeeze breakout
band_width = self.bb.get_band_width()
if band_width / middle_band < 0.03: # Very narrow bands
if high > upper_band:
analysis["squeeze_breakout"] = True
analysis["signal"] = "BUY_BREAKOUT"
elif low < lower_band:
analysis["squeeze_breakout"] = True
analysis["signal"] = "SELL_BREAKOUT"
# Mean reversion signals
percent_b = self.bb.get_percent_b_ohlc(high, low, close)
if percent_b <= 0.1 and close > low: # Bounce from lower band
analysis["signal"] = "BUY_BOUNCE"
elif percent_b >= 0.9 and close < high: # Rejection from upper band
analysis["signal"] = "SELL_REJECTION"
return analysis
def get_support_resistance_levels(self) -> dict:
"""Get dynamic support and resistance levels."""
if not self.bb.is_ready():
return {}
return {
"resistance": self.bb.get_upper_band(),
"support": self.bb.get_lower_band(),
"pivot": self.bb.get_middle_band(),
"band_width": self.bb.get_band_width()
}
# Usage
ohlc_strategy = OHLCBollingerStrategy(period=20, std_dev=2.0)
for high, low, close in ohlc_data:
ohlc_strategy.update(high, low, close)
analysis = ohlc_strategy.analyze_candle_position(high, low, close)
levels = ohlc_strategy.get_support_resistance_levels()
if analysis.get("signal") != "HOLD":
print(f"Signal: {analysis['signal']}")
print(f"Analysis: {analysis}")
print(f"S/R Levels: {levels}")
```
### Performance Characteristics
- **Time Complexity**: O(1) per update (after initial period)
- **Space Complexity**: O(period)
- **Memory Usage**: ~8 bytes per period + constant overhead
## Comparison: BollingerBandsState vs BollingerBandsOHLCState
| Aspect | BollingerBandsState | BollingerBandsOHLCState |
|--------|---------------------|-------------------------|
| **Input Data** | Close prices only | High, Low, Close |
| **Calculation Base** | Close price | Typical price (HLC/3) |
| **Accuracy** | Good for trends | Better for volatility |
| **Signal Quality** | Standard | Enhanced |
| **Data Requirements** | Minimal | Complete OHLC |
### When to Use BollingerBandsState
- **Simple Analysis**: When only closing prices are available
- **Trend Following**: For basic trend and mean reversion analysis
- **Memory Efficiency**: When OHLC data is not necessary
- **Quick Implementation**: For rapid prototyping and testing
### When to Use BollingerBandsOHLCState
- **Complete Analysis**: When full OHLC data is available
- **Volatility Trading**: For more accurate volatility measurement
- **Intraday Trading**: When intraday price action matters
- **Professional Trading**: For more sophisticated trading strategies
## Advanced Usage Patterns
### Multi-Timeframe Bollinger Bands
```python
class MultiBollingerBands:
def __init__(self):
self.bb_short = BollingerBandsState(period=10, std_dev_multiplier=2.0)
self.bb_medium = BollingerBandsState(period=20, std_dev_multiplier=2.0)
self.bb_long = BollingerBandsState(period=50, std_dev_multiplier=2.0)
def update(self, price: float):
self.bb_short.update(price)
self.bb_medium.update(price)
self.bb_long.update(price)
def get_volatility_regime(self) -> str:
"""Determine volatility regime across timeframes."""
if not all([self.bb_short.is_ready(), self.bb_medium.is_ready(), self.bb_long.is_ready()]):
return "UNKNOWN"
# Compare band widths
short_width = self.bb_short.get_band_width() / self.bb_short.get_middle_band()
medium_width = self.bb_medium.get_band_width() / self.bb_medium.get_middle_band()
long_width = self.bb_long.get_band_width() / self.bb_long.get_middle_band()
avg_width = (short_width + medium_width + long_width) / 3
if avg_width > 0.08:
return "HIGH_VOLATILITY"
elif avg_width < 0.03:
return "LOW_VOLATILITY"
else:
return "NORMAL_VOLATILITY"
def get_trend_alignment(self, price: float) -> str:
"""Check trend alignment across timeframes."""
if not all([self.bb_short.is_ready(), self.bb_medium.is_ready(), self.bb_long.is_ready()]):
return "UNKNOWN"
# Check position relative to middle bands
above_short = price > self.bb_short.get_middle_band()
above_medium = price > self.bb_medium.get_middle_band()
above_long = price > self.bb_long.get_middle_band()
if all([above_short, above_medium, above_long]):
return "STRONG_BULLISH"
elif not any([above_short, above_medium, above_long]):
return "STRONG_BEARISH"
elif above_short and above_medium:
return "BULLISH"
elif not above_short and not above_medium:
return "BEARISH"
else:
return "MIXED"
# Usage
multi_bb = MultiBollingerBands()
for price in prices:
multi_bb.update(price)
volatility_regime = multi_bb.get_volatility_regime()
trend_alignment = multi_bb.get_trend_alignment(price)
print(f"Price: {price:.2f}, Volatility: {volatility_regime}, Trend: {trend_alignment}")
```
### Bollinger Bands with RSI Confluence
```python
class BollingerRSIStrategy:
def __init__(self, bb_period: int = 20, rsi_period: int = 14):
self.bb = BollingerBandsState(bb_period, 2.0)
self.rsi = SimpleRSIState(rsi_period)
def update(self, price: float):
self.bb.update(price)
self.rsi.update(price)
def get_confluence_signal(self, price: float) -> dict:
"""Get signals based on Bollinger Bands and RSI confluence."""
if not (self.bb.is_ready() and self.rsi.is_ready()):
return {"signal": "HOLD", "confidence": 0.0}
percent_b = self.bb.get_percent_b(price)
rsi_value = self.rsi.get_value()
# Bullish confluence: oversold RSI + lower band touch
if percent_b <= 0.1 and rsi_value <= 30:
confidence = min(0.9, (30 - rsi_value) / 20 + (0.1 - percent_b) * 5)
return {
"signal": "BUY",
"confidence": confidence,
"reason": "oversold_confluence",
"percent_b": percent_b,
"rsi": rsi_value
}
# Bearish confluence: overbought RSI + upper band touch
elif percent_b >= 0.9 and rsi_value >= 70:
confidence = min(0.9, (rsi_value - 70) / 20 + (percent_b - 0.9) * 5)
return {
"signal": "SELL",
"confidence": confidence,
"reason": "overbought_confluence",
"percent_b": percent_b,
"rsi": rsi_value
}
# Exit signals: return to middle
elif 0.4 <= percent_b <= 0.6 and 40 <= rsi_value <= 60:
return {
"signal": "EXIT",
"confidence": 0.5,
"reason": "return_to_neutral",
"percent_b": percent_b,
"rsi": rsi_value
}
return {"signal": "HOLD", "confidence": 0.0}
# Usage
bb_rsi_strategy = BollingerRSIStrategy(bb_period=20, rsi_period=14)
for price in prices:
bb_rsi_strategy.update(price)
signal_info = bb_rsi_strategy.get_confluence_signal(price)
if signal_info["signal"] != "HOLD":
print(f"Confluence Signal: {signal_info['signal']}")
print(f" Confidence: {signal_info['confidence']:.2f}")
print(f" Reason: {signal_info['reason']}")
print(f" %B: {signal_info.get('percent_b', 0):.2f}")
print(f" RSI: {signal_info.get('rsi', 0):.1f}")
```
## Integration with Strategies
### Bollinger Bands Mean Reversion Strategy
```python
class BollingerMeanReversionStrategy(IncStrategyBase):
def __init__(self, name: str, params: dict = None):
super().__init__(name, params)
# Initialize Bollinger Bands
bb_period = self.params.get('bb_period', 20)
bb_std_dev = self.params.get('bb_std_dev', 2.0)
self.bb = BollingerBandsOHLCState(bb_period, bb_std_dev)
# Strategy parameters
self.entry_threshold = self.params.get('entry_threshold', 0.1) # %B threshold
self.exit_threshold = self.params.get('exit_threshold', 0.5) # Return to middle
# State tracking
self.position_type = None
def _process_aggregated_data(self, timestamp: int, ohlcv: tuple) -> IncStrategySignal:
open_price, high, low, close, volume = ohlcv
# Update Bollinger Bands
self.bb.update_ohlc(high, low, close)
# Wait for indicator to be ready
if not self.bb.is_ready():
return IncStrategySignal.HOLD()
# Calculate %B
percent_b = self.bb.get_percent_b_ohlc(high, low, close)
band_width = self.bb.get_band_width()
middle_band = self.bb.get_middle_band()
# Entry signals
if percent_b <= self.entry_threshold and self.position_type != "LONG":
# Oversold condition - buy signal
confidence = min(0.9, (self.entry_threshold - percent_b) * 5)
self.position_type = "LONG"
return IncStrategySignal.BUY(
confidence=confidence,
metadata={
'percent_b': percent_b,
'band_width': band_width,
'signal_type': 'mean_reversion_buy',
'upper_band': self.bb.get_upper_band(),
'lower_band': self.bb.get_lower_band()
}
)
elif percent_b >= (1.0 - self.entry_threshold) and self.position_type != "SHORT":
# Overbought condition - sell signal
confidence = min(0.9, (percent_b - (1.0 - self.entry_threshold)) * 5)
self.position_type = "SHORT"
return IncStrategySignal.SELL(
confidence=confidence,
metadata={
'percent_b': percent_b,
'band_width': band_width,
'signal_type': 'mean_reversion_sell',
'upper_band': self.bb.get_upper_band(),
'lower_band': self.bb.get_lower_band()
}
)
# Exit signals
elif abs(percent_b - 0.5) <= (0.5 - self.exit_threshold):
# Return to middle - exit position
if self.position_type is not None:
exit_signal = IncStrategySignal.SELL() if self.position_type == "LONG" else IncStrategySignal.BUY()
exit_signal.confidence = 0.6
exit_signal.metadata = {
'percent_b': percent_b,
'signal_type': 'mean_reversion_exit',
'previous_position': self.position_type
}
self.position_type = None
return exit_signal
return IncStrategySignal.HOLD()
```
## Performance Optimization Tips
### 1. Choose the Right Implementation
```python
# For simple price analysis
bb = BollingerBandsState(period=20, std_dev_multiplier=2.0)
# For comprehensive OHLC analysis
bb_ohlc = BollingerBandsOHLCState(period=20, std_dev_multiplier=2.0)
```
### 2. Optimize Standard Deviation Calculation
```python
# Use incremental variance calculation for better performance
def incremental_variance(sum_val: float, sum_squares: float, count: int, mean: float) -> float:
"""Calculate variance incrementally."""
if count == 0:
return 0.0
return max(0.0, (sum_squares / count) - (mean * mean))
```
### 3. Cache Band Values for Multiple Calculations
```python
class CachedBollingerBands:
def __init__(self, period: int, std_dev: float = 2.0):
self.bb = BollingerBandsState(period, std_dev)
self._cached_bands = None
self._cache_valid = False
def update(self, price: float):
self.bb.update(price)
self._cache_valid = False
def get_bands(self) -> tuple:
if not self._cache_valid:
self._cached_bands = (
self.bb.get_upper_band(),
self.bb.get_middle_band(),
self.bb.get_lower_band()
)
self._cache_valid = True
return self._cached_bands
```
---
*Bollinger Bands are versatile indicators for volatility analysis and mean reversion trading. Use BollingerBandsState for simple price analysis or BollingerBandsOHLCState for comprehensive volatility measurement with complete OHLC data.*

View File

@ -0,0 +1,404 @@
# Moving Average Indicators
## Overview
Moving averages are fundamental trend-following indicators that smooth price data by creating a constantly updated average price. IncrementalTrader provides both Simple Moving Average (SMA) and Exponential Moving Average (EMA) implementations with O(1) time complexity.
## MovingAverageState (SMA)
Simple Moving Average that maintains a rolling window of prices.
### Features
- **O(1) Updates**: Constant time complexity per update
- **Memory Efficient**: Only stores necessary data points
- **Real-time Ready**: Immediate calculation without historical data dependency
### Mathematical Formula
```
SMA = (P₁ + P₂ + ... + Pₙ) / n
Where:
- P₁, P₂, ..., Pₙ are the last n price values
- n is the period
```
### Class Definition
```python
from IncrementalTrader.strategies.indicators import MovingAverageState
class MovingAverageState(IndicatorState):
def __init__(self, period: int):
super().__init__(period)
self.values = []
self.sum = 0.0
def update(self, value: float):
self.values.append(value)
self.sum += value
if len(self.values) > self.period:
old_value = self.values.pop(0)
self.sum -= old_value
self.data_count += 1
def get_value(self) -> float:
if not self.is_ready():
return 0.0
return self.sum / len(self.values)
```
### Usage Examples
#### Basic Usage
```python
# Create 20-period SMA
sma_20 = MovingAverageState(period=20)
# Update with price data
prices = [100, 101, 99, 102, 98, 103, 97, 104]
for price in prices:
sma_20.update(price)
if sma_20.is_ready():
print(f"SMA(20): {sma_20.get_value():.2f}")
```
#### Multiple Timeframes
```python
# Different period SMAs
sma_10 = MovingAverageState(period=10)
sma_20 = MovingAverageState(period=20)
sma_50 = MovingAverageState(period=50)
for price in price_stream:
# Update all SMAs
sma_10.update(price)
sma_20.update(price)
sma_50.update(price)
# Check for golden cross (SMA10 > SMA20)
if all([sma_10.is_ready(), sma_20.is_ready()]):
if sma_10.get_value() > sma_20.get_value():
print("Golden Cross detected!")
```
### Performance Characteristics
- **Time Complexity**: O(1) per update
- **Space Complexity**: O(period)
- **Memory Usage**: ~8 bytes per period (for float values)
## ExponentialMovingAverageState (EMA)
Exponential Moving Average that gives more weight to recent prices.
### Features
- **Exponential Weighting**: Recent prices have more influence
- **O(1) Memory**: Only stores current EMA value and multiplier
- **Responsive**: Reacts faster to price changes than SMA
### Mathematical Formula
```
EMA = (Price × α) + (Previous_EMA × (1 - α))
Where:
- α = 2 / (period + 1) (smoothing factor)
- Price is the current price
- Previous_EMA is the previous EMA value
```
### Class Definition
```python
class ExponentialMovingAverageState(IndicatorState):
def __init__(self, period: int):
super().__init__(period)
self.multiplier = 2.0 / (period + 1)
self.ema_value = 0.0
self.is_first_value = True
def update(self, value: float):
if self.is_first_value:
self.ema_value = value
self.is_first_value = False
else:
self.ema_value = (value * self.multiplier) + (self.ema_value * (1 - self.multiplier))
self.data_count += 1
def get_value(self) -> float:
return self.ema_value
```
### Usage Examples
#### Basic Usage
```python
# Create 12-period EMA
ema_12 = ExponentialMovingAverageState(period=12)
# Update with price data
for price in price_data:
ema_12.update(price)
print(f"EMA(12): {ema_12.get_value():.2f}")
```
#### MACD Calculation
```python
# MACD uses EMA12 and EMA26
ema_12 = ExponentialMovingAverageState(period=12)
ema_26 = ExponentialMovingAverageState(period=26)
macd_values = []
for price in price_data:
ema_12.update(price)
ema_26.update(price)
if ema_26.is_ready(): # EMA26 takes longer to be ready
macd = ema_12.get_value() - ema_26.get_value()
macd_values.append(macd)
print(f"MACD: {macd:.4f}")
```
### Performance Characteristics
- **Time Complexity**: O(1) per update
- **Space Complexity**: O(1)
- **Memory Usage**: ~24 bytes (constant)
## Comparison: SMA vs EMA
| Aspect | SMA | EMA |
|--------|-----|-----|
| **Responsiveness** | Slower | Faster |
| **Memory Usage** | O(period) | O(1) |
| **Smoothness** | Smoother | More volatile |
| **Lag** | Higher lag | Lower lag |
| **Noise Filtering** | Better | Moderate |
### When to Use SMA
- **Trend Identification**: Better for identifying long-term trends
- **Support/Resistance**: More reliable for support and resistance levels
- **Noise Reduction**: Better at filtering out market noise
- **Memory Constraints**: When memory usage is not a concern
### When to Use EMA
- **Quick Signals**: When you need faster response to price changes
- **Memory Efficiency**: When memory usage is critical
- **Short-term Trading**: Better for short-term trading strategies
- **Real-time Systems**: Ideal for high-frequency trading systems
## Advanced Usage Patterns
### Moving Average Crossover Strategy
```python
class MovingAverageCrossover:
def __init__(self, fast_period: int, slow_period: int):
self.fast_ma = MovingAverageState(fast_period)
self.slow_ma = MovingAverageState(slow_period)
self.previous_fast = 0.0
self.previous_slow = 0.0
def update(self, price: float):
self.previous_fast = self.fast_ma.get_value() if self.fast_ma.is_ready() else 0.0
self.previous_slow = self.slow_ma.get_value() if self.slow_ma.is_ready() else 0.0
self.fast_ma.update(price)
self.slow_ma.update(price)
def get_signal(self) -> str:
if not (self.fast_ma.is_ready() and self.slow_ma.is_ready()):
return "HOLD"
current_fast = self.fast_ma.get_value()
current_slow = self.slow_ma.get_value()
# Golden Cross: Fast MA crosses above Slow MA
if self.previous_fast <= self.previous_slow and current_fast > current_slow:
return "BUY"
# Death Cross: Fast MA crosses below Slow MA
if self.previous_fast >= self.previous_slow and current_fast < current_slow:
return "SELL"
return "HOLD"
# Usage
crossover = MovingAverageCrossover(fast_period=10, slow_period=20)
for price in price_stream:
crossover.update(price)
signal = crossover.get_signal()
if signal != "HOLD":
print(f"Signal: {signal} at price {price}")
```
### Adaptive Moving Average
```python
class AdaptiveMovingAverage:
def __init__(self, min_period: int = 5, max_period: int = 50):
self.min_period = min_period
self.max_period = max_period
self.sma_fast = MovingAverageState(min_period)
self.sma_slow = MovingAverageState(max_period)
self.current_ma = MovingAverageState(min_period)
def update(self, price: float):
self.sma_fast.update(price)
self.sma_slow.update(price)
if self.sma_slow.is_ready():
# Calculate volatility-based period
volatility = abs(self.sma_fast.get_value() - self.sma_slow.get_value())
normalized_vol = min(volatility / price, 0.1) # Cap at 10%
# Adjust period based on volatility
adaptive_period = int(self.min_period + (normalized_vol * (self.max_period - self.min_period)))
# Update current MA with adaptive period
if adaptive_period != self.current_ma.period:
self.current_ma = MovingAverageState(adaptive_period)
self.current_ma.update(price)
def get_value(self) -> float:
return self.current_ma.get_value()
def is_ready(self) -> bool:
return self.current_ma.is_ready()
```
## Error Handling and Edge Cases
### Robust Implementation
```python
class RobustMovingAverage(MovingAverageState):
def __init__(self, period: int):
if period <= 0:
raise ValueError("Period must be positive")
super().__init__(period)
def update(self, value: float):
# Validate input
if value is None:
self.logger.warning("Received None value, skipping update")
return
if math.isnan(value) or math.isinf(value):
self.logger.warning(f"Received invalid value: {value}, skipping update")
return
try:
super().update(value)
except Exception as e:
self.logger.error(f"Error updating moving average: {e}")
def get_value(self) -> float:
try:
return super().get_value()
except Exception as e:
self.logger.error(f"Error getting moving average value: {e}")
return 0.0
```
### Handling Missing Data
```python
def update_with_gap_handling(ma: MovingAverageState, value: float, timestamp: int, last_timestamp: int):
"""Update moving average with gap handling for missing data."""
# Define maximum acceptable gap (e.g., 5 minutes)
max_gap = 5 * 60 * 1000 # 5 minutes in milliseconds
if last_timestamp and (timestamp - last_timestamp) > max_gap:
# Large gap detected - reset the moving average
ma.reset()
print(f"Gap detected, resetting moving average")
ma.update(value)
```
## Integration with Strategies
### Strategy Implementation Example
```python
class MovingAverageStrategy(IncStrategyBase):
def __init__(self, name: str, params: dict = None):
super().__init__(name, params)
# Initialize moving averages
self.sma_short = MovingAverageState(self.params.get('short_period', 10))
self.sma_long = MovingAverageState(self.params.get('long_period', 20))
self.ema_signal = ExponentialMovingAverageState(self.params.get('signal_period', 5))
def _process_aggregated_data(self, timestamp: int, ohlcv: tuple) -> IncStrategySignal:
open_price, high, low, close, volume = ohlcv
# Update all moving averages
self.sma_short.update(close)
self.sma_long.update(close)
self.ema_signal.update(close)
# Wait for all indicators to be ready
if not all([self.sma_short.is_ready(), self.sma_long.is_ready(), self.ema_signal.is_ready()]):
return IncStrategySignal.HOLD()
# Get current values
sma_short_val = self.sma_short.get_value()
sma_long_val = self.sma_long.get_value()
ema_signal_val = self.ema_signal.get_value()
# Generate signals
if sma_short_val > sma_long_val and close > ema_signal_val:
confidence = min(0.9, (sma_short_val - sma_long_val) / sma_long_val * 10)
return IncStrategySignal.BUY(confidence=confidence)
elif sma_short_val < sma_long_val and close < ema_signal_val:
confidence = min(0.9, (sma_long_val - sma_short_val) / sma_long_val * 10)
return IncStrategySignal.SELL(confidence=confidence)
return IncStrategySignal.HOLD()
```
## Performance Optimization Tips
### 1. Choose the Right Moving Average
```python
# For memory-constrained environments
ema = ExponentialMovingAverageState(period=20) # O(1) memory
# For better smoothing and trend identification
sma = MovingAverageState(period=20) # O(period) memory
```
### 2. Batch Processing
```python
# Process multiple prices efficiently
def batch_update_moving_averages(mas: list, prices: list):
for price in prices:
for ma in mas:
ma.update(price)
# Return all values at once
return [ma.get_value() for ma in mas if ma.is_ready()]
```
### 3. Avoid Unnecessary Calculations
```python
# Cache ready state to avoid repeated checks
class CachedMovingAverage(MovingAverageState):
def __init__(self, period: int):
super().__init__(period)
self._is_ready_cached = False
def update(self, value: float):
super().update(value)
if not self._is_ready_cached:
self._is_ready_cached = self.data_count >= self.period
def is_ready(self) -> bool:
return self._is_ready_cached
```
---
*Moving averages are the foundation of many trading strategies. Choose SMA for smoother, more reliable signals, or EMA for faster response to price changes.*

View File

@ -0,0 +1,615 @@
# Oscillator Indicators
## Overview
Oscillator indicators help identify overbought and oversold conditions in the market. IncrementalTrader provides RSI (Relative Strength Index) implementations that measure the speed and magnitude of price changes.
## RSIState
Full RSI implementation using Wilder's smoothing method for accurate calculation.
### Features
- **Wilder's Smoothing**: Uses the traditional RSI calculation method
- **Overbought/Oversold**: Clear signals for market extremes
- **Momentum Measurement**: Indicates price momentum strength
- **Divergence Detection**: Helps identify potential trend reversals
### Mathematical Formula
```
RS = Average Gain / Average Loss
RSI = 100 - (100 / (1 + RS))
Where:
- Average Gain = Wilder's smoothing of positive price changes
- Average Loss = Wilder's smoothing of negative price changes
- Wilder's smoothing: ((previous_average × (period - 1)) + current_value) / period
```
### Class Definition
```python
from IncrementalTrader.strategies.indicators import RSIState
class RSIState(IndicatorState):
def __init__(self, period: int):
super().__init__(period)
self.gains = []
self.losses = []
self.avg_gain = 0.0
self.avg_loss = 0.0
self.previous_close = None
self.is_first_calculation = True
def update(self, value: float):
if self.previous_close is not None:
change = value - self.previous_close
gain = max(change, 0.0)
loss = max(-change, 0.0)
if self.is_first_calculation and len(self.gains) >= self.period:
# Initial calculation using simple average
self.avg_gain = sum(self.gains[-self.period:]) / self.period
self.avg_loss = sum(self.losses[-self.period:]) / self.period
self.is_first_calculation = False
elif not self.is_first_calculation:
# Wilder's smoothing
self.avg_gain = ((self.avg_gain * (self.period - 1)) + gain) / self.period
self.avg_loss = ((self.avg_loss * (self.period - 1)) + loss) / self.period
self.gains.append(gain)
self.losses.append(loss)
# Keep only necessary history
if len(self.gains) > self.period:
self.gains.pop(0)
self.losses.pop(0)
self.previous_close = value
self.data_count += 1
def get_value(self) -> float:
if not self.is_ready() or self.avg_loss == 0:
return 50.0 # Neutral RSI
rs = self.avg_gain / self.avg_loss
rsi = 100.0 - (100.0 / (1.0 + rs))
return rsi
def is_ready(self) -> bool:
return self.data_count > self.period and not self.is_first_calculation
```
### Usage Examples
#### Basic RSI Usage
```python
# Create 14-period RSI
rsi_14 = RSIState(period=14)
# Price data
prices = [44, 44.34, 44.09, 44.15, 43.61, 44.33, 44.83, 45.85, 47.25, 47.92, 46.23, 44.18, 46.57, 46.61, 46.5]
for price in prices:
rsi_14.update(price)
if rsi_14.is_ready():
rsi_value = rsi_14.get_value()
print(f"Price: {price:.2f}, RSI(14): {rsi_value:.2f}")
```
#### RSI Trading Signals
```python
class RSISignals:
def __init__(self, period: int = 14, overbought: float = 70.0, oversold: float = 30.0):
self.rsi = RSIState(period)
self.overbought = overbought
self.oversold = oversold
self.previous_rsi = None
def update(self, price: float):
self.rsi.update(price)
def get_signal(self) -> str:
if not self.rsi.is_ready():
return "HOLD"
current_rsi = self.rsi.get_value()
# Oversold bounce signal
if (self.previous_rsi is not None and
self.previous_rsi <= self.oversold and
current_rsi > self.oversold):
signal = "BUY"
# Overbought pullback signal
elif (self.previous_rsi is not None and
self.previous_rsi >= self.overbought and
current_rsi < self.overbought):
signal = "SELL"
else:
signal = "HOLD"
self.previous_rsi = current_rsi
return signal
def get_condition(self) -> str:
"""Get current market condition based on RSI."""
if not self.rsi.is_ready():
return "UNKNOWN"
rsi_value = self.rsi.get_value()
if rsi_value >= self.overbought:
return "OVERBOUGHT"
elif rsi_value <= self.oversold:
return "OVERSOLD"
else:
return "NEUTRAL"
# Usage
rsi_signals = RSISignals(period=14, overbought=70, oversold=30)
for price in prices:
rsi_signals.update(price)
signal = rsi_signals.get_signal()
condition = rsi_signals.get_condition()
if signal != "HOLD":
print(f"RSI Signal: {signal}, Condition: {condition}, Price: {price:.2f}")
```
### Performance Characteristics
- **Time Complexity**: O(1) per update (after initial period)
- **Space Complexity**: O(period)
- **Memory Usage**: ~16 bytes per period + constant overhead
## SimpleRSIState
Simplified RSI implementation using exponential smoothing for memory efficiency.
### Features
- **O(1) Memory**: Constant memory usage regardless of period
- **Exponential Smoothing**: Uses EMA-based calculation
- **Fast Computation**: No need to maintain gain/loss history
- **Approximate RSI**: Close approximation to traditional RSI
### Mathematical Formula
```
Gain = max(price_change, 0)
Loss = max(-price_change, 0)
EMA_Gain = EMA(Gain, period)
EMA_Loss = EMA(Loss, period)
RSI = 100 - (100 / (1 + EMA_Gain / EMA_Loss))
```
### Class Definition
```python
class SimpleRSIState(IndicatorState):
def __init__(self, period: int):
super().__init__(period)
self.alpha = 2.0 / (period + 1)
self.ema_gain = 0.0
self.ema_loss = 0.0
self.previous_close = None
self.is_first_value = True
def update(self, value: float):
if self.previous_close is not None:
change = value - self.previous_close
gain = max(change, 0.0)
loss = max(-change, 0.0)
if self.is_first_value:
self.ema_gain = gain
self.ema_loss = loss
self.is_first_value = False
else:
self.ema_gain = (gain * self.alpha) + (self.ema_gain * (1 - self.alpha))
self.ema_loss = (loss * self.alpha) + (self.ema_loss * (1 - self.alpha))
self.previous_close = value
self.data_count += 1
def get_value(self) -> float:
if not self.is_ready() or self.ema_loss == 0:
return 50.0 # Neutral RSI
rs = self.ema_gain / self.ema_loss
rsi = 100.0 - (100.0 / (1.0 + rs))
return rsi
def is_ready(self) -> bool:
return self.data_count > 1 and not self.is_first_value
```
### Usage Examples
#### Memory-Efficient RSI
```python
# Create memory-efficient RSI
simple_rsi = SimpleRSIState(period=14)
# Process large amounts of data with constant memory
for i, price in enumerate(large_price_dataset):
simple_rsi.update(price)
if i % 1000 == 0 and simple_rsi.is_ready(): # Print every 1000 updates
print(f"RSI after {i} updates: {simple_rsi.get_value():.2f}")
```
#### RSI Divergence Detection
```python
class RSIDivergence:
def __init__(self, period: int = 14, lookback: int = 20):
self.rsi = SimpleRSIState(period)
self.lookback = lookback
self.price_history = []
self.rsi_history = []
def update(self, price: float):
self.rsi.update(price)
if self.rsi.is_ready():
self.price_history.append(price)
self.rsi_history.append(self.rsi.get_value())
# Keep only recent history
if len(self.price_history) > self.lookback:
self.price_history.pop(0)
self.rsi_history.pop(0)
def detect_bullish_divergence(self) -> bool:
"""Detect bullish divergence: price makes lower low, RSI makes higher low."""
if len(self.price_history) < self.lookback:
return False
# Find recent lows
price_low_idx = self.price_history.index(min(self.price_history[-10:]))
rsi_low_idx = self.rsi_history.index(min(self.rsi_history[-10:]))
# Check for divergence pattern
if (price_low_idx < len(self.price_history) - 3 and
rsi_low_idx < len(self.rsi_history) - 3):
recent_price_low = min(self.price_history[-3:])
recent_rsi_low = min(self.rsi_history[-3:])
# Bullish divergence: price lower low, RSI higher low
if (recent_price_low < self.price_history[price_low_idx] and
recent_rsi_low > self.rsi_history[rsi_low_idx]):
return True
return False
def detect_bearish_divergence(self) -> bool:
"""Detect bearish divergence: price makes higher high, RSI makes lower high."""
if len(self.price_history) < self.lookback:
return False
# Find recent highs
price_high_idx = self.price_history.index(max(self.price_history[-10:]))
rsi_high_idx = self.rsi_history.index(max(self.rsi_history[-10:]))
# Check for divergence pattern
if (price_high_idx < len(self.price_history) - 3 and
rsi_high_idx < len(self.rsi_history) - 3):
recent_price_high = max(self.price_history[-3:])
recent_rsi_high = max(self.rsi_history[-3:])
# Bearish divergence: price higher high, RSI lower high
if (recent_price_high > self.price_history[price_high_idx] and
recent_rsi_high < self.rsi_history[rsi_high_idx]):
return True
return False
# Usage
divergence_detector = RSIDivergence(period=14, lookback=20)
for price in price_data:
divergence_detector.update(price)
if divergence_detector.detect_bullish_divergence():
print(f"Bullish RSI divergence detected at price {price:.2f}")
if divergence_detector.detect_bearish_divergence():
print(f"Bearish RSI divergence detected at price {price:.2f}")
```
### Performance Characteristics
- **Time Complexity**: O(1) per update
- **Space Complexity**: O(1)
- **Memory Usage**: ~32 bytes (constant)
## Comparison: RSIState vs SimpleRSIState
| Aspect | RSIState | SimpleRSIState |
|--------|----------|----------------|
| **Memory Usage** | O(period) | O(1) |
| **Calculation Method** | Wilder's Smoothing | Exponential Smoothing |
| **Accuracy** | Higher (traditional) | Good (approximation) |
| **Responsiveness** | Standard | Slightly more responsive |
| **Historical Compatibility** | Traditional RSI | Modern approximation |
### When to Use RSIState
- **Precise Calculations**: When you need exact traditional RSI values
- **Backtesting**: For historical analysis and strategy validation
- **Research**: When studying exact RSI behavior and patterns
- **Small Periods**: When period is small (< 20) and memory isn't an issue
### When to Use SimpleRSIState
- **Memory Efficiency**: When processing large amounts of data
- **Real-time Systems**: For high-frequency trading applications
- **Approximate Analysis**: When close approximation is sufficient
- **Large Periods**: When using large RSI periods (> 50)
## Advanced Usage Patterns
### Multi-Timeframe RSI Analysis
```python
class MultiTimeframeRSI:
def __init__(self):
self.rsi_short = SimpleRSIState(period=7) # Short-term momentum
self.rsi_medium = SimpleRSIState(period=14) # Standard RSI
self.rsi_long = SimpleRSIState(period=21) # Long-term momentum
def update(self, price: float):
self.rsi_short.update(price)
self.rsi_medium.update(price)
self.rsi_long.update(price)
def get_momentum_regime(self) -> str:
"""Determine current momentum regime."""
if not all([self.rsi_short.is_ready(), self.rsi_medium.is_ready(), self.rsi_long.is_ready()]):
return "UNKNOWN"
short_rsi = self.rsi_short.get_value()
medium_rsi = self.rsi_medium.get_value()
long_rsi = self.rsi_long.get_value()
# All timeframes bullish
if all(rsi > 50 for rsi in [short_rsi, medium_rsi, long_rsi]):
return "STRONG_BULLISH"
# All timeframes bearish
elif all(rsi < 50 for rsi in [short_rsi, medium_rsi, long_rsi]):
return "STRONG_BEARISH"
# Mixed signals
elif short_rsi > 50 and medium_rsi > 50:
return "BULLISH"
elif short_rsi < 50 and medium_rsi < 50:
return "BEARISH"
else:
return "MIXED"
def get_overbought_oversold_consensus(self) -> str:
"""Get consensus on overbought/oversold conditions."""
if not all([self.rsi_short.is_ready(), self.rsi_medium.is_ready(), self.rsi_long.is_ready()]):
return "UNKNOWN"
rsi_values = [self.rsi_short.get_value(), self.rsi_medium.get_value(), self.rsi_long.get_value()]
overbought_count = sum(1 for rsi in rsi_values if rsi >= 70)
oversold_count = sum(1 for rsi in rsi_values if rsi <= 30)
if overbought_count >= 2:
return "OVERBOUGHT"
elif oversold_count >= 2:
return "OVERSOLD"
else:
return "NEUTRAL"
# Usage
multi_rsi = MultiTimeframeRSI()
for price in price_data:
multi_rsi.update(price)
regime = multi_rsi.get_momentum_regime()
consensus = multi_rsi.get_overbought_oversold_consensus()
print(f"Price: {price:.2f}, Momentum: {regime}, Condition: {consensus}")
```
### RSI with Dynamic Thresholds
```python
class AdaptiveRSI:
def __init__(self, period: int = 14, lookback: int = 50):
self.rsi = SimpleRSIState(period)
self.lookback = lookback
self.rsi_history = []
def update(self, price: float):
self.rsi.update(price)
if self.rsi.is_ready():
self.rsi_history.append(self.rsi.get_value())
# Keep only recent history
if len(self.rsi_history) > self.lookback:
self.rsi_history.pop(0)
def get_adaptive_thresholds(self) -> tuple:
"""Calculate adaptive overbought/oversold thresholds."""
if len(self.rsi_history) < 20:
return 70.0, 30.0 # Default thresholds
# Calculate percentiles for adaptive thresholds
sorted_rsi = sorted(self.rsi_history)
# Use 80th and 20th percentiles as adaptive thresholds
overbought_threshold = sorted_rsi[int(len(sorted_rsi) * 0.8)]
oversold_threshold = sorted_rsi[int(len(sorted_rsi) * 0.2)]
# Ensure minimum separation
if overbought_threshold - oversold_threshold < 20:
mid = (overbought_threshold + oversold_threshold) / 2
overbought_threshold = mid + 10
oversold_threshold = mid - 10
return overbought_threshold, oversold_threshold
def get_adaptive_signal(self) -> str:
"""Get signal using adaptive thresholds."""
if not self.rsi.is_ready() or len(self.rsi_history) < 2:
return "HOLD"
current_rsi = self.rsi.get_value()
previous_rsi = self.rsi_history[-2]
overbought, oversold = self.get_adaptive_thresholds()
# Adaptive oversold bounce
if previous_rsi <= oversold and current_rsi > oversold:
return "BUY"
# Adaptive overbought pullback
elif previous_rsi >= overbought and current_rsi < overbought:
return "SELL"
return "HOLD"
# Usage
adaptive_rsi = AdaptiveRSI(period=14, lookback=50)
for price in price_data:
adaptive_rsi.update(price)
signal = adaptive_rsi.get_adaptive_signal()
overbought, oversold = adaptive_rsi.get_adaptive_thresholds()
if signal != "HOLD":
print(f"Adaptive RSI Signal: {signal}, Thresholds: OB={overbought:.1f}, OS={oversold:.1f}")
```
## Integration with Strategies
### RSI Mean Reversion Strategy
```python
class RSIMeanReversionStrategy(IncStrategyBase):
def __init__(self, name: str, params: dict = None):
super().__init__(name, params)
# Initialize RSI
self.rsi = RSIState(self.params.get('rsi_period', 14))
# RSI parameters
self.overbought = self.params.get('overbought', 70.0)
self.oversold = self.params.get('oversold', 30.0)
self.exit_neutral = self.params.get('exit_neutral', 50.0)
# State tracking
self.previous_rsi = None
self.position_type = None
def _process_aggregated_data(self, timestamp: int, ohlcv: tuple) -> IncStrategySignal:
open_price, high, low, close, volume = ohlcv
# Update RSI
self.rsi.update(close)
# Wait for RSI to be ready
if not self.rsi.is_ready():
return IncStrategySignal.HOLD()
current_rsi = self.rsi.get_value()
# Entry signals
if self.previous_rsi is not None:
# Oversold bounce (mean reversion up)
if (self.previous_rsi <= self.oversold and
current_rsi > self.oversold and
self.position_type != "LONG"):
confidence = min(0.9, (self.oversold - self.previous_rsi) / 20.0)
self.position_type = "LONG"
return IncStrategySignal.BUY(
confidence=confidence,
metadata={
'rsi': current_rsi,
'previous_rsi': self.previous_rsi,
'signal_type': 'oversold_bounce'
}
)
# Overbought pullback (mean reversion down)
elif (self.previous_rsi >= self.overbought and
current_rsi < self.overbought and
self.position_type != "SHORT"):
confidence = min(0.9, (self.previous_rsi - self.overbought) / 20.0)
self.position_type = "SHORT"
return IncStrategySignal.SELL(
confidence=confidence,
metadata={
'rsi': current_rsi,
'previous_rsi': self.previous_rsi,
'signal_type': 'overbought_pullback'
}
)
# Exit signals (return to neutral)
elif (self.position_type == "LONG" and current_rsi >= self.exit_neutral):
self.position_type = None
return IncStrategySignal.SELL(confidence=0.5, metadata={'signal_type': 'exit_long'})
elif (self.position_type == "SHORT" and current_rsi <= self.exit_neutral):
self.position_type = None
return IncStrategySignal.BUY(confidence=0.5, metadata={'signal_type': 'exit_short'})
self.previous_rsi = current_rsi
return IncStrategySignal.HOLD()
```
## Performance Optimization Tips
### 1. Choose the Right RSI Implementation
```python
# For memory-constrained environments
rsi = SimpleRSIState(period=14) # O(1) memory
# For precise traditional RSI
rsi = RSIState(period=14) # O(period) memory
```
### 2. Batch Processing for Multiple RSIs
```python
def update_multiple_rsis(rsis: list, price: float):
"""Efficiently update multiple RSI indicators."""
for rsi in rsis:
rsi.update(price)
return [rsi.get_value() for rsi in rsis if rsi.is_ready()]
```
### 3. Cache RSI Values for Complex Calculations
```python
class CachedRSI:
def __init__(self, period: int):
self.rsi = SimpleRSIState(period)
self._cached_value = 50.0
self._cache_valid = False
def update(self, price: float):
self.rsi.update(price)
self._cache_valid = False
def get_value(self) -> float:
if not self._cache_valid:
self._cached_value = self.rsi.get_value()
self._cache_valid = True
return self._cached_value
```
---
*RSI indicators are essential for identifying momentum and overbought/oversold conditions. Use RSIState for traditional analysis or SimpleRSIState for memory efficiency in high-frequency applications.*

View File

@ -0,0 +1,577 @@
# Trend Indicators
## Overview
Trend indicators help identify the direction and strength of market trends. IncrementalTrader provides Supertrend implementations that combine price action with volatility to generate clear trend signals.
## SupertrendState
Individual Supertrend indicator that tracks trend direction and provides support/resistance levels.
### Features
- **Trend Direction**: Clear bullish/bearish trend identification
- **Dynamic Support/Resistance**: Adaptive levels based on volatility
- **ATR-Based**: Uses Average True Range for volatility adjustment
- **Real-time Updates**: Incremental calculation for live trading
### Mathematical Formula
```
Basic Upper Band = (High + Low) / 2 + (Multiplier × ATR)
Basic Lower Band = (High + Low) / 2 - (Multiplier × ATR)
Final Upper Band = Basic Upper Band < Previous Final Upper Band OR Previous Close > Previous Final Upper Band
? Basic Upper Band : Previous Final Upper Band
Final Lower Band = Basic Lower Band > Previous Final Lower Band OR Previous Close < Previous Final Lower Band
? Basic Lower Band : Previous Final Lower Band
Supertrend = Close <= Final Lower Band ? Final Lower Band : Final Upper Band
Trend = Close <= Final Lower Band ? DOWN : UP
```
### Class Definition
```python
from IncrementalTrader.strategies.indicators import SupertrendState
class SupertrendState(OHLCIndicatorState):
def __init__(self, period: int, multiplier: float):
super().__init__(period)
self.multiplier = multiplier
self.atr = SimpleATRState(period)
# Supertrend state
self.supertrend_value = 0.0
self.trend = 1 # 1 for up, -1 for down
self.final_upper_band = 0.0
self.final_lower_band = 0.0
self.previous_close = 0.0
def _process_ohlc_data(self, high: float, low: float, close: float):
# Update ATR
self.atr.update_ohlc(high, low, close)
if not self.atr.is_ready():
return
# Calculate basic bands
hl2 = (high + low) / 2.0
atr_value = self.atr.get_value()
basic_upper_band = hl2 + (self.multiplier * atr_value)
basic_lower_band = hl2 - (self.multiplier * atr_value)
# Calculate final bands
if self.data_count == 1:
self.final_upper_band = basic_upper_band
self.final_lower_band = basic_lower_band
else:
# Final upper band logic
if basic_upper_band < self.final_upper_band or self.previous_close > self.final_upper_band:
self.final_upper_band = basic_upper_band
# Final lower band logic
if basic_lower_band > self.final_lower_band or self.previous_close < self.final_lower_band:
self.final_lower_band = basic_lower_band
# Determine trend and supertrend value
if close <= self.final_lower_band:
self.trend = -1 # Downtrend
self.supertrend_value = self.final_lower_band
else:
self.trend = 1 # Uptrend
self.supertrend_value = self.final_upper_band
self.previous_close = close
def get_value(self) -> float:
return self.supertrend_value
def get_trend(self) -> int:
"""Get current trend direction: 1 for up, -1 for down."""
return self.trend
def is_bullish(self) -> bool:
"""Check if current trend is bullish."""
return self.trend == 1
def is_bearish(self) -> bool:
"""Check if current trend is bearish."""
return self.trend == -1
```
### Usage Examples
#### Basic Supertrend Usage
```python
# Create Supertrend with 10-period ATR and 3.0 multiplier
supertrend = SupertrendState(period=10, multiplier=3.0)
# OHLC data: (high, low, close)
ohlc_data = [
(105.0, 102.0, 104.0),
(106.0, 103.0, 105.5),
(107.0, 104.0, 106.0),
(108.0, 105.0, 107.5)
]
for high, low, close in ohlc_data:
supertrend.update_ohlc(high, low, close)
if supertrend.is_ready():
trend_direction = "BULLISH" if supertrend.is_bullish() else "BEARISH"
print(f"Supertrend: {supertrend.get_value():.2f}, Trend: {trend_direction}")
```
#### Trend Change Detection
```python
class SupertrendSignals:
def __init__(self, period: int = 10, multiplier: float = 3.0):
self.supertrend = SupertrendState(period, multiplier)
self.previous_trend = None
def update(self, high: float, low: float, close: float):
self.supertrend.update_ohlc(high, low, close)
def get_signal(self) -> str:
if not self.supertrend.is_ready():
return "HOLD"
current_trend = self.supertrend.get_trend()
# Check for trend change
if self.previous_trend is not None and self.previous_trend != current_trend:
if current_trend == 1:
signal = "BUY" # Trend changed to bullish
else:
signal = "SELL" # Trend changed to bearish
else:
signal = "HOLD"
self.previous_trend = current_trend
return signal
def get_support_resistance(self) -> float:
"""Get current support/resistance level."""
return self.supertrend.get_value()
# Usage
signals = SupertrendSignals(period=10, multiplier=3.0)
for high, low, close in ohlc_data:
signals.update(high, low, close)
signal = signals.get_signal()
support_resistance = signals.get_support_resistance()
if signal != "HOLD":
print(f"Signal: {signal} at {close:.2f}, S/R: {support_resistance:.2f}")
```
### Performance Characteristics
- **Time Complexity**: O(1) per update
- **Space Complexity**: O(ATR_period)
- **Memory Usage**: ~8 bytes per ATR period + constant overhead
## SupertrendCollection
Collection of multiple Supertrend indicators for meta-trend analysis.
### Features
- **Multiple Timeframes**: Combines different Supertrend configurations
- **Consensus Signals**: Requires agreement among multiple indicators
- **Trend Strength**: Measures trend strength through consensus
- **Flexible Configuration**: Customizable periods and multipliers
### Class Definition
```python
class SupertrendCollection:
def __init__(self, configs: list):
"""
Initialize with list of (period, multiplier) tuples.
Example: [(10, 3.0), (14, 2.0), (21, 1.5)]
"""
self.supertrendss = []
for period, multiplier in configs:
self.supertrendss.append(SupertrendState(period, multiplier))
self.configs = configs
def update_ohlc(self, high: float, low: float, close: float):
"""Update all Supertrend indicators."""
for st in self.supertrendss:
st.update_ohlc(high, low, close)
def is_ready(self) -> bool:
"""Check if all indicators are ready."""
return all(st.is_ready() for st in self.supertrendss)
def get_consensus_trend(self) -> int:
"""Get consensus trend: 1 for bullish, -1 for bearish, 0 for mixed."""
if not self.is_ready():
return 0
trends = [st.get_trend() for st in self.supertrendss]
bullish_count = sum(1 for trend in trends if trend == 1)
bearish_count = sum(1 for trend in trends if trend == -1)
if bullish_count > bearish_count:
return 1
elif bearish_count > bullish_count:
return -1
else:
return 0
def get_trend_strength(self) -> float:
"""Get trend strength as percentage of indicators agreeing."""
if not self.is_ready():
return 0.0
consensus_trend = self.get_consensus_trend()
if consensus_trend == 0:
return 0.0
trends = [st.get_trend() for st in self.supertrendss]
agreeing_count = sum(1 for trend in trends if trend == consensus_trend)
return agreeing_count / len(trends)
def get_supertrend_values(self) -> list:
"""Get all Supertrend values."""
return [st.get_value() for st in self.supertrendss if st.is_ready()]
def get_average_supertrend(self) -> float:
"""Get average Supertrend value."""
values = self.get_supertrend_values()
return sum(values) / len(values) if values else 0.0
```
### Usage Examples
#### Multi-Timeframe Trend Analysis
```python
# Create collection with different configurations
configs = [
(10, 3.0), # Fast Supertrend
(14, 2.5), # Medium Supertrend
(21, 2.0) # Slow Supertrend
]
supertrend_collection = SupertrendCollection(configs)
for high, low, close in ohlc_data:
supertrend_collection.update_ohlc(high, low, close)
if supertrend_collection.is_ready():
consensus = supertrend_collection.get_consensus_trend()
strength = supertrend_collection.get_trend_strength()
avg_supertrend = supertrend_collection.get_average_supertrend()
trend_name = {1: "BULLISH", -1: "BEARISH", 0: "MIXED"}[consensus]
print(f"Consensus: {trend_name}, Strength: {strength:.1%}, Avg S/R: {avg_supertrend:.2f}")
```
#### Meta-Trend Strategy
```python
class MetaTrendStrategy:
def __init__(self):
# Multiple Supertrend configurations
self.supertrend_collection = SupertrendCollection([
(10, 3.0), # Fast
(14, 2.5), # Medium
(21, 2.0), # Slow
(28, 1.5) # Very slow
])
self.previous_consensus = None
def update(self, high: float, low: float, close: float):
self.supertrend_collection.update_ohlc(high, low, close)
def get_meta_signal(self) -> dict:
if not self.supertrend_collection.is_ready():
return {"signal": "HOLD", "confidence": 0.0, "strength": 0.0}
current_consensus = self.supertrend_collection.get_consensus_trend()
strength = self.supertrend_collection.get_trend_strength()
# Check for consensus change
signal = "HOLD"
if self.previous_consensus is not None and self.previous_consensus != current_consensus:
if current_consensus == 1:
signal = "BUY"
elif current_consensus == -1:
signal = "SELL"
# Calculate confidence based on strength and consensus
confidence = strength if current_consensus != 0 else 0.0
self.previous_consensus = current_consensus
return {
"signal": signal,
"confidence": confidence,
"strength": strength,
"consensus": current_consensus,
"avg_supertrend": self.supertrend_collection.get_average_supertrend()
}
# Usage
meta_strategy = MetaTrendStrategy()
for high, low, close in ohlc_data:
meta_strategy.update(high, low, close)
result = meta_strategy.get_meta_signal()
if result["signal"] != "HOLD":
print(f"Meta Signal: {result['signal']}, Confidence: {result['confidence']:.1%}")
```
### Performance Characteristics
- **Time Complexity**: O(n) per update (where n is number of Supertrends)
- **Space Complexity**: O(sum of all ATR periods)
- **Memory Usage**: Scales with number of indicators
## Advanced Usage Patterns
### Adaptive Supertrend
```python
class AdaptiveSupertrend:
def __init__(self, base_period: int = 14, base_multiplier: float = 2.0):
self.base_period = base_period
self.base_multiplier = base_multiplier
# Volatility measurement for adaptation
self.atr_short = SimpleATRState(period=5)
self.atr_long = SimpleATRState(period=20)
# Current adaptive Supertrend
self.current_supertrend = SupertrendState(base_period, base_multiplier)
# Adaptation parameters
self.min_multiplier = 1.0
self.max_multiplier = 4.0
def update_ohlc(self, high: float, low: float, close: float):
# Update volatility measurements
self.atr_short.update_ohlc(high, low, close)
self.atr_long.update_ohlc(high, low, close)
# Calculate adaptive multiplier
if self.atr_long.is_ready() and self.atr_short.is_ready():
volatility_ratio = self.atr_short.get_value() / self.atr_long.get_value()
# Adjust multiplier based on volatility
adaptive_multiplier = self.base_multiplier * volatility_ratio
adaptive_multiplier = max(self.min_multiplier, min(self.max_multiplier, adaptive_multiplier))
# Update Supertrend if multiplier changed significantly
if abs(adaptive_multiplier - self.current_supertrend.multiplier) > 0.1:
self.current_supertrend = SupertrendState(self.base_period, adaptive_multiplier)
# Update current Supertrend
self.current_supertrend.update_ohlc(high, low, close)
def get_value(self) -> float:
return self.current_supertrend.get_value()
def get_trend(self) -> int:
return self.current_supertrend.get_trend()
def is_ready(self) -> bool:
return self.current_supertrend.is_ready()
def get_current_multiplier(self) -> float:
return self.current_supertrend.multiplier
# Usage
adaptive_st = AdaptiveSupertrend(base_period=14, base_multiplier=2.0)
for high, low, close in ohlc_data:
adaptive_st.update_ohlc(high, low, close)
if adaptive_st.is_ready():
trend = "BULLISH" if adaptive_st.get_trend() == 1 else "BEARISH"
multiplier = adaptive_st.get_current_multiplier()
print(f"Adaptive Supertrend: {adaptive_st.get_value():.2f}, "
f"Trend: {trend}, Multiplier: {multiplier:.2f}")
```
### Supertrend with Stop Loss Management
```python
class SupertrendStopLoss:
def __init__(self, period: int = 14, multiplier: float = 2.0, buffer_percent: float = 0.5):
self.supertrend = SupertrendState(period, multiplier)
self.buffer_percent = buffer_percent / 100.0
self.current_position = None # "LONG", "SHORT", or None
self.entry_price = 0.0
self.stop_loss = 0.0
def update(self, high: float, low: float, close: float):
previous_trend = self.supertrend.get_trend() if self.supertrend.is_ready() else None
self.supertrend.update_ohlc(high, low, close)
if not self.supertrend.is_ready():
return
current_trend = self.supertrend.get_trend()
supertrend_value = self.supertrend.get_value()
# Check for trend change (entry signal)
if previous_trend is not None and previous_trend != current_trend:
if current_trend == 1: # Bullish trend
self.enter_long(close, supertrend_value)
else: # Bearish trend
self.enter_short(close, supertrend_value)
# Update stop loss for existing position
if self.current_position:
self.update_stop_loss(supertrend_value)
def enter_long(self, price: float, supertrend_value: float):
self.current_position = "LONG"
self.entry_price = price
self.stop_loss = supertrend_value * (1 - self.buffer_percent)
print(f"LONG entry at {price:.2f}, Stop: {self.stop_loss:.2f}")
def enter_short(self, price: float, supertrend_value: float):
self.current_position = "SHORT"
self.entry_price = price
self.stop_loss = supertrend_value * (1 + self.buffer_percent)
print(f"SHORT entry at {price:.2f}, Stop: {self.stop_loss:.2f}")
def update_stop_loss(self, supertrend_value: float):
if self.current_position == "LONG":
new_stop = supertrend_value * (1 - self.buffer_percent)
if new_stop > self.stop_loss: # Only move stop up
self.stop_loss = new_stop
elif self.current_position == "SHORT":
new_stop = supertrend_value * (1 + self.buffer_percent)
if new_stop < self.stop_loss: # Only move stop down
self.stop_loss = new_stop
def check_stop_loss(self, current_price: float) -> bool:
"""Check if stop loss is hit."""
if not self.current_position:
return False
if self.current_position == "LONG" and current_price <= self.stop_loss:
print(f"LONG stop loss hit at {current_price:.2f}")
self.current_position = None
return True
elif self.current_position == "SHORT" and current_price >= self.stop_loss:
print(f"SHORT stop loss hit at {current_price:.2f}")
self.current_position = None
return True
return False
# Usage
st_stop_loss = SupertrendStopLoss(period=14, multiplier=2.0, buffer_percent=0.5)
for high, low, close in ohlc_data:
st_stop_loss.update(high, low, close)
# Check stop loss on each update
if st_stop_loss.check_stop_loss(close):
print("Position closed due to stop loss")
```
## Integration with Strategies
### Supertrend Strategy Example
```python
class SupertrendStrategy(IncStrategyBase):
def __init__(self, name: str, params: dict = None):
super().__init__(name, params)
# Initialize Supertrend collection
configs = self.params.get('supertrend_configs', [(10, 3.0), (14, 2.5), (21, 2.0)])
self.supertrend_collection = SupertrendCollection(configs)
# Strategy parameters
self.min_strength = self.params.get('min_strength', 0.75)
self.previous_consensus = None
def _process_aggregated_data(self, timestamp: int, ohlcv: tuple) -> IncStrategySignal:
open_price, high, low, close, volume = ohlcv
# Update Supertrend collection
self.supertrend_collection.update_ohlc(high, low, close)
# Wait for indicators to be ready
if not self.supertrend_collection.is_ready():
return IncStrategySignal.HOLD()
# Get consensus and strength
current_consensus = self.supertrend_collection.get_consensus_trend()
strength = self.supertrend_collection.get_trend_strength()
# Check for strong consensus change
if (self.previous_consensus is not None and
self.previous_consensus != current_consensus and
strength >= self.min_strength):
if current_consensus == 1:
# Strong bullish consensus
return IncStrategySignal.BUY(
confidence=strength,
metadata={
'consensus': current_consensus,
'strength': strength,
'avg_supertrend': self.supertrend_collection.get_average_supertrend()
}
)
elif current_consensus == -1:
# Strong bearish consensus
return IncStrategySignal.SELL(
confidence=strength,
metadata={
'consensus': current_consensus,
'strength': strength,
'avg_supertrend': self.supertrend_collection.get_average_supertrend()
}
)
self.previous_consensus = current_consensus
return IncStrategySignal.HOLD()
```
## Performance Optimization Tips
### 1. Choose Appropriate Configurations
```python
# For fast signals (more noise)
fast_configs = [(7, 3.0), (10, 2.5)]
# For balanced signals
balanced_configs = [(10, 3.0), (14, 2.5), (21, 2.0)]
# For slow, reliable signals
slow_configs = [(14, 2.0), (21, 1.5), (28, 1.0)]
```
### 2. Optimize Memory Usage
```python
# Use SimpleATRState for memory efficiency
class MemoryEfficientSupertrend(SupertrendState):
def __init__(self, period: int, multiplier: float):
super().__init__(period, multiplier)
# Replace ATRState with SimpleATRState
self.atr = SimpleATRState(period)
```
### 3. Batch Processing
```python
def update_multiple_supertrends(supertrends: list, high: float, low: float, close: float):
"""Efficiently update multiple Supertrend indicators."""
for st in supertrends:
st.update_ohlc(high, low, close)
return [(st.get_value(), st.get_trend()) for st in supertrends if st.is_ready()]
```
---
*Supertrend indicators provide clear trend direction and dynamic support/resistance levels. Use single Supertrend for simple trend following or SupertrendCollection for robust meta-trend analysis.*

View File

@ -0,0 +1,546 @@
# Volatility Indicators
## Overview
Volatility indicators measure the rate of price change and market uncertainty. IncrementalTrader provides Average True Range (ATR) implementations that help assess market volatility and set appropriate stop-loss levels.
## ATRState (Average True Range)
Full ATR implementation that maintains a moving average of True Range values.
### Features
- **True Range Calculation**: Accounts for gaps between trading sessions
- **Volatility Measurement**: Provides absolute volatility measurement
- **Stop-Loss Guidance**: Helps set dynamic stop-loss levels
- **Trend Strength**: Indicates trend strength through volatility
### Mathematical Formula
```
True Range = max(
High - Low,
|High - Previous_Close|,
|Low - Previous_Close|
)
ATR = Moving_Average(True_Range, period)
```
### Class Definition
```python
from IncrementalTrader.strategies.indicators import ATRState
class ATRState(OHLCIndicatorState):
def __init__(self, period: int):
super().__init__(period)
self.true_ranges = []
self.tr_sum = 0.0
self.previous_close = None
def _process_ohlc_data(self, high: float, low: float, close: float):
# Calculate True Range
if self.previous_close is not None:
tr = max(
high - low,
abs(high - self.previous_close),
abs(low - self.previous_close)
)
else:
tr = high - low
# Update True Range moving average
self.true_ranges.append(tr)
self.tr_sum += tr
if len(self.true_ranges) > self.period:
old_tr = self.true_ranges.pop(0)
self.tr_sum -= old_tr
self.previous_close = close
def get_value(self) -> float:
if not self.is_ready():
return 0.0
return self.tr_sum / len(self.true_ranges)
```
### Usage Examples
#### Basic ATR Calculation
```python
# Create 14-period ATR
atr_14 = ATRState(period=14)
# OHLC data: (high, low, close)
ohlc_data = [
(105.0, 102.0, 104.0),
(106.0, 103.0, 105.5),
(107.0, 104.0, 106.0),
(108.0, 105.0, 107.5)
]
for high, low, close in ohlc_data:
atr_14.update_ohlc(high, low, close)
if atr_14.is_ready():
print(f"ATR(14): {atr_14.get_value():.2f}")
```
#### Dynamic Stop-Loss with ATR
```python
class ATRStopLoss:
def __init__(self, atr_period: int = 14, atr_multiplier: float = 2.0):
self.atr = ATRState(atr_period)
self.atr_multiplier = atr_multiplier
def update(self, high: float, low: float, close: float):
self.atr.update_ohlc(high, low, close)
def get_stop_loss(self, entry_price: float, position_type: str) -> float:
if not self.atr.is_ready():
return entry_price * 0.95 if position_type == "LONG" else entry_price * 1.05
atr_value = self.atr.get_value()
if position_type == "LONG":
return entry_price - (atr_value * self.atr_multiplier)
else: # SHORT
return entry_price + (atr_value * self.atr_multiplier)
def get_position_size(self, account_balance: float, risk_percent: float, entry_price: float, position_type: str) -> float:
"""Calculate position size based on ATR risk."""
if not self.atr.is_ready():
return 0.0
risk_amount = account_balance * (risk_percent / 100)
stop_loss = self.get_stop_loss(entry_price, position_type)
risk_per_share = abs(entry_price - stop_loss)
if risk_per_share == 0:
return 0.0
return risk_amount / risk_per_share
# Usage
atr_stop = ATRStopLoss(atr_period=14, atr_multiplier=2.0)
for high, low, close in ohlc_stream:
atr_stop.update(high, low, close)
# Calculate stop loss for a long position
entry_price = close
stop_loss = atr_stop.get_stop_loss(entry_price, "LONG")
position_size = atr_stop.get_position_size(10000, 2.0, entry_price, "LONG")
print(f"Entry: {entry_price:.2f}, Stop: {stop_loss:.2f}, Size: {position_size:.0f}")
```
### Performance Characteristics
- **Time Complexity**: O(1) per update
- **Space Complexity**: O(period)
- **Memory Usage**: ~8 bytes per period + constant overhead
## SimpleATRState
Simplified ATR implementation using exponential smoothing instead of simple moving average.
### Features
- **O(1) Memory**: Constant memory usage regardless of period
- **Exponential Smoothing**: Uses Wilder's smoothing method
- **Faster Computation**: No need to maintain historical True Range values
- **Traditional ATR**: Follows Wilder's original ATR calculation
### Mathematical Formula
```
True Range = max(
High - Low,
|High - Previous_Close|,
|Low - Previous_Close|
)
ATR = (Previous_ATR × (period - 1) + True_Range) / period
```
### Class Definition
```python
class SimpleATRState(OHLCIndicatorState):
def __init__(self, period: int):
super().__init__(period)
self.atr_value = 0.0
self.previous_close = None
self.is_first_value = True
def _process_ohlc_data(self, high: float, low: float, close: float):
# Calculate True Range
if self.previous_close is not None:
tr = max(
high - low,
abs(high - self.previous_close),
abs(low - self.previous_close)
)
else:
tr = high - low
# Update ATR using Wilder's smoothing
if self.is_first_value:
self.atr_value = tr
self.is_first_value = False
else:
self.atr_value = ((self.atr_value * (self.period - 1)) + tr) / self.period
self.previous_close = close
def get_value(self) -> float:
return self.atr_value
```
### Usage Examples
#### Memory-Efficient ATR
```python
# Create memory-efficient ATR
simple_atr = SimpleATRState(period=14)
# Process large amounts of data with constant memory
for i, (high, low, close) in enumerate(large_ohlc_dataset):
simple_atr.update_ohlc(high, low, close)
if i % 1000 == 0: # Print every 1000 updates
print(f"ATR after {i} updates: {simple_atr.get_value():.4f}")
```
#### Volatility Breakout Strategy
```python
class VolatilityBreakout:
def __init__(self, atr_period: int = 14, breakout_multiplier: float = 1.5):
self.atr = SimpleATRState(atr_period)
self.breakout_multiplier = breakout_multiplier
self.previous_close = None
def update(self, high: float, low: float, close: float):
self.atr.update_ohlc(high, low, close)
self.previous_close = close
def get_breakout_levels(self, current_close: float) -> tuple:
"""Get upper and lower breakout levels."""
if not self.atr.is_ready() or self.previous_close is None:
return current_close * 1.01, current_close * 0.99
atr_value = self.atr.get_value()
breakout_distance = atr_value * self.breakout_multiplier
upper_breakout = self.previous_close + breakout_distance
lower_breakout = self.previous_close - breakout_distance
return upper_breakout, lower_breakout
def check_breakout(self, current_high: float, current_low: float, current_close: float) -> str:
"""Check if current price breaks out of volatility range."""
upper_level, lower_level = self.get_breakout_levels(current_close)
if current_high > upper_level:
return "BULLISH_BREAKOUT"
elif current_low < lower_level:
return "BEARISH_BREAKOUT"
return "NO_BREAKOUT"
# Usage
breakout_detector = VolatilityBreakout(atr_period=14, breakout_multiplier=1.5)
for high, low, close in ohlc_data:
breakout_detector.update(high, low, close)
breakout_signal = breakout_detector.check_breakout(high, low, close)
if breakout_signal != "NO_BREAKOUT":
print(f"Breakout detected: {breakout_signal} at {close:.2f}")
```
### Performance Characteristics
- **Time Complexity**: O(1) per update
- **Space Complexity**: O(1)
- **Memory Usage**: ~32 bytes (constant)
## Comparison: ATRState vs SimpleATRState
| Aspect | ATRState | SimpleATRState |
|--------|----------|----------------|
| **Memory Usage** | O(period) | O(1) |
| **Calculation Method** | Simple Moving Average | Exponential Smoothing |
| **Accuracy** | Higher (true SMA) | Good (Wilder's method) |
| **Responsiveness** | Moderate | Slightly more responsive |
| **Historical Compatibility** | Modern | Traditional (Wilder's) |
### When to Use ATRState
- **Precise Calculations**: When you need exact simple moving average of True Range
- **Backtesting**: For historical analysis where memory isn't constrained
- **Research**: When studying exact ATR behavior
- **Small Periods**: When period is small (< 20) and memory isn't an issue
### When to Use SimpleATRState
- **Memory Efficiency**: When processing large amounts of data
- **Real-time Systems**: For high-frequency trading applications
- **Traditional Analysis**: When following Wilder's original methodology
- **Large Periods**: When using large ATR periods (> 50)
## Advanced Usage Patterns
### Multi-Timeframe ATR Analysis
```python
class MultiTimeframeATR:
def __init__(self):
self.atr_short = SimpleATRState(period=7) # Short-term volatility
self.atr_medium = SimpleATRState(period=14) # Medium-term volatility
self.atr_long = SimpleATRState(period=28) # Long-term volatility
def update(self, high: float, low: float, close: float):
self.atr_short.update_ohlc(high, low, close)
self.atr_medium.update_ohlc(high, low, close)
self.atr_long.update_ohlc(high, low, close)
def get_volatility_regime(self) -> str:
"""Determine current volatility regime."""
if not all([self.atr_short.is_ready(), self.atr_medium.is_ready(), self.atr_long.is_ready()]):
return "UNKNOWN"
short_atr = self.atr_short.get_value()
medium_atr = self.atr_medium.get_value()
long_atr = self.atr_long.get_value()
# Compare short-term to long-term volatility
volatility_ratio = short_atr / long_atr if long_atr > 0 else 1.0
if volatility_ratio > 1.5:
return "HIGH_VOLATILITY"
elif volatility_ratio < 0.7:
return "LOW_VOLATILITY"
else:
return "NORMAL_VOLATILITY"
def get_adaptive_stop_multiplier(self) -> float:
"""Get adaptive stop-loss multiplier based on volatility regime."""
regime = self.get_volatility_regime()
if regime == "HIGH_VOLATILITY":
return 2.5 # Wider stops in high volatility
elif regime == "LOW_VOLATILITY":
return 1.5 # Tighter stops in low volatility
else:
return 2.0 # Standard stops in normal volatility
# Usage
multi_atr = MultiTimeframeATR()
for high, low, close in ohlc_data:
multi_atr.update(high, low, close)
regime = multi_atr.get_volatility_regime()
stop_multiplier = multi_atr.get_adaptive_stop_multiplier()
print(f"Volatility Regime: {regime}, Stop Multiplier: {stop_multiplier:.1f}")
```
### ATR-Based Position Sizing
```python
class ATRPositionSizer:
def __init__(self, atr_period: int = 14):
self.atr = SimpleATRState(atr_period)
self.price_history = []
def update(self, high: float, low: float, close: float):
self.atr.update_ohlc(high, low, close)
self.price_history.append(close)
# Keep only recent price history
if len(self.price_history) > 100:
self.price_history.pop(0)
def calculate_position_size(self, account_balance: float, risk_percent: float,
entry_price: float, stop_loss_atr_multiplier: float = 2.0) -> dict:
"""Calculate position size based on ATR risk management."""
if not self.atr.is_ready():
return {"position_size": 0, "risk_amount": 0, "stop_loss": entry_price * 0.95}
atr_value = self.atr.get_value()
risk_amount = account_balance * (risk_percent / 100)
# Calculate stop loss based on ATR
stop_loss = entry_price - (atr_value * stop_loss_atr_multiplier)
risk_per_share = entry_price - stop_loss
# Calculate position size
if risk_per_share > 0:
position_size = risk_amount / risk_per_share
else:
position_size = 0
return {
"position_size": position_size,
"risk_amount": risk_amount,
"stop_loss": stop_loss,
"atr_value": atr_value,
"risk_per_share": risk_per_share
}
def get_volatility_percentile(self) -> float:
"""Get current ATR percentile compared to recent history."""
if not self.atr.is_ready() or len(self.price_history) < 20:
return 50.0 # Default to median
current_atr = self.atr.get_value()
# Calculate ATR for recent periods
recent_atrs = []
for i in range(len(self.price_history) - 14):
if i + 14 < len(self.price_history):
# Simplified ATR calculation for comparison
price_range = max(self.price_history[i:i+14]) - min(self.price_history[i:i+14])
recent_atrs.append(price_range)
if not recent_atrs:
return 50.0
# Calculate percentile
sorted_atrs = sorted(recent_atrs)
position = sum(1 for atr in sorted_atrs if atr <= current_atr)
percentile = (position / len(sorted_atrs)) * 100
return percentile
# Usage
position_sizer = ATRPositionSizer(atr_period=14)
for high, low, close in ohlc_data:
position_sizer.update(high, low, close)
# Calculate position for a potential trade
trade_info = position_sizer.calculate_position_size(
account_balance=10000,
risk_percent=2.0,
entry_price=close,
stop_loss_atr_multiplier=2.0
)
volatility_percentile = position_sizer.get_volatility_percentile()
print(f"Price: {close:.2f}, Position Size: {trade_info['position_size']:.0f}, "
f"ATR Percentile: {volatility_percentile:.1f}%")
```
## Integration with Strategies
### ATR-Enhanced Strategy Example
```python
class ATRTrendStrategy(IncStrategyBase):
def __init__(self, name: str, params: dict = None):
super().__init__(name, params)
# Initialize indicators
self.atr = SimpleATRState(self.params.get('atr_period', 14))
self.sma = MovingAverageState(self.params.get('sma_period', 20))
# ATR parameters
self.atr_stop_multiplier = self.params.get('atr_stop_multiplier', 2.0)
self.atr_entry_multiplier = self.params.get('atr_entry_multiplier', 0.5)
def _process_aggregated_data(self, timestamp: int, ohlcv: tuple) -> IncStrategySignal:
open_price, high, low, close, volume = ohlcv
# Update indicators
self.atr.update_ohlc(high, low, close)
self.sma.update(close)
# Wait for indicators to be ready
if not all([self.atr.is_ready(), self.sma.is_ready()]):
return IncStrategySignal.HOLD()
atr_value = self.atr.get_value()
sma_value = self.sma.get_value()
# Calculate dynamic entry threshold based on ATR
entry_threshold = atr_value * self.atr_entry_multiplier
# Generate signals based on trend and volatility
if close > sma_value + entry_threshold:
# Strong uptrend with sufficient volatility
confidence = min(0.9, (close - sma_value) / atr_value * 0.1)
# Calculate stop loss
stop_loss = close - (atr_value * self.atr_stop_multiplier)
return IncStrategySignal.BUY(
confidence=confidence,
metadata={
'atr_value': atr_value,
'sma_value': sma_value,
'stop_loss': stop_loss,
'entry_threshold': entry_threshold
}
)
elif close < sma_value - entry_threshold:
# Strong downtrend with sufficient volatility
confidence = min(0.9, (sma_value - close) / atr_value * 0.1)
# Calculate stop loss
stop_loss = close + (atr_value * self.atr_stop_multiplier)
return IncStrategySignal.SELL(
confidence=confidence,
metadata={
'atr_value': atr_value,
'sma_value': sma_value,
'stop_loss': stop_loss,
'entry_threshold': entry_threshold
}
)
return IncStrategySignal.HOLD()
```
## Performance Optimization Tips
### 1. Choose the Right ATR Implementation
```python
# For memory-constrained environments
atr = SimpleATRState(period=14) # O(1) memory
# For precise calculations
atr = ATRState(period=14) # O(period) memory
```
### 2. Batch Processing for Multiple ATRs
```python
def update_multiple_atrs(atrs: list, high: float, low: float, close: float):
"""Efficiently update multiple ATR indicators."""
for atr in atrs:
atr.update_ohlc(high, low, close)
return [atr.get_value() for atr in atrs if atr.is_ready()]
```
### 3. Cache ATR Values for Complex Calculations
```python
class CachedATR:
def __init__(self, period: int):
self.atr = SimpleATRState(period)
self._cached_value = 0.0
self._cache_valid = False
def update_ohlc(self, high: float, low: float, close: float):
self.atr.update_ohlc(high, low, close)
self._cache_valid = False
def get_value(self) -> float:
if not self._cache_valid:
self._cached_value = self.atr.get_value()
self._cache_valid = True
return self._cached_value
```
---
*ATR indicators are essential for risk management and volatility analysis. Use ATRState for precise calculations or SimpleATRState for memory efficiency in high-frequency applications.*

View File

@ -0,0 +1,363 @@
# Migration Guide: Cycles Framework → IncrementalTrader
## Overview
This guide helps you migrate from the legacy Cycles framework to the new IncrementalTrader module. The IncrementalTrader module provides a cleaner, more modular architecture while maintaining compatibility with existing strategies and workflows.
## Key Architectural Changes
### Module Structure
**Old Structure (Cycles)**:
```
cycles/
├── IncStrategies/
│ ├── base.py
│ ├── default_strategy.py
│ └── bbrs_strategy.py
├── backtest.py
├── trader.py
└── utils/
```
**New Structure (IncrementalTrader)**:
```
IncrementalTrader/
├── strategies/
│ ├── base.py
│ ├── metatrend.py
│ ├── random.py
│ ├── bbrs.py
│ └── indicators/
├── trader/
│ ├── trader.py
│ └── position.py
├── backtester/
│ ├── backtester.py
│ ├── config.py
│ └── utils.py
└── docs/
```
### Import Changes
**Old Imports**:
```python
from cycles.IncStrategies.base import StrategyBase, StrategySignal
from cycles.IncStrategies.default_strategy import DefaultStrategy
from cycles.IncStrategies.bbrs_strategy import BBRSStrategy
from cycles.backtest import Backtester
from cycles.trader import Trader
```
**New Imports**:
```python
from IncrementalTrader.strategies.base import IncStrategyBase, IncStrategySignal
from IncrementalTrader.strategies.metatrend import MetaTrendStrategy
from IncrementalTrader.strategies.bbrs import BBRSStrategy
from IncrementalTrader.backtester import IncBacktester
from IncrementalTrader.trader import IncTrader
```
## Strategy Migration
### Base Class Changes
**Old Base Class**:
```python
class MyStrategy(StrategyBase):
def get_entry_signal(self, backtester, df_index):
return StrategySignal("ENTRY", confidence=0.8)
```
**New Base Class**:
```python
class MyStrategy(IncStrategyBase):
def get_entry_signal(self, backtester, df_index):
return IncStrategySignal.BUY(confidence=0.8)
```
### Signal Generation Changes
**Old Signal Creation**:
```python
# Manual signal creation
signal = StrategySignal("ENTRY", confidence=0.8)
signal = StrategySignal("EXIT", confidence=0.9)
signal = StrategySignal("HOLD", confidence=0.0)
```
**New Signal Creation (Factory Methods)**:
```python
# Factory methods for cleaner signal creation
signal = IncStrategySignal.BUY(confidence=0.8)
signal = IncStrategySignal.SELL(confidence=0.9)
signal = IncStrategySignal.HOLD(confidence=0.0)
```
### Strategy Name Mapping
| Old Strategy | New Strategy | Compatibility Alias |
|-------------|-------------|-------------------|
| `DefaultStrategy` | `MetaTrendStrategy` | `IncMetaTrendStrategy` |
| `BBRSStrategy` | `BBRSStrategy` | `IncBBRSStrategy` |
| N/A | `RandomStrategy` | `IncRandomStrategy` |
## Backtesting Migration
### Configuration Changes
**Old Configuration**:
```python
# Direct backtester usage
backtester = Backtester(data, strategy)
results = backtester.run()
```
**New Configuration**:
```python
# Enhanced configuration system
from IncrementalTrader.backtester import IncBacktester, BacktestConfig
config = BacktestConfig(
initial_capital=10000,
commission=0.001,
slippage=0.0001
)
backtester = IncBacktester(config)
results = backtester.run_backtest(data, strategy)
```
### Parameter Optimization
**Old Optimization**:
```python
# Manual parameter loops
for param1 in values1:
for param2 in values2:
strategy = MyStrategy(param1=param1, param2=param2)
results = backtester.run()
```
**New Optimization**:
```python
# Built-in optimization framework
from IncrementalTrader.backtester import OptimizationConfig
opt_config = OptimizationConfig(
strategy_class=MyStrategy,
param_ranges={
'param1': [1, 2, 3, 4, 5],
'param2': [0.1, 0.2, 0.3, 0.4, 0.5]
},
optimization_metric='sharpe_ratio'
)
results = backtester.optimize_strategy(data, opt_config)
```
## Trading Migration
### Trader Interface Changes
**Old Trader**:
```python
trader = Trader(strategy, initial_capital=10000)
trader.process_tick(price_data)
```
**New Trader**:
```python
trader = IncTrader(strategy, initial_capital=10000)
trader.process_tick(price_data)
```
### Position Management
**Old Position Handling**:
```python
# Position management was embedded in trader
if trader.position_size > 0:
# Handle long position
```
**New Position Handling**:
```python
# Dedicated position manager
position_manager = trader.position_manager
if position_manager.has_position():
current_position = position_manager.get_current_position()
# Handle position with dedicated methods
```
## Indicator Migration
### Import Changes
**Old Indicator Imports**:
```python
from cycles.IncStrategies.indicators import SupertrendState, ATRState
```
**New Indicator Imports**:
```python
from IncrementalTrader.strategies.indicators import SupertrendState, ATRState
```
### Indicator Usage
The indicator interface remains largely the same, but with enhanced features:
**Enhanced Indicator Features**:
```python
# New indicators have better state management
supertrend = SupertrendState(period=10, multiplier=3.0)
# Process data incrementally
for price_data in data_stream:
supertrend.update(price_data)
current_trend = supertrend.get_value()
trend_direction = supertrend.get_trend()
```
## Compatibility Layer
### Backward Compatibility Aliases
The new module provides compatibility aliases for smooth migration:
```python
# These imports work for backward compatibility
from IncrementalTrader.strategies.metatrend import IncMetaTrendStrategy as DefaultStrategy
from IncrementalTrader.strategies.bbrs import IncBBRSStrategy as BBRSStrategy
from IncrementalTrader.strategies.random import IncRandomStrategy as RandomStrategy
```
### Gradual Migration Strategy
1. **Phase 1**: Update imports to use compatibility aliases
2. **Phase 2**: Update signal generation to use factory methods
3. **Phase 3**: Migrate to new configuration system
4. **Phase 4**: Update to new class names and remove aliases
## Enhanced Features
### New Capabilities in IncrementalTrader
1. **Modular Architecture**: Each component can be used independently
2. **Enhanced Configuration**: Robust configuration with validation
3. **Better Error Handling**: Comprehensive exception handling and logging
4. **Improved Performance**: Optimized data processing and memory usage
5. **Self-Contained**: No external dependencies on legacy modules
6. **Enhanced Documentation**: Comprehensive API documentation and examples
### Performance Improvements
- **Memory Efficiency**: Reduced memory footprint for large datasets
- **Processing Speed**: Optimized indicator calculations
- **Parallel Processing**: Built-in support for parallel backtesting
- **Resource Management**: Intelligent system resource allocation
## Migration Checklist
### Pre-Migration
- [ ] Review current strategy implementations
- [ ] Identify external dependencies
- [ ] Backup existing configurations
- [ ] Test current system performance
### During Migration
- [ ] Update import statements
- [ ] Replace signal generation with factory methods
- [ ] Update configuration format
- [ ] Test strategy behavior equivalence
- [ ] Validate backtesting results
### Post-Migration
- [ ] Remove old import statements
- [ ] Update documentation
- [ ] Performance testing
- [ ] Clean up legacy code references
## Common Migration Issues
### Issue 1: Signal Type Mismatch
**Problem**: Old string-based signals don't work with new system
**Solution**: Use factory methods (`IncStrategySignal.BUY()` instead of `"ENTRY"`)
### Issue 2: Import Errors
**Problem**: Old import paths no longer exist
**Solution**: Update to new module structure or use compatibility aliases
### Issue 3: Configuration Format
**Problem**: Old configuration format not compatible
**Solution**: Migrate to new `BacktestConfig` and `OptimizationConfig` classes
### Issue 4: Indicator State
**Problem**: Indicator state not preserved during migration
**Solution**: Use new indicator initialization patterns with proper state management
## Support and Resources
### Documentation
- [Strategy Development Guide](./strategies.md)
- [Indicator Reference](./indicators.md)
- [Backtesting Guide](./backtesting.md)
- [API Reference](./api.md)
### Examples
- [Basic Usage Examples](../examples/basic_usage.py)
- Strategy migration examples in documentation
### Getting Help
- Review the comprehensive API documentation
- Check the examples directory for usage patterns
- Refer to the original Cycles documentation for context
## Legacy Framework Reference
### Timeframe System (Legacy)
The legacy Cycles framework had sophisticated timeframe management that is preserved in the new system:
**Key Concepts from Legacy System**:
- Strategy-controlled timeframes
- Automatic resampling
- Precision execution with 1-minute data
- Signal mapping between timeframes
**Migration Notes**:
- The new `TimeframeAggregator` provides similar functionality
- Strategies can still specify required timeframes
- Multi-timeframe strategies are fully supported
- 1-minute precision for stop-loss execution is maintained
### Strategy Manager (Legacy)
The legacy StrategyManager for multi-strategy combination:
**Legacy Features**:
- Multi-strategy orchestration
- Signal combination methods (weighted consensus, majority voting)
- Multi-timeframe strategy coordination
**Migration Path**:
- Individual strategies are now self-contained
- Multi-strategy combination can be implemented at the application level
- Consider using multiple backtests and combining results
### Performance Characteristics (Legacy)
**Legacy Strategy Performance Notes**:
- Default Strategy: High accuracy in trending markets, vulnerable to sideways markets
- BBRS Strategy: Market regime adaptation, volume confirmation, multi-timeframe analysis
**New Performance Improvements**:
- Enhanced signal generation reduces false positives
- Better risk management with dedicated position manager
- Improved backtesting accuracy with enhanced data handling
---
*This migration guide provides a comprehensive path from the legacy Cycles framework to the new IncrementalTrader module while preserving functionality and improving architecture.*

View File

@ -0,0 +1,615 @@
# 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
```python
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
```python
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
```python
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
```python
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
```python
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
```python
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
```python
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:
```python
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
```python
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
```python
# 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
```python
# 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
```python
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
```python
# 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
```python
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
```python
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
```python
# 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
```python
# 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.*

View File

@ -0,0 +1,444 @@
# MetaTrend Strategy Documentation
## Overview
The MetaTrend Strategy is a sophisticated trend-following algorithm that uses multiple Supertrend indicators to detect and confirm market trends. By combining signals from multiple Supertrend configurations, it creates a "meta-trend" that provides more reliable trend detection with reduced false signals.
## Strategy Concept
### Core Philosophy
- **Trend Confirmation**: Multiple Supertrend indicators must agree before generating signals
- **False Signal Reduction**: Requires consensus among indicators to filter noise
- **Adaptive Sensitivity**: Different Supertrend configurations capture various trend timeframes
- **Risk Management**: Built-in trend reversal detection for exit signals
### Key Features
- **Multi-Supertrend Analysis**: Uses 3+ Supertrend indicators with different parameters
- **Consensus-Based Signals**: Requires minimum agreement threshold for signal generation
- **Incremental Processing**: O(1) memory and processing time per data point
- **Configurable Parameters**: Flexible configuration for different market conditions
## Algorithm Details
### Mathematical Foundation
The strategy uses multiple Supertrend indicators, each calculated as:
```
Basic Upper Band = (High + Low) / 2 + Multiplier × ATR(Period)
Basic Lower Band = (High + Low) / 2 - Multiplier × ATR(Period)
Final Upper Band = Basic Upper Band < Previous Upper Band OR Previous Close > Previous Upper Band
? Basic Upper Band : Previous Upper Band
Final Lower Band = Basic Lower Band > Previous Lower Band OR Previous Close < Previous Lower Band
? Basic Lower Band : Previous Lower Band
Supertrend = Close <= Final Lower Band ? Final Lower Band : Final Upper Band
Trend Direction = Close <= Final Lower Band ? -1 : 1
```
### Meta-Trend Calculation
```python
# For each Supertrend indicator
for st in supertrend_collection:
if st.is_uptrend():
uptrend_count += 1
elif st.is_downtrend():
downtrend_count += 1
# Calculate agreement ratios
total_indicators = len(supertrend_collection)
uptrend_ratio = uptrend_count / total_indicators
downtrend_ratio = downtrend_count / total_indicators
# Generate meta-signal
if uptrend_ratio >= min_trend_agreement:
meta_signal = "BUY"
elif downtrend_ratio >= min_trend_agreement:
meta_signal = "SELL"
else:
meta_signal = "HOLD"
```
## Process Flow Diagram
```
Data Input (OHLCV)
TimeframeAggregator
[15min aggregated data]
┌─────────────────────────────────────┐
│ MetaTrend Strategy │
│ │
│ ┌─────────────────────────────────┐│
│ │ SupertrendCollection ││
│ │ ││
│ │ ST1(10,2.0) → Signal1 ││
│ │ ST2(20,3.0) → Signal2 ││
│ │ ST3(30,4.0) → Signal3 ││
│ │ ││
│ │ Agreement Analysis: ││
│ │ - Count BUY signals ││
│ │ - Count SELL signals ││
│ │ - Calculate ratios ││
│ └─────────────────────────────────┘│
│ ↓ │
│ ┌─────────────────────────────────┐│
│ │ Meta-Signal Logic ││
│ │ ││
│ │ if uptrend_ratio >= threshold: ││
│ │ return BUY ││
│ │ elif downtrend_ratio >= thresh:││
│ │ return SELL ││
│ │ else: ││
│ │ return HOLD ││
│ └─────────────────────────────────┘│
└─────────────────────────────────────┘
IncStrategySignal
Trader Execution
```
## Implementation Architecture
### Class Hierarchy
```
IncStrategyBase
MetaTrendStrategy
├── TimeframeAggregator (inherited)
├── SupertrendCollection
│ ├── SupertrendState(10, 2.0)
│ ├── SupertrendState(20, 3.0)
│ └── SupertrendState(30, 4.0)
└── Signal Generation Logic
```
### Key Components
#### 1. SupertrendCollection
```python
class SupertrendCollection:
def __init__(self, periods: list, multipliers: list):
# Creates multiple Supertrend indicators
self.supertrends = [
SupertrendState(period, multiplier)
for period, multiplier in zip(periods, multipliers)
]
def update_ohlc(self, high, low, close):
# Updates all Supertrend indicators
for st in self.supertrends:
st.update_ohlc(high, low, close)
def get_meta_signal(self, min_agreement=0.6):
# Calculates consensus signal
signals = [st.get_signal() for st in self.supertrends]
return self._calculate_consensus(signals, min_agreement)
```
#### 2. Signal Generation Process
```python
def _process_aggregated_data(self, timestamp: int, ohlcv: tuple) -> IncStrategySignal:
open_price, high, low, close, volume = ohlcv
# Update all Supertrend indicators
self.supertrend_collection.update_ohlc(high, low, close)
# Check if indicators are ready
if not self.supertrend_collection.is_ready():
return IncStrategySignal.HOLD()
# Get meta-signal
meta_signal = self.supertrend_collection.get_meta_signal(
min_agreement=self.params['min_trend_agreement']
)
# Generate strategy signal
if meta_signal == 'BUY' and self.current_signal.signal_type != 'BUY':
return IncStrategySignal.BUY(
confidence=self.supertrend_collection.get_agreement_ratio(),
metadata={
'meta_signal': meta_signal,
'individual_signals': self.supertrend_collection.get_signals(),
'agreement_ratio': self.supertrend_collection.get_agreement_ratio()
}
)
elif meta_signal == 'SELL' and self.current_signal.signal_type != 'SELL':
return IncStrategySignal.SELL(
confidence=self.supertrend_collection.get_agreement_ratio(),
metadata={
'meta_signal': meta_signal,
'individual_signals': self.supertrend_collection.get_signals(),
'agreement_ratio': self.supertrend_collection.get_agreement_ratio()
}
)
return IncStrategySignal.HOLD()
```
## Configuration Parameters
### Default Parameters
```python
default_params = {
"timeframe": "15min", # Data aggregation timeframe
"supertrend_periods": [10, 20, 30], # ATR periods for each Supertrend
"supertrend_multipliers": [2.0, 3.0, 4.0], # Multipliers for each Supertrend
"min_trend_agreement": 0.6 # Minimum agreement ratio (60%)
}
```
### Parameter Descriptions
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `timeframe` | str | "15min" | Data aggregation timeframe |
| `supertrend_periods` | List[int] | [10, 20, 30] | ATR periods for Supertrend calculations |
| `supertrend_multipliers` | List[float] | [2.0, 3.0, 4.0] | ATR multipliers for band calculation |
| `min_trend_agreement` | float | 0.6 | Minimum ratio of indicators that must agree |
### Parameter Optimization Ranges
```python
optimization_ranges = {
"supertrend_periods": [
[10, 20, 30], # Conservative
[15, 25, 35], # Moderate
[20, 30, 40], # Aggressive
[5, 15, 25], # Fast
[25, 35, 45] # Slow
],
"supertrend_multipliers": [
[1.5, 2.5, 3.5], # Tight bands
[2.0, 3.0, 4.0], # Standard
[2.5, 3.5, 4.5], # Wide bands
[3.0, 4.0, 5.0] # Very wide bands
],
"min_trend_agreement": [0.4, 0.5, 0.6, 0.7, 0.8, 0.9],
"timeframe": ["5min", "15min", "30min", "1h"]
}
```
## Signal Generation Logic
### Entry Conditions
**BUY Signal Generated When:**
1. Meta-trend changes from non-bullish to bullish
2. Agreement ratio ≥ `min_trend_agreement`
3. Previous signal was not already BUY
4. All Supertrend indicators are ready
**SELL Signal Generated When:**
1. Meta-trend changes from non-bearish to bearish
2. Agreement ratio ≥ `min_trend_agreement`
3. Previous signal was not already SELL
4. All Supertrend indicators are ready
### Signal Confidence
The confidence level is calculated as the agreement ratio:
```python
confidence = agreeing_indicators / total_indicators
```
- **High Confidence (0.8-1.0)**: Strong consensus among indicators
- **Medium Confidence (0.6-0.8)**: Moderate consensus
- **Low Confidence (0.4-0.6)**: Weak consensus (may not generate signal)
### Signal Metadata
Each signal includes comprehensive metadata:
```python
metadata = {
'meta_signal': 'BUY', # Overall meta-signal
'individual_signals': ['BUY', 'BUY', 'HOLD'], # Individual Supertrend signals
'agreement_ratio': 0.67, # Ratio of agreeing indicators
'supertrend_values': [45123.45, 45234.56, 45345.67], # Current Supertrend values
'trend_directions': [1, 1, 0], # Trend directions (1=up, -1=down, 0=neutral)
'timestamp': 1640995200000 # Signal generation timestamp
}
```
## Performance Characteristics
### Strengths
1. **Trend Accuracy**: High accuracy in strong trending markets
2. **False Signal Reduction**: Multiple confirmations reduce whipsaws
3. **Adaptive Sensitivity**: Different parameters capture various trend speeds
4. **Risk Management**: Clear trend reversal detection
5. **Scalability**: Works across different timeframes and markets
### Weaknesses
1. **Sideways Markets**: May generate false signals in ranging conditions
2. **Lag**: Multiple confirmations can delay entry/exit points
3. **Whipsaws**: Vulnerable to rapid trend reversals
4. **Parameter Sensitivity**: Performance depends on parameter tuning
### Optimal Market Conditions
- **Trending Markets**: Best performance in clear directional moves
- **Medium Volatility**: Works well with moderate price swings
- **Sufficient Volume**: Better signals with adequate trading volume
- **Clear Trends**: Performs best when trends last longer than indicator periods
## Usage Examples
### Basic Usage
```python
from IncrementalTrader import MetaTrendStrategy, IncTrader
# Create strategy with default parameters
strategy = MetaTrendStrategy("metatrend")
# 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})")
```
### Custom Configuration
```python
# Custom parameters for aggressive trading
strategy = MetaTrendStrategy("metatrend_aggressive", {
"timeframe": "5min",
"supertrend_periods": [5, 10, 15],
"supertrend_multipliers": [1.5, 2.0, 2.5],
"min_trend_agreement": 0.5
})
```
### Conservative Configuration
```python
# Conservative parameters for stable trends
strategy = MetaTrendStrategy("metatrend_conservative", {
"timeframe": "1h",
"supertrend_periods": [20, 30, 40],
"supertrend_multipliers": [3.0, 4.0, 5.0],
"min_trend_agreement": 0.8
})
```
## Backtesting Results
### Performance Metrics (Example)
```
Timeframe: 15min
Period: 2024-01-01 to 2024-12-31
Initial Capital: $10,000
Total Return: 23.45%
Sharpe Ratio: 1.34
Max Drawdown: -8.23%
Win Rate: 58.3%
Profit Factor: 1.67
Total Trades: 127
```
### Parameter Sensitivity Analysis
```
min_trend_agreement vs Performance:
0.4: Return 18.2%, Sharpe 1.12, Trades 203
0.5: Return 20.1%, Sharpe 1.23, Trades 167
0.6: Return 23.4%, Sharpe 1.34, Trades 127 ← Optimal
0.7: Return 21.8%, Sharpe 1.41, Trades 89
0.8: Return 19.3%, Sharpe 1.38, Trades 54
```
## Implementation Notes
### Memory Efficiency
- **Constant Memory**: O(1) memory usage regardless of data history
- **Efficient Updates**: Each data point processed in O(1) time
- **State Management**: Minimal state storage for optimal performance
### Real-time Capability
- **Incremental Processing**: Designed for live trading applications
- **Low Latency**: Minimal processing delay per data point
- **Stateful Design**: Maintains indicator state between updates
### Error Handling
```python
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()
# Process data
# ... strategy logic ...
except Exception as e:
self.logger.error(f"Error in MetaTrend strategy: {e}")
return IncStrategySignal.HOLD()
```
## Advanced Features
### Dynamic Parameter Adjustment
```python
# Adjust parameters based on market volatility
def adjust_parameters_for_volatility(self, volatility):
if volatility > 0.03: # High volatility
self.params['min_trend_agreement'] = 0.7 # Require more agreement
elif volatility < 0.01: # Low volatility
self.params['min_trend_agreement'] = 0.5 # Allow less agreement
```
### Multi-timeframe Analysis
```python
# Combine multiple timeframes for better signals
strategy_5m = MetaTrendStrategy("mt_5m", {"timeframe": "5min"})
strategy_15m = MetaTrendStrategy("mt_15m", {"timeframe": "15min"})
strategy_1h = MetaTrendStrategy("mt_1h", {"timeframe": "1h"})
# Use higher timeframe for trend direction, lower for entry timing
```
## Troubleshooting
### Common Issues
1. **No Signals Generated**
- Check if `min_trend_agreement` is too high
- Verify sufficient data for indicator warmup
- Ensure data quality and consistency
2. **Too Many False Signals**
- Increase `min_trend_agreement` threshold
- Use wider Supertrend multipliers
- Consider longer timeframes
3. **Delayed Signals**
- Reduce `min_trend_agreement` threshold
- Use shorter Supertrend periods
- Consider faster timeframes
### Debug Information
```python
# Enable debug logging
strategy.logger.setLevel(logging.DEBUG)
# Access internal state
print(f"Current signals: {strategy.supertrend_collection.get_signals()}")
print(f"Agreement ratio: {strategy.supertrend_collection.get_agreement_ratio()}")
print(f"Meta signal: {strategy.supertrend_collection.get_meta_signal()}")
```
---
*The MetaTrend Strategy provides robust trend-following capabilities through multi-indicator consensus, making it suitable for various market conditions while maintaining computational efficiency for real-time applications.*

View File

@ -0,0 +1,573 @@
# 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.*

View File

@ -0,0 +1,580 @@
# Strategy Development Guide
This guide explains how to create custom trading strategies using the IncrementalTrader framework.
## Overview
IncrementalTrader strategies are built around the `IncStrategyBase` class, which provides a robust framework for incremental computation, timeframe aggregation, and signal generation.
## Basic Strategy Structure
```python
from IncrementalTrader.strategies.base import IncStrategyBase, IncStrategySignal
from IncrementalTrader.strategies.indicators import MovingAverageState
class MyCustomStrategy(IncStrategyBase):
def __init__(self, name: str, params: dict = None):
super().__init__(name, params)
# Initialize indicators
self.sma_fast = MovingAverageState(period=self.params.get('fast_period', 10))
self.sma_slow = MovingAverageState(period=self.params.get('slow_period', 20))
# Strategy state
self.current_signal = IncStrategySignal.HOLD()
def _process_aggregated_data(self, timestamp: int, ohlcv: tuple) -> IncStrategySignal:
"""Process aggregated data and generate signals."""
open_price, high, low, close, volume = ohlcv
# Update indicators
self.sma_fast.update(close)
self.sma_slow.update(close)
# Generate signals
if self.sma_fast.is_ready() and self.sma_slow.is_ready():
fast_sma = self.sma_fast.get_value()
slow_sma = self.sma_slow.get_value()
if fast_sma > slow_sma and self.current_signal.signal_type != 'BUY':
self.current_signal = IncStrategySignal.BUY(
confidence=0.8,
metadata={'fast_sma': fast_sma, 'slow_sma': slow_sma}
)
elif fast_sma < slow_sma and self.current_signal.signal_type != 'SELL':
self.current_signal = IncStrategySignal.SELL(
confidence=0.8,
metadata={'fast_sma': fast_sma, 'slow_sma': slow_sma}
)
return self.current_signal
```
## Key Components
### 1. Base Class Inheritance
All strategies must inherit from `IncStrategyBase`:
```python
class MyStrategy(IncStrategyBase):
def __init__(self, name: str, params: dict = None):
super().__init__(name, params)
# Your initialization code here
```
### 2. Required Methods
#### `_process_aggregated_data()`
This is the core method where your strategy logic goes:
```python
def _process_aggregated_data(self, timestamp: int, ohlcv: tuple) -> IncStrategySignal:
"""
Process aggregated OHLCV data and return a signal.
Args:
timestamp: Unix timestamp
ohlcv: Tuple of (open, high, low, close, volume)
Returns:
IncStrategySignal: BUY, SELL, or HOLD signal
"""
# Your strategy logic here
return signal
```
### 3. Signal Generation
Use the factory methods to create signals:
```python
# Buy signal
signal = IncStrategySignal.BUY(
confidence=0.8, # Optional: 0.0 to 1.0
metadata={'reason': 'Golden cross detected'} # Optional: additional data
)
# Sell signal
signal = IncStrategySignal.SELL(
confidence=0.9,
metadata={'reason': 'Death cross detected'}
)
# Hold signal
signal = IncStrategySignal.HOLD()
```
## Using Indicators
### Built-in Indicators
IncrementalTrader provides many built-in indicators:
```python
from IncrementalTrader.strategies.indicators import (
MovingAverageState,
ExponentialMovingAverageState,
ATRState,
SupertrendState,
RSIState,
BollingerBandsState
)
class MyStrategy(IncStrategyBase):
def __init__(self, name: str, params: dict = None):
super().__init__(name, params)
# Moving averages
self.sma = MovingAverageState(period=20)
self.ema = ExponentialMovingAverageState(period=20, alpha=0.1)
# Volatility
self.atr = ATRState(period=14)
# Trend
self.supertrend = SupertrendState(period=10, multiplier=3.0)
# Oscillators
self.rsi = RSIState(period=14)
self.bb = BollingerBandsState(period=20, std_dev=2.0)
```
### Indicator Usage Pattern
```python
def _process_aggregated_data(self, timestamp: int, ohlcv: tuple) -> IncStrategySignal:
open_price, high, low, close, volume = ohlcv
# Update indicators
self.sma.update(close)
self.rsi.update(close)
self.atr.update_ohlc(high, low, close)
# Check if indicators are ready
if not (self.sma.is_ready() and self.rsi.is_ready()):
return IncStrategySignal.HOLD()
# Get indicator values
sma_value = self.sma.get_value()
rsi_value = self.rsi.get_value()
atr_value = self.atr.get_value()
# Your strategy logic here
# ...
```
## Advanced Features
### 1. Timeframe Aggregation
The base class automatically handles timeframe aggregation:
```python
class MyStrategy(IncStrategyBase):
def __init__(self, name: str, params: dict = None):
# Set timeframe in params
default_params = {"timeframe": "15min"}
if params:
default_params.update(params)
super().__init__(name, default_params)
```
Supported timeframes:
- `"1min"`, `"5min"`, `"15min"`, `"30min"`
- `"1h"`, `"4h"`, `"1d"`
### 2. State Management
Track strategy state for complex logic:
```python
class TrendFollowingStrategy(IncStrategyBase):
def __init__(self, name: str, params: dict = None):
super().__init__(name, params)
# Strategy state
self.trend_state = "UNKNOWN" # BULLISH, BEARISH, SIDEWAYS
self.position_state = "NONE" # LONG, SHORT, NONE
self.last_signal_time = 0
def _process_aggregated_data(self, timestamp: int, ohlcv: tuple) -> IncStrategySignal:
# Update trend state
self._update_trend_state(ohlcv)
# Generate signals based on trend and position
if self.trend_state == "BULLISH" and self.position_state != "LONG":
self.position_state = "LONG"
return IncStrategySignal.BUY(confidence=0.8)
elif self.trend_state == "BEARISH" and self.position_state != "SHORT":
self.position_state = "SHORT"
return IncStrategySignal.SELL(confidence=0.8)
return IncStrategySignal.HOLD()
```
### 3. Multi-Indicator Strategies
Combine multiple indicators for robust signals:
```python
class MultiIndicatorStrategy(IncStrategyBase):
def __init__(self, name: str, params: dict = None):
super().__init__(name, params)
# Trend indicators
self.supertrend = SupertrendState(period=10, multiplier=3.0)
self.sma_50 = MovingAverageState(period=50)
self.sma_200 = MovingAverageState(period=200)
# Momentum indicators
self.rsi = RSIState(period=14)
# Volatility indicators
self.bb = BollingerBandsState(period=20, std_dev=2.0)
def _process_aggregated_data(self, timestamp: int, ohlcv: tuple) -> IncStrategySignal:
open_price, high, low, close, volume = ohlcv
# Update all indicators
self.supertrend.update_ohlc(high, low, close)
self.sma_50.update(close)
self.sma_200.update(close)
self.rsi.update(close)
self.bb.update(close)
# Wait for all indicators to be ready
if not all([
self.supertrend.is_ready(),
self.sma_50.is_ready(),
self.sma_200.is_ready(),
self.rsi.is_ready(),
self.bb.is_ready()
]):
return IncStrategySignal.HOLD()
# Get indicator values
supertrend_signal = self.supertrend.get_signal()
sma_50 = self.sma_50.get_value()
sma_200 = self.sma_200.get_value()
rsi = self.rsi.get_value()
bb_upper, bb_middle, bb_lower = self.bb.get_bands()
# Multi-condition buy signal
buy_conditions = [
supertrend_signal == 'BUY',
sma_50 > sma_200, # Long-term uptrend
rsi < 70, # Not overbought
close < bb_upper # Not at upper band
]
# Multi-condition sell signal
sell_conditions = [
supertrend_signal == 'SELL',
sma_50 < sma_200, # Long-term downtrend
rsi > 30, # Not oversold
close > bb_lower # Not at lower band
]
if all(buy_conditions):
confidence = sum([1 for c in buy_conditions if c]) / len(buy_conditions)
return IncStrategySignal.BUY(
confidence=confidence,
metadata={
'supertrend': supertrend_signal,
'sma_trend': 'UP' if sma_50 > sma_200 else 'DOWN',
'rsi': rsi,
'bb_position': 'MIDDLE'
}
)
elif all(sell_conditions):
confidence = sum([1 for c in sell_conditions if c]) / len(sell_conditions)
return IncStrategySignal.SELL(
confidence=confidence,
metadata={
'supertrend': supertrend_signal,
'sma_trend': 'DOWN' if sma_50 < sma_200 else 'UP',
'rsi': rsi,
'bb_position': 'MIDDLE'
}
)
return IncStrategySignal.HOLD()
```
## Parameter Management
### Default Parameters
Define default parameters in your strategy:
```python
class MyStrategy(IncStrategyBase):
def __init__(self, name: str, params: dict = None):
# Define defaults
default_params = {
"timeframe": "15min",
"fast_period": 10,
"slow_period": 20,
"rsi_period": 14,
"rsi_overbought": 70,
"rsi_oversold": 30
}
# Merge with provided params
if params:
default_params.update(params)
super().__init__(name, default_params)
# Use parameters
self.fast_sma = MovingAverageState(period=self.params['fast_period'])
self.slow_sma = MovingAverageState(period=self.params['slow_period'])
self.rsi = RSIState(period=self.params['rsi_period'])
```
### Parameter Validation
Add validation for critical parameters:
```python
def __init__(self, name: str, params: dict = None):
super().__init__(name, params)
# Validate parameters
if self.params['fast_period'] >= self.params['slow_period']:
raise ValueError("fast_period must be less than slow_period")
if not (1 <= self.params['rsi_period'] <= 100):
raise ValueError("rsi_period must be between 1 and 100")
```
## Testing Your Strategy
### Unit Testing
```python
import unittest
from IncrementalTrader.strategies.base import IncStrategySignal
class TestMyStrategy(unittest.TestCase):
def setUp(self):
self.strategy = MyCustomStrategy("test", {
"fast_period": 5,
"slow_period": 10
})
def test_initialization(self):
self.assertEqual(self.strategy.name, "test")
self.assertEqual(self.strategy.params['fast_period'], 5)
def test_signal_generation(self):
# Feed test data
test_data = [
(1000, (100, 105, 95, 102, 1000)),
(1001, (102, 108, 100, 106, 1200)),
# ... more test data
]
for timestamp, ohlcv in test_data:
signal = self.strategy.process_data_point(timestamp, ohlcv)
self.assertIsInstance(signal, IncStrategySignal)
```
### Backtesting
```python
from IncrementalTrader import IncBacktester, BacktestConfig
# Test your strategy
config = BacktestConfig(
initial_usd=10000,
start_date="2024-01-01",
end_date="2024-03-31"
)
backtester = IncBacktester()
results = backtester.run_single_strategy(
strategy_class=MyCustomStrategy,
strategy_params={"fast_period": 10, "slow_period": 20},
config=config,
data_file="test_data.csv"
)
print(f"Total Return: {results['performance_metrics']['total_return_pct']:.2f}%")
```
## Best Practices
### 1. Incremental Design
Always design for incremental computation:
```python
# Good: Incremental calculation
class IncrementalSMA:
def __init__(self, period):
self.period = period
self.values = deque(maxlen=period)
self.sum = 0
def update(self, value):
if len(self.values) == self.period:
self.sum -= self.values[0]
self.values.append(value)
self.sum += value
def get_value(self):
return self.sum / len(self.values) if self.values else 0
# Bad: Batch calculation
def calculate_sma(prices, period):
return [sum(prices[i:i+period])/period for i in range(len(prices)-period+1)]
```
### 2. State Management
Keep minimal state and ensure it's always consistent:
```python
def _process_aggregated_data(self, timestamp: int, ohlcv: tuple) -> IncStrategySignal:
# Update all indicators first
self._update_indicators(ohlcv)
# Then update strategy state
self._update_strategy_state()
# Finally generate signal
return self._generate_signal()
```
### 3. Error Handling
Handle edge cases gracefully:
```python
def _process_aggregated_data(self, timestamp: int, ohlcv: tuple) -> IncStrategySignal:
try:
open_price, high, low, close, volume = ohlcv
# Validate data
if not all(isinstance(x, (int, float)) for x in ohlcv):
self.logger.warning(f"Invalid OHLCV data: {ohlcv}")
return IncStrategySignal.HOLD()
if high < low or close < 0:
self.logger.warning(f"Inconsistent price data: {ohlcv}")
return IncStrategySignal.HOLD()
# Your strategy logic here
# ...
except Exception as e:
self.logger.error(f"Error processing data: {e}")
return IncStrategySignal.HOLD()
```
### 4. Logging
Use the built-in logger for debugging:
```python
def _process_aggregated_data(self, timestamp: int, ohlcv: tuple) -> IncStrategySignal:
open_price, high, low, close, volume = ohlcv
# Log important events
if self.sma_fast.get_value() > self.sma_slow.get_value():
self.logger.debug(f"Fast SMA ({self.sma_fast.get_value():.2f}) > Slow SMA ({self.sma_slow.get_value():.2f})")
# Log signal generation
if signal.signal_type != 'HOLD':
self.logger.info(f"Generated {signal.signal_type} signal with confidence {signal.confidence}")
return signal
```
## Example Strategies
### Simple Moving Average Crossover
```python
class SMAStrategy(IncStrategyBase):
def __init__(self, name: str, params: dict = None):
default_params = {
"timeframe": "15min",
"fast_period": 10,
"slow_period": 20
}
if params:
default_params.update(params)
super().__init__(name, default_params)
self.sma_fast = MovingAverageState(period=self.params['fast_period'])
self.sma_slow = MovingAverageState(period=self.params['slow_period'])
self.last_signal = 'HOLD'
def _process_aggregated_data(self, timestamp: int, ohlcv: tuple) -> IncStrategySignal:
_, _, _, close, _ = ohlcv
self.sma_fast.update(close)
self.sma_slow.update(close)
if not (self.sma_fast.is_ready() and self.sma_slow.is_ready()):
return IncStrategySignal.HOLD()
fast = self.sma_fast.get_value()
slow = self.sma_slow.get_value()
if fast > slow and self.last_signal != 'BUY':
self.last_signal = 'BUY'
return IncStrategySignal.BUY(confidence=0.7)
elif fast < slow and self.last_signal != 'SELL':
self.last_signal = 'SELL'
return IncStrategySignal.SELL(confidence=0.7)
return IncStrategySignal.HOLD()
```
### RSI Mean Reversion
```python
class RSIMeanReversionStrategy(IncStrategyBase):
def __init__(self, name: str, params: dict = None):
default_params = {
"timeframe": "15min",
"rsi_period": 14,
"oversold": 30,
"overbought": 70
}
if params:
default_params.update(params)
super().__init__(name, default_params)
self.rsi = RSIState(period=self.params['rsi_period'])
def _process_aggregated_data(self, timestamp: int, ohlcv: tuple) -> IncStrategySignal:
_, _, _, close, _ = ohlcv
self.rsi.update(close)
if not self.rsi.is_ready():
return IncStrategySignal.HOLD()
rsi_value = self.rsi.get_value()
if rsi_value < self.params['oversold']:
return IncStrategySignal.BUY(
confidence=min(1.0, (self.params['oversold'] - rsi_value) / 20),
metadata={'rsi': rsi_value, 'condition': 'oversold'}
)
elif rsi_value > self.params['overbought']:
return IncStrategySignal.SELL(
confidence=min(1.0, (rsi_value - self.params['overbought']) / 20),
metadata={'rsi': rsi_value, 'condition': 'overbought'}
)
return IncStrategySignal.HOLD()
```
This guide provides a comprehensive foundation for developing custom strategies with IncrementalTrader. Remember to always test your strategies thoroughly before using them in live trading!

View File

@ -0,0 +1,273 @@
#!/usr/bin/env python3
"""
Basic Usage Example for IncrementalTrader
This example demonstrates the basic usage of the IncrementalTrader framework
for testing trading strategies.
"""
import pandas as pd
from IncrementalTrader import (
MetaTrendStrategy, BBRSStrategy, RandomStrategy,
IncTrader, IncBacktester, BacktestConfig
)
def basic_strategy_usage():
"""Demonstrate basic strategy usage with live data processing."""
print("=== Basic Strategy Usage ===")
# Create a strategy
strategy = MetaTrendStrategy("metatrend", params={
"timeframe": "15min",
"supertrend_periods": [10, 20, 30],
"supertrend_multipliers": [2.0, 3.0, 4.0],
"min_trend_agreement": 0.6
})
# Create trader
trader = IncTrader(
strategy=strategy,
initial_usd=10000,
stop_loss_pct=0.03,
take_profit_pct=0.06,
fee_pct=0.001
)
# Simulate some price data (in real usage, this would come from your data source)
sample_data = [
(1640995200000, (46000, 46500, 45800, 46200, 1000)), # timestamp, (O,H,L,C,V)
(1640995260000, (46200, 46800, 46100, 46600, 1200)),
(1640995320000, (46600, 47000, 46400, 46800, 1100)),
(1640995380000, (46800, 47200, 46700, 47000, 1300)),
(1640995440000, (47000, 47400, 46900, 47200, 1150)),
# Add more data points as needed...
]
print(f"Processing {len(sample_data)} data points...")
# Process data points
for timestamp, ohlcv in sample_data:
signal = trader.process_data_point(timestamp, ohlcv)
# Log significant signals
if signal.signal_type != 'HOLD':
print(f"Signal: {signal.signal_type} at price {ohlcv[3]} (confidence: {signal.confidence:.2f})")
# Get results
results = trader.get_results()
print(f"\nFinal Portfolio Value: ${results['final_portfolio_value']:.2f}")
print(f"Total Return: {results['total_return_pct']:.2f}%")
print(f"Number of Trades: {len(results['trades'])}")
def basic_backtesting():
"""Demonstrate basic backtesting functionality."""
print("\n=== Basic Backtesting ===")
# Note: In real usage, you would have a CSV file with historical data
# For this example, we'll create sample data
create_sample_data_file()
# Configure backtest
config = BacktestConfig(
initial_usd=10000,
stop_loss_pct=0.03,
take_profit_pct=0.06,
start_date="2024-01-01",
end_date="2024-01-31",
fee_pct=0.001,
slippage_pct=0.0005
)
# Create backtester
backtester = IncBacktester()
# Test MetaTrend strategy
print("Testing MetaTrend Strategy...")
results = backtester.run_single_strategy(
strategy_class=MetaTrendStrategy,
strategy_params={"timeframe": "15min"},
config=config,
data_file="sample_data.csv"
)
# Print results
performance = results['performance_metrics']
print(f"Total Return: {performance['total_return_pct']:.2f}%")
print(f"Sharpe Ratio: {performance['sharpe_ratio']:.2f}")
print(f"Max Drawdown: {performance['max_drawdown_pct']:.2f}%")
print(f"Win Rate: {performance['win_rate']:.2f}%")
print(f"Total Trades: {performance['total_trades']}")
def compare_strategies():
"""Compare different strategies on the same data."""
print("\n=== Strategy Comparison ===")
# Ensure we have sample data
create_sample_data_file()
# Configure backtest
config = BacktestConfig(
initial_usd=10000,
start_date="2024-01-01",
end_date="2024-01-31"
)
# Strategies to compare
strategies = [
(MetaTrendStrategy, {"timeframe": "15min"}, "MetaTrend"),
(BBRSStrategy, {"timeframe": "15min"}, "BBRS"),
(RandomStrategy, {"timeframe": "15min", "seed": 42}, "Random")
]
backtester = IncBacktester()
results_comparison = {}
for strategy_class, params, name in strategies:
print(f"Testing {name} strategy...")
results = backtester.run_single_strategy(
strategy_class=strategy_class,
strategy_params=params,
config=config,
data_file="sample_data.csv"
)
results_comparison[name] = results['performance_metrics']
# Print comparison
print("\n--- Strategy Comparison Results ---")
print(f"{'Strategy':<12} {'Return %':<10} {'Sharpe':<8} {'Max DD %':<10} {'Trades':<8}")
print("-" * 50)
for name, performance in results_comparison.items():
print(f"{name:<12} {performance['total_return_pct']:<10.2f} "
f"{performance['sharpe_ratio']:<8.2f} {performance['max_drawdown_pct']:<10.2f} "
f"{performance['total_trades']:<8}")
def create_sample_data_file():
"""Create a sample data file for backtesting examples."""
import numpy as np
from datetime import datetime, timedelta
# Generate sample OHLCV data
start_date = datetime(2024, 1, 1)
end_date = datetime(2024, 1, 31)
# Generate timestamps (1-minute intervals)
timestamps = []
current_time = start_date
while current_time <= end_date:
timestamps.append(int(current_time.timestamp() * 1000))
current_time += timedelta(minutes=1)
# Generate realistic price data with some trend
np.random.seed(42) # For reproducible results
initial_price = 45000
prices = [initial_price]
for i in range(1, len(timestamps)):
# Add some trend and random walk
trend = 0.0001 * i # Slight upward trend
random_change = np.random.normal(0, 0.002) # 0.2% volatility
new_price = prices[-1] * (1 + trend + random_change)
prices.append(new_price)
# Generate OHLCV data
data = []
for i, (timestamp, close) in enumerate(zip(timestamps, prices)):
# Generate realistic OHLC from close price
volatility = close * 0.001 # 0.1% intrabar volatility
high = close + np.random.uniform(0, volatility)
low = close - np.random.uniform(0, volatility)
open_price = low + np.random.uniform(0, high - low)
# Ensure OHLC consistency
high = max(high, open_price, close)
low = min(low, open_price, close)
volume = np.random.uniform(800, 1500) # Random volume
data.append({
'timestamp': timestamp,
'open': round(open_price, 2),
'high': round(high, 2),
'low': round(low, 2),
'close': round(close, 2),
'volume': round(volume, 2)
})
# Save to CSV
df = pd.DataFrame(data)
df.to_csv("sample_data.csv", index=False)
print(f"Created sample data file with {len(data)} data points")
def indicator_usage_example():
"""Demonstrate how to use indicators directly."""
print("\n=== Direct Indicator Usage ===")
from IncrementalTrader.strategies.indicators import (
MovingAverageState, RSIState, SupertrendState, BollingerBandsState
)
# Initialize indicators
sma_20 = MovingAverageState(period=20)
rsi_14 = RSIState(period=14)
supertrend = SupertrendState(period=10, multiplier=3.0)
bb = BollingerBandsState(period=20, std_dev=2.0)
# Sample price data
prices = [100, 101, 99, 102, 98, 103, 97, 104, 96, 105,
94, 106, 93, 107, 92, 108, 91, 109, 90, 110]
print("Processing price data with indicators...")
print(f"{'Price':<8} {'SMA20':<8} {'RSI14':<8} {'ST Signal':<10} {'BB %B':<8}")
print("-" * 50)
for i, price in enumerate(prices):
# Update indicators
sma_20.update(price)
rsi_14.update(price)
# For Supertrend, we need OHLC data (using price as close, with small spread)
high = price * 1.001
low = price * 0.999
supertrend.update_ohlc(high, low, price)
bb.update(price)
# Print values when indicators are ready
if i >= 19: # After warmup period
sma_val = sma_20.get_value() if sma_20.is_ready() else "N/A"
rsi_val = rsi_14.get_value() if rsi_14.is_ready() else "N/A"
st_signal = supertrend.get_signal() if supertrend.is_ready() else "N/A"
bb_percent_b = bb.get_percent_b(price) if bb.is_ready() else "N/A"
print(f"{price:<8.2f} {sma_val:<8.2f} {rsi_val:<8.2f} "
f"{st_signal:<10} {bb_percent_b:<8.2f}")
if __name__ == "__main__":
"""Run all examples."""
print("IncrementalTrader - Basic Usage Examples")
print("=" * 50)
try:
# Run examples
basic_strategy_usage()
basic_backtesting()
compare_strategies()
indicator_usage_example()
print("\n" + "=" * 50)
print("All examples completed successfully!")
print("\nNext steps:")
print("1. Replace sample data with your own historical data")
print("2. Experiment with different strategy parameters")
print("3. Create your own custom strategies")
print("4. Use parameter optimization for better results")
except Exception as e:
print(f"Error running examples: {e}")
print("Make sure you have the IncrementalTrader module properly installed.")

View File

@ -1,6 +1,6 @@
# Incremental Trading Refactoring - Task Progress
## Current Phase: Phase 3 - Strategy Migration 🚀 IN PROGRESS
## Current Phase: Phase 4 - Documentation and Examples ✅ COMPLETED
### Phase 1: Module Structure Setup ✅
- [x] **Task 1.1**: Create `IncrementalTrader/` directory structure ✅
@ -19,12 +19,14 @@
- [x] **Task 3.3**: Move BBRS strategy ✅ COMPLETED
- [x] **Task 3.4**: Move indicators ✅ COMPLETED (all needed indicators migrated)
### Phase 4: Documentation and Examples 🚀 NEXT
- [ ] **Task 4.1**: Create comprehensive documentation
- [ ] **Task 4.2**: Create usage examples
- [ ] **Task 4.3**: Migrate existing documentation
### Phase 4: Documentation and Examples ✅ COMPLETED
- [x] **Task 4.1**: Create comprehensive documentation ✅ COMPLETED
- [x] **Task 4.2**: Create usage examples ✅ COMPLETED
- [x] **Task 4.3**: Migrate existing documentation
✅ COMPLETED
- [x] **Task 4.4**: Create detailed strategy documentation ✅ COMPLETED
### Phase 5: Integration and Testing (Pending)
### Phase 5: Integration and Testing 🚀 NEXT
- [ ] **Task 5.1**: Update import statements
- [ ] **Task 5.2**: Update dependencies
- [ ] **Task 5.3**: Testing and validation
@ -38,6 +40,66 @@
## Progress Log
### 2024-01-XX - Task 4.4 Completed ✅
- ✅ Successfully created detailed strategy documentation for all three strategies
- ✅ Created comprehensive MetaTrend strategy documentation (`IncrementalTrader/docs/strategies/metatrend.md`)
- ✅ Created comprehensive BBRS strategy documentation (`IncrementalTrader/docs/strategies/bbrs.md`)
- ✅ Created comprehensive Random strategy documentation (`IncrementalTrader/docs/strategies/random.md`)
- ✅ Each documentation includes detailed process flow diagrams and implementation details
- ✅ Documented mathematical foundations, configuration parameters, and usage examples
- ✅ Added troubleshooting guides and advanced features for each strategy
**Task 4.4 Results:**
- **MetaTrend Documentation**: Complete guide with multi-Supertrend consensus algorithm details
- **BBRS Documentation**: Comprehensive mean-reversion strategy with market regime detection
- **Random Documentation**: Testing and benchmarking strategy with statistical validation features
- **Process Diagrams**: Visual flow diagrams showing data processing and signal generation
- **Implementation Details**: Code examples, configuration parameters, and optimization ranges
- **Performance Analysis**: Expected performance characteristics and backtesting results
**Key Documentation Features:**
- **Mathematical Foundations**: Detailed algorithms and calculations for each strategy
- **Process Flow Diagrams**: Visual representation of data flow and decision logic
- **Implementation Architecture**: Class hierarchies and component relationships
- **Configuration Management**: Parameter descriptions and optimization ranges
- **Usage Examples**: Basic, aggressive, and conservative configuration examples
- **Advanced Features**: Dynamic parameter adjustment and multi-timeframe analysis
- **Troubleshooting**: Common issues and debug information
- **Performance Metrics**: Expected results and statistical properties
**Phase 4 Summary - Documentation and Examples COMPLETED ✅:**
All documentation tasks have been successfully completed:
- ✅ **Comprehensive Documentation**: Complete API reference, guides, and examples
- ✅ **Usage Examples**: Practical examples for immediate use
- ✅ **Migration Guide**: Smooth transition path from legacy framework
- ✅ **Strategy Documentation**: Detailed documentation for all three strategies with process diagrams
**Ready for Phase 5:** Integration and testing can now begin with complete documentation.
### 2024-01-XX - Task 4.3 Completed ✅
- ✅ Successfully migrated existing documentation from legacy Cycles framework
- ✅ Created comprehensive migration guide (`IncrementalTrader/docs/migration.md`)
- ✅ Documented architectural changes and import updates
- ✅ Provided strategy migration patterns and examples
- ✅ Included compatibility layer documentation
- ✅ Added troubleshooting guide for common migration issues
- ✅ Preserved valuable timeframe system and strategy manager concepts from legacy docs
**Task 4.3 Results:**
- **Migration Guide**: Complete guide for transitioning from Cycles to IncrementalTrader
- **Architectural Mapping**: Clear mapping between old and new module structures
- **Import Updates**: Comprehensive list of import changes and compatibility aliases
- **Strategy Migration**: Detailed patterns for migrating existing strategies
- **Legacy Reference**: Preserved important concepts from original documentation
- **Troubleshooting**: Common issues and solutions for migration process
**Key Migration Features:**
- **Backward Compatibility**: Compatibility aliases for smooth transition
- **Gradual Migration**: Phased approach to minimize disruption
- **Enhanced Features**: Documentation of new capabilities and improvements
- **Performance Notes**: Memory efficiency and processing speed improvements
- **Resource Links**: Complete reference to new documentation structure
### 2024-01-XX - Task 3.3 Completed ✅
- ✅ Successfully migrated BBRS strategy with all dependencies
- ✅ Migrated Bollinger Bands indicators: `BollingerBandsState`, `BollingerBandsOHLCState`
@ -81,8 +143,6 @@ All major strategies have been successfully migrated:
- ✅ **BBRS Strategy**: Bollinger Bands + RSI with market regime detection
- ✅ **Complete Indicator Framework**: All indicators needed for strategies
**Ready for Phase 4:** Documentation and examples creation can now begin.
### 2024-01-XX - Task 3.2 Completed ✅
- ✅ Successfully migrated Random strategy for testing framework
- ✅ Created `IncrementalTrader/strategies/random.py` with enhanced Random strategy
@ -105,8 +165,6 @@ All major strategies have been successfully migrated:
- **Better Documentation**: Enhanced docstrings and examples
- **Compatibility**: Added `IncRandomStrategy` alias for backward compatibility
**Ready for Task 3.3:** BBRS strategy migration can now begin.
### 2024-01-XX - Task 3.1 Completed ✅
- ✅ Successfully migrated MetaTrend strategy and all its dependencies
- ✅ Migrated complete indicator framework: base classes, moving averages, ATR, Supertrend
@ -131,8 +189,6 @@ All major strategies have been successfully migrated:
- `SupertrendState`, `SupertrendCollection`: Supertrend indicators for trend detection
- `MetaTrendStrategy`: Complete strategy implementation with meta-trend calculation
**Ready for Task 3.2:** Random strategy migration can now begin.
### 2024-01-XX - Task 2.3 Completed ✅
- ✅ Successfully moved and refactored backtester implementation
- ✅ Created `IncrementalTrader/backtester/backtester.py` with enhanced architecture
@ -163,8 +219,6 @@ All major strategies have been successfully migrated:
- **System Resource Optimization**: Intelligent worker allocation based on system resources
- **Action Logging**: Comprehensive logging of all backtesting operations
**Ready for Phase 3:** Strategy migration can now begin with complete core framework.
### 2024-01-XX - Task 2.2 Completed ✅
- ✅ Successfully moved and refactored trader implementation
- ✅ Created `IncrementalTrader/trader/trader.py` with improved architecture
@ -191,8 +245,6 @@ All major strategies have been successfully migrated:
- **Improved Performance Tracking**: Portfolio history and detailed metrics
- **Flexible Fee Calculation**: Support for different exchange fee structures
**Ready for Task 2.3:** Backtester implementation migration can now begin.
### 2024-01-XX - Task 2.1 Completed ✅
- ✅ Successfully moved and refactored base classes
- ✅ Created `IncrementalTrader/strategies/base.py` with improved structure
@ -208,12 +260,6 @@ All major strategies have been successfully migrated:
- `IncStrategyBase`: Comprehensive base class with performance tracking
- All imports updated and working correctly
**Ready for Task 2.2:** Trader implementation migration can now begin.
### 2024-01-XX - Phase 2 Started 🚀
- 🚀 Starting Task 2.1: Moving and refactoring base classes
- Moving `cycles/IncStrategies/base.py``IncrementalTrader/strategies/base.py`
### 2024-01-XX - Phase 1 Completed ✅
- ✅ Created complete directory structure for IncrementalTrader module
- ✅ Set up all `__init__.py` files with proper module exports
@ -236,11 +282,13 @@ IncrementalTrader/
│ └── __init__.py # Backtester exports
└── docs/ # Documentation
├── README.md # Documentation index
└── architecture.md # System architecture
├── architecture.md # System architecture
└── strategies/ # Strategy documentation
├── metatrend.md # MetaTrend strategy guide
├── bbrs.md # BBRS strategy guide
└── random.md # Random strategy guide
```
**Ready for Phase 2:** Core component migration can now begin.
---
*This file tracks the progress of the incremental trading module refactoring.*