188 lines
5.3 KiB
Python
188 lines
5.3 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Backtesting & Bulk Training
|
|
|
|
Main entry point for:
|
|
- Historical data backtesting
|
|
- Fast sliding-window training
|
|
- Model performance evaluation
|
|
- Checkpoint management
|
|
|
|
Usage:
|
|
python main_backtest.py --start YYYY-MM-DD --end YYYY-MM-DD [--symbol SYMBOL] [--window HOURS]
|
|
|
|
Examples:
|
|
# Run 30-day backtest with default settings
|
|
python main_backtest.py --start 2024-01-01 --end 2024-01-31
|
|
|
|
# Custom symbol and window size
|
|
python main_backtest.py --start 2024-01-01 --end 2024-12-31 --symbol BTC/USDT --window 48
|
|
|
|
# Resume from checkpoint
|
|
python main_backtest.py --start 2024-01-01 --end 2024-12-31 --resume
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import logging
|
|
import argparse
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
|
|
# Add project root to path
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
|
|
# Import training runner
|
|
try:
|
|
from training_runner import UnifiedTrainingRunner
|
|
from core.config import setup_logging
|
|
except ImportError as e:
|
|
print(f"Error importing modules: {e}")
|
|
sys.exit(1)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def validate_date(date_str: str) -> datetime:
|
|
"""Validate and parse date string"""
|
|
try:
|
|
return datetime.strptime(date_str, '%Y-%m-%d')
|
|
except ValueError:
|
|
raise argparse.ArgumentTypeError(f"Invalid date format: {date_str}. Use YYYY-MM-DD")
|
|
|
|
|
|
def main():
|
|
"""Main entry point for backtesting"""
|
|
parser = argparse.ArgumentParser(
|
|
description='Backtesting & Bulk Training System',
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
epilog="""
|
|
Examples:
|
|
# 30-day backtest
|
|
python main_backtest.py --start 2024-01-01 --end 2024-01-31
|
|
|
|
# Year-long training with custom parameters
|
|
python main_backtest.py --start 2024-01-01 --end 2024-12-31 --symbol BTC/USDT --window 48
|
|
|
|
# Fast backtest with smaller window
|
|
python main_backtest.py --start 2024-12-01 --end 2024-12-31 --window 12 --step 6
|
|
"""
|
|
)
|
|
|
|
# Required arguments
|
|
parser.add_argument(
|
|
'--start',
|
|
type=str,
|
|
required=True,
|
|
help='Start date for backtesting (YYYY-MM-DD)'
|
|
)
|
|
parser.add_argument(
|
|
'--end',
|
|
type=str,
|
|
required=True,
|
|
help='End date for backtesting (YYYY-MM-DD)'
|
|
)
|
|
|
|
# Optional arguments
|
|
parser.add_argument(
|
|
'--symbol',
|
|
type=str,
|
|
default='ETH/USDT',
|
|
help='Trading symbol (default: ETH/USDT)'
|
|
)
|
|
parser.add_argument(
|
|
'--window',
|
|
type=int,
|
|
default=24,
|
|
help='Sliding window size in hours (default: 24)'
|
|
)
|
|
parser.add_argument(
|
|
'--step',
|
|
type=int,
|
|
default=1,
|
|
help='Window step size in hours (default: 1)'
|
|
)
|
|
parser.add_argument(
|
|
'--resume',
|
|
action='store_true',
|
|
help='Resume from last checkpoint'
|
|
)
|
|
parser.add_argument(
|
|
'--save-interval',
|
|
type=int,
|
|
default=2,
|
|
help='Checkpoint save interval in hours (default: 2)'
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
# Validate dates
|
|
try:
|
|
start_date = validate_date(args.start)
|
|
end_date = validate_date(args.end)
|
|
except argparse.ArgumentTypeError as e:
|
|
parser.error(str(e))
|
|
|
|
if start_date >= end_date:
|
|
parser.error("Start date must be before end date")
|
|
|
|
# Calculate duration
|
|
duration_days = (end_date - start_date).days
|
|
|
|
# Setup logging
|
|
try:
|
|
setup_logging()
|
|
logger.info("=" * 80)
|
|
logger.info("BACKTESTING & BULK TRAINING SYSTEM")
|
|
logger.info("=" * 80)
|
|
logger.info(f"Symbol: {args.symbol}")
|
|
logger.info(f"Period: {args.start} to {args.end} ({duration_days} days)")
|
|
logger.info(f"Window: {args.window}h, Step: {args.step}h")
|
|
logger.info(f"Checkpoint Interval: {args.save_interval}h")
|
|
logger.info(f"Resume from checkpoint: {'YES' if args.resume else 'NO'}")
|
|
logger.info("=" * 80)
|
|
except Exception as e:
|
|
print(f"Error setting up logging: {e}")
|
|
|
|
# Ensure logs directory exists
|
|
Path('logs').mkdir(exist_ok=True)
|
|
|
|
try:
|
|
# Create training runner in backtest mode
|
|
logger.info("Initializing backtest training runner...")
|
|
runner = UnifiedTrainingRunner(
|
|
mode='backtest',
|
|
symbol=args.symbol
|
|
)
|
|
|
|
# Update configuration
|
|
runner.config['backtest']['window_size_hours'] = args.window
|
|
runner.config['backtest']['step_size_hours'] = args.step
|
|
runner.config['backtest']['save_interval_hours'] = args.save_interval
|
|
|
|
# Run backtest training
|
|
logger.info("Starting backtest training...")
|
|
runner.run_backtest_training(
|
|
start_date=start_date,
|
|
end_date=end_date
|
|
)
|
|
|
|
logger.info("=" * 80)
|
|
logger.info("BACKTEST TRAINING COMPLETE")
|
|
logger.info("=" * 80)
|
|
|
|
except KeyboardInterrupt:
|
|
logger.info("Backtest interrupted by user")
|
|
sys.exit(0)
|
|
except Exception as e:
|
|
logger.error(f"Error during backtest: {e}")
|
|
import traceback
|
|
logger.error(traceback.format_exc())
|
|
sys.exit(1)
|
|
finally:
|
|
logger.info("Backtest runner shutdown complete")
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|