#!/bin/bash # PPO Comprehensive Hyperparameter Tuning - 50 Trials # Mission: Optimize PPO for better explained variance and Sharpe ratio # Expected Duration: 8-12 hours set -euo pipefail # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Configuration SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="${SCRIPT_DIR}" TUNING_CONFIG="${PROJECT_ROOT}/tuning_config_ppo_comprehensive.yaml" OUTPUT_DIR="${PROJECT_ROOT}/ml/trained_models/tuning/ppo_comprehensive" LOG_FILE="${OUTPUT_DIR}/tuning_execution.log" BASELINE_CHECKPOINT="${PROJECT_ROOT}/ml/trained_models/production/ppo_real_data/ppo_actor_epoch_380.safetensors" # Tuning parameters MODEL_TYPE="PPO" NUM_TRIALS=50 MAX_EPOCHS_PER_TRIAL=50 # Validation symbols (all 4 as specified) SYMBOLS=("6E.FUT" "ZN.FUT" "ES.FUT" "NQ.FUT") # Hardware configuration USE_GPU=true GPU_DEVICE=0 echo -e "${BLUE}╔════════════════════════════════════════════════════════════╗${NC}" echo -e "${BLUE}║ PPO Comprehensive Hyperparameter Tuning ║${NC}" echo -e "${BLUE}║ 50 Trials with Early Stopping at Epoch 50 ║${NC}" echo -e "${BLUE}╚════════════════════════════════════════════════════════════╝${NC}" echo "" # Function to print section headers print_section() { echo -e "\n${GREEN}═══ $1 ═══${NC}\n" } # Function to check prerequisites check_prerequisites() { print_section "Checking Prerequisites" # Check if baseline checkpoint exists if [ ! -f "${BASELINE_CHECKPOINT}" ]; then echo -e "${RED}✗ Baseline checkpoint not found: ${BASELINE_CHECKPOINT}${NC}" echo -e "${YELLOW} Run Agent 79 analysis first to generate baseline${NC}" exit 1 fi echo -e "${GREEN}✓ Baseline checkpoint found (Epoch 380)${NC}" # Check if tuning config exists if [ ! -f "${TUNING_CONFIG}" ]; then echo -e "${RED}✗ Tuning config not found: ${TUNING_CONFIG}${NC}" exit 1 fi echo -e "${GREEN}✓ Tuning configuration loaded${NC}" # Check GPU availability if command -v nvidia-smi &> /dev/null; then echo -e "${GREEN}✓ GPU detected:${NC}" nvidia-smi --query-gpu=name,memory.total,driver_version --format=csv,noheader else echo -e "${YELLOW}⚠ GPU not detected, will use CPU (slower)${NC}" USE_GPU=false fi # Check if services are running if ! pgrep -f "ml_training_service" > /dev/null; then echo -e "${YELLOW}⚠ ML Training Service not running, attempting to start...${NC}" cargo run -p ml_training_service --release & sleep 5 fi echo -e "${GREEN}✓ ML Training Service is running${NC}" # Check data files local missing_data=false for symbol in "${SYMBOLS[@]}"; do local data_file="${PROJECT_ROOT}/test_data/${symbol}_2024-01-02.dbn.zst" if [ ! -f "${data_file}" ]; then echo -e "${RED}✗ Missing data file: ${symbol}${NC}" missing_data=true else echo -e "${GREEN}✓ Data file found: ${symbol}${NC}" fi done if [ "$missing_data" = true ]; then echo -e "${RED}Some data files are missing. Please download them first.${NC}" exit 1 fi } # Function to create output directory prepare_output_directory() { print_section "Preparing Output Directory" mkdir -p "${OUTPUT_DIR}" mkdir -p "${OUTPUT_DIR}/logs" mkdir -p "${OUTPUT_DIR}/checkpoints" mkdir -p "${OUTPUT_DIR}/plots" echo -e "${GREEN}✓ Output directory prepared: ${OUTPUT_DIR}${NC}" # Initialize log file cat > "${LOG_FILE}" <5% over baseline" } # Function to start tuning via TLI start_tuning_job() { print_section "Starting Hyperparameter Tuning" echo "Initiating tuning job via TLI..." echo "Command: tli tune start --model ${MODEL_TYPE} --trials ${NUM_TRIALS} --config ${TUNING_CONFIG}" echo "" # Start tuning job and capture job ID local job_output job_output=$(cargo run -p tli -- tune start \ --model "${MODEL_TYPE}" \ --trials "${NUM_TRIALS}" \ --config "${TUNING_CONFIG}" 2>&1) # Extract job ID from output local job_id job_id=$(echo "${job_output}" | grep -oP 'Job ID: \K[a-f0-9-]+' || echo "") if [ -z "${job_id}" ]; then echo -e "${RED}✗ Failed to start tuning job${NC}" echo "${job_output}" exit 1 fi echo -e "${GREEN}✓ Tuning job started successfully${NC}" echo -e "Job ID: ${BLUE}${job_id}${NC}" echo "${job_id}" > "${OUTPUT_DIR}/job_id.txt" echo "${job_output}" >> "${LOG_FILE}" echo "" >> "${LOG_FILE}" echo "${job_id}" } # Function to monitor tuning progress monitor_tuning_progress() { local job_id=$1 print_section "Monitoring Tuning Progress" echo "Job ID: ${job_id}" echo "Press Ctrl+C to stop monitoring (tuning will continue in background)" echo "" local trial_count=0 local start_time=$(date +%s) while true; do # Get job status local status_output status_output=$(cargo run -p tli -- tune status --job-id "${job_id}" 2>&1 || true) # Extract current trial number local current_trial current_trial=$(echo "${status_output}" | grep -oP 'Trial \K\d+' | tail -1 || echo "0") # Extract status local status status=$(echo "${status_output}" | grep -oP 'Status: \K\w+' || echo "Unknown") # Display progress bar local progress=$((current_trial * 100 / NUM_TRIALS)) local filled=$((progress / 2)) local empty=$((50 - filled)) printf "\rProgress: [" printf "%${filled}s" | tr ' ' '=' printf "%${empty}s" | tr ' ' ' ' printf "] %3d%% (%d/%d trials)" "${progress}" "${current_trial}" "${NUM_TRIALS}" # Check if completed if [[ "${status}" == "Completed" ]] || [[ "${status}" == "Failed" ]]; then echo "" echo "" echo -e "${GREEN}Tuning job ${status}${NC}" break fi # Periodic status log if (( current_trial > trial_count )); then trial_count=${current_trial} local elapsed=$(($(date +%s) - start_time)) local avg_time_per_trial=$((elapsed / trial_count)) local remaining_trials=$((NUM_TRIALS - trial_count)) local eta=$((avg_time_per_trial * remaining_trials)) { echo "Trial ${trial_count}/${NUM_TRIALS} completed" echo " Elapsed: $(date -d@${elapsed} -u +%H:%M:%S)" echo " ETA: $(date -d@${eta} -u +%H:%M:%S)" echo "" } >> "${LOG_FILE}" fi sleep 10 done # Log final status echo "" >> "${LOG_FILE}" echo "Tuning completed at: $(date)" >> "${LOG_FILE}" echo "" >> "${LOG_FILE}" } # Function to retrieve best hyperparameters retrieve_best_hyperparameters() { local job_id=$1 print_section "Retrieving Best Hyperparameters" local best_output best_output=$(cargo run -p tli -- tune best --job-id "${job_id}" 2>&1) echo "${best_output}" echo "" >> "${LOG_FILE}" echo "═══ Best Hyperparameters ═══" >> "${LOG_FILE}" echo "${best_output}" >> "${LOG_FILE}" echo "" >> "${LOG_FILE}" # Save best params to file echo "${best_output}" > "${OUTPUT_DIR}/best_hyperparameters.txt" } # Function to compare with baseline compare_with_baseline() { print_section "Baseline Comparison" echo "Baseline (Epoch 380 from Agent 79 analysis):" echo " • Explained Variance: 0.4469" echo " • Distance from optimal: 0.0531" echo " • Training duration: 5.6 minutes (338.7 seconds)" echo " • Checkpoint: ${BASELINE_CHECKPOINT}" echo "" echo "Check the best hyperparameters output above for tuning results." echo "" { echo "═══ Baseline Comparison ═══" echo "Baseline: Epoch 380" echo " Explained Variance: 0.4469" echo " Distance from optimal: 0.0531" echo "" echo "Tuning results saved to: ${OUTPUT_DIR}/best_hyperparameters.txt" } >> "${LOG_FILE}" } # Function to generate summary report generate_summary_report() { print_section "Generating Summary Report" local report_file="${OUTPUT_DIR}/TUNING_SUMMARY_REPORT.md" cat > "${report_file}" </dev/null || echo "N/A") **Configuration**: ${TUNING_CONFIG} --- ## Tuning Configuration - **Model Type**: ${MODEL_TYPE} - **Number of Trials**: ${NUM_TRIALS} - **Max Epochs per Trial**: ${MAX_EPOCHS_PER_TRIAL} - **Early Stopping**: Enabled (epoch 50) - **GPU**: ${USE_GPU} - **Validation Symbols**: ${SYMBOLS[*]} ## Search Space | Hyperparameter | Search Space | Type | |----------------|--------------|------| | Learning Rate | [0.0001, 0.0003, 0.001] | Categorical | | Batch Size | [32, 64, 128, 256] | Categorical | | Gamma | [0.95, 0.99] | Categorical | | GAE Lambda | [0.9, 0.95, 0.98] | Categorical | | Clip Epsilon | [0.1, 0.2, 0.3] | Categorical | | Entropy Coefficient | [0.001, 0.01, 0.1] | Categorical | **Total Combinations**: 648 (intelligent sampling via TPE) ## Objective Function \`\`\` Combined Objective = 0.7 × Sharpe Ratio + 0.3 × Explained Variance \`\`\` ### Rationale - **Sharpe Ratio (70%)**: Primary metric for risk-adjusted returns - **Explained Variance (30%)**: Critical for PPO value network accuracy ## Baseline Performance - **Source**: Agent 79 checkpoint analysis - **Checkpoint**: Epoch 380 - **Explained Variance**: 0.4469 - **Distance from Optimal (0.5)**: 0.0531 - **Status**: EXCELLENT (within 5% of theoretical optimal) ## Best Hyperparameters \`\`\` $(cat "${OUTPUT_DIR}/best_hyperparameters.txt" 2>/dev/null || echo "Not available - check tuning job status") \`\`\` ## Value Network Convergence Analysis ### Focus Areas 1. **Explained Variance Trajectory**: Monitor convergence across trials 2. **Policy Stability**: Ensure KL divergence remains healthy 3. **Loss Dynamics**: Track policy loss and value loss evolution 4. **Entropy Decay**: Verify exploration-exploitation balance ### Expected Improvements - Target: >5% improvement in combined objective over baseline - Explained variance: Approach 0.47+ (vs 0.4469 baseline) - Sharpe ratio: Measure risk-adjusted performance across all symbols ## Next Steps 1. **Validation**: Run comprehensive backtest with best hyperparameters 2. **Cross-symbol Analysis**: Compare performance across 6E, ZN, ES, NQ 3. **Production Training**: Execute 500-epoch training with optimized hyperparameters 4. **Checkpoint Analysis**: Identify optimal checkpoint (may not be final epoch) ## Files Generated - **Tuning Log**: ${LOG_FILE} - **Best Hyperparameters**: ${OUTPUT_DIR}/best_hyperparameters.txt - **Checkpoints**: ${OUTPUT_DIR}/checkpoints/ - **Plots**: ${OUTPUT_DIR}/plots/ (if generated) - **This Report**: ${report_file} --- **Mission Status**: ✅ COMPLETE **Ready for**: Production training with optimized hyperparameters EOF echo -e "${GREEN}✓ Summary report generated: ${report_file}${NC}" } # Function to display completion summary display_completion_summary() { print_section "Tuning Complete" local elapsed=$(($(date +%s) - SCRIPT_START_TIME)) echo -e "${GREEN}╔════════════════════════════════════════════════════════════╗${NC}" echo -e "${GREEN}║ PPO Hyperparameter Tuning Completed Successfully ║${NC}" echo -e "${GREEN}╚════════════════════════════════════════════════════════════╝${NC}" echo "" echo "Duration: $(date -d@${elapsed} -u +%H:%M:%S)" echo "Trials: ${NUM_TRIALS}" echo "Output: ${OUTPUT_DIR}" echo "" echo "Next steps:" echo " 1. Review best hyperparameters in: ${OUTPUT_DIR}/best_hyperparameters.txt" echo " 2. Compare with baseline (Epoch 380)" echo " 3. Run production training with optimized hyperparameters" echo " 4. Perform checkpoint analysis to find optimal epoch" echo "" echo -e "${BLUE}Full summary report: ${OUTPUT_DIR}/TUNING_SUMMARY_REPORT.md${NC}" } # Main execution main() { SCRIPT_START_TIME=$(date +%s) # Execute tuning workflow check_prerequisites prepare_output_directory display_search_space display_objective # Start tuning job local job_id job_id=$(start_tuning_job) # Monitor progress monitor_tuning_progress "${job_id}" # Retrieve results retrieve_best_hyperparameters "${job_id}" compare_with_baseline # Generate reports generate_summary_report display_completion_summary } # Run main function main "$@"