129 lines
4.4 KiB
Python
129 lines
4.4 KiB
Python
"""
|
|
Configuration Manager
|
|
|
|
This module provides centralized configuration handling for the backtesting system.
|
|
It handles loading, validation, and provides a clean interface for accessing
|
|
configuration data.
|
|
"""
|
|
|
|
import json
|
|
import datetime
|
|
import logging
|
|
from typing import Dict, List, Optional, Any
|
|
from pathlib import Path
|
|
|
|
|
|
class ConfigManager:
|
|
"""
|
|
Manages configuration loading, validation, and access.
|
|
|
|
Provides a centralized way to handle configuration files with validation
|
|
and convenient access methods.
|
|
"""
|
|
|
|
def __init__(self, config_path: Optional[str] = None):
|
|
"""
|
|
Initialize configuration manager.
|
|
|
|
Args:
|
|
config_path: Path to configuration file. If None, uses default.
|
|
"""
|
|
self.config_path = config_path or "configs/config_default.json"
|
|
self.config = self._load_config()
|
|
self._validate_config()
|
|
|
|
def _load_config(self) -> Dict[str, Any]:
|
|
"""Load configuration from file."""
|
|
try:
|
|
with open(self.config_path, 'r') as f:
|
|
config = json.load(f)
|
|
logging.info(f"Loaded configuration from: {self.config_path}")
|
|
return config
|
|
except FileNotFoundError:
|
|
available_configs = list(Path("configs").glob("*.json"))
|
|
raise FileNotFoundError(
|
|
f"Config file '{self.config_path}' not found. "
|
|
f"Available configs: {[str(c) for c in available_configs]}"
|
|
)
|
|
except json.JSONDecodeError as e:
|
|
raise ValueError(f"Invalid JSON in config file '{self.config_path}': {e}")
|
|
|
|
def _validate_config(self) -> None:
|
|
"""Validate configuration structure and values."""
|
|
required_fields = ['start_date', 'initial_usd', 'timeframes', 'strategies']
|
|
|
|
for field in required_fields:
|
|
if field not in self.config:
|
|
raise ValueError(f"Missing required field '{field}' in configuration")
|
|
|
|
# Validate strategies
|
|
if not self.config['strategies']:
|
|
raise ValueError("At least one strategy must be specified")
|
|
|
|
for strategy in self.config['strategies']:
|
|
if 'name' not in strategy:
|
|
raise ValueError("Strategy must have a 'name' field")
|
|
|
|
# Validate timeframes
|
|
if not self.config['timeframes']:
|
|
raise ValueError("At least one timeframe must be specified")
|
|
|
|
logging.info("Configuration validation successful")
|
|
|
|
@property
|
|
def start_date(self) -> str:
|
|
"""Get start date."""
|
|
return self.config['start_date']
|
|
|
|
@property
|
|
def stop_date(self) -> str:
|
|
"""Get stop date, defaulting to current date if None."""
|
|
stop_date = self.config.get('stop_date')
|
|
if stop_date is None:
|
|
return datetime.datetime.now().strftime("%Y-%m-%d")
|
|
return stop_date
|
|
|
|
@property
|
|
def initial_usd(self) -> float:
|
|
"""Get initial USD amount."""
|
|
return self.config['initial_usd']
|
|
|
|
@property
|
|
def timeframes(self) -> List[str]:
|
|
"""Get list of timeframes to test."""
|
|
return self.config['timeframes']
|
|
|
|
@property
|
|
def strategies_config(self) -> List[Dict[str, Any]]:
|
|
"""Get strategies configuration."""
|
|
return self.config['strategies']
|
|
|
|
@property
|
|
def combination_rules(self) -> Dict[str, Any]:
|
|
"""Get combination rules for strategy manager."""
|
|
return self.config.get('combination_rules', {
|
|
"entry": "any",
|
|
"exit": "any",
|
|
"min_confidence": 0.5
|
|
})
|
|
|
|
def get_strategy_manager_config(self) -> Dict[str, Any]:
|
|
"""Get configuration for strategy manager."""
|
|
return {
|
|
"strategies": self.strategies_config,
|
|
"combination_rules": self.combination_rules
|
|
}
|
|
|
|
def get_timeframe_task_config(self, timeframe: str) -> Dict[str, Any]:
|
|
"""Get configuration for a specific timeframe task."""
|
|
return {
|
|
"initial_usd": self.initial_usd,
|
|
"strategies": self.strategies_config,
|
|
"combination_rules": self.combination_rules
|
|
}
|
|
|
|
def __repr__(self) -> str:
|
|
"""String representation of configuration."""
|
|
return (f"ConfigManager(config_path='{self.config_path}', "
|
|
f"strategies={len(self.strategies_config)}, "
|
|
f"timeframes={len(self.timeframes)})") |