Remove deprecated modules and files related to the backtesting framework, including backtest.py, cli.py, config.py, data.py, intrabar.py, logging_utils.py, market_costs.py, metrics.py, trade.py, and supertrend indicators. Introduce a new structure for the backtesting engine with improved organization and functionality, including a CLI handler, data manager, and reporting capabilities. Update dependencies in pyproject.toml to support the new architecture.

This commit is contained in:
2026-01-12 21:11:39 +08:00
parent c4aa965a98
commit 44fac1ed25
37 changed files with 5253 additions and 393 deletions

128
strategies/factory.py Normal file
View File

@@ -0,0 +1,128 @@
"""
Strategy factory for creating strategy instances with their parameters.
Centralizes strategy creation and parameter configuration.
"""
from dataclasses import dataclass, field
from typing import Any
import numpy as np
from strategies.base import BaseStrategy
@dataclass
class StrategyConfig:
"""
Configuration for a strategy including default and grid parameters.
Attributes:
strategy_class: The strategy class to instantiate
default_params: Parameters for single backtest runs
grid_params: Parameters for grid search optimization
"""
strategy_class: type[BaseStrategy]
default_params: dict[str, Any] = field(default_factory=dict)
grid_params: dict[str, Any] = field(default_factory=dict)
def _build_registry() -> dict[str, StrategyConfig]:
"""
Build the strategy registry lazily to avoid circular imports.
Returns:
Dictionary mapping strategy names to their configurations
"""
# Import here to avoid circular imports
from strategies.examples import MaCrossStrategy, RsiStrategy
from strategies.supertrend import MetaSupertrendStrategy
return {
"rsi": StrategyConfig(
strategy_class=RsiStrategy,
default_params={
'period': 14,
'rsi_lower': 30,
'rsi_upper': 70
},
grid_params={
'period': np.arange(10, 25, 2),
'rsi_lower': [20, 30, 40],
'rsi_upper': [60, 70, 80]
}
),
"macross": StrategyConfig(
strategy_class=MaCrossStrategy,
default_params={
'fast_window': 10,
'slow_window': 20
},
grid_params={
'fast_window': np.arange(5, 20, 5),
'slow_window': np.arange(20, 60, 10)
}
),
"meta_st": StrategyConfig(
strategy_class=MetaSupertrendStrategy,
default_params={
'period1': 12, 'multiplier1': 3.0,
'period2': 10, 'multiplier2': 1.0,
'period3': 11, 'multiplier3': 2.0
},
grid_params={
'multiplier1': [2.0, 3.0, 4.0],
'period1': [10, 12, 14],
'period2': 11, 'multiplier2': 2.0,
'period3': 12, 'multiplier3': 1.0
}
),
}
# Module-level cache for the registry
_REGISTRY_CACHE: dict[str, StrategyConfig] | None = None
def get_registry() -> dict[str, StrategyConfig]:
"""Get the strategy registry, building it on first access."""
global _REGISTRY_CACHE
if _REGISTRY_CACHE is None:
_REGISTRY_CACHE = _build_registry()
return _REGISTRY_CACHE
def get_strategy_names() -> list[str]:
"""
Get list of available strategy names.
Returns:
List of strategy name strings
"""
return list(get_registry().keys())
def get_strategy(name: str, is_grid: bool = False) -> tuple[BaseStrategy, dict[str, Any]]:
"""
Create a strategy instance with appropriate parameters.
Args:
name: Strategy identifier (e.g., 'rsi', 'macross', 'meta_st')
is_grid: If True, return grid search parameters
Returns:
Tuple of (strategy instance, parameters dict)
Raises:
KeyError: If strategy name is not found in registry
"""
registry = get_registry()
if name not in registry:
available = ", ".join(registry.keys())
raise KeyError(f"Unknown strategy '{name}'. Available: {available}")
config = registry[name]
strategy = config.strategy_class()
params = config.grid_params if is_grid else config.default_params
return strategy, params.copy()