#!/bin/bash # Automated backup script for Foxhunt HFT Trading System # Version: 3.0.0 # Wave 75 Agent 9 set -euo pipefail BACKUP_BASE_DIR="${BACKUP_BASE_DIR:-/opt/foxhunt/backups}" BACKUP_DIR="$BACKUP_BASE_DIR/$(date +%Y%m%d_%H%M%S)" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo " FOXHUNT HFT BACKUP PROCEDURE" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo " $(date '+%Y-%m-%d %H:%M:%S')" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" echo "Creating backup: $BACKUP_DIR" echo "" # Create backup directory mkdir -p "$BACKUP_DIR" # Backup binaries echo "[1/5] Backing up binaries..." if [ -d "/opt/foxhunt/bin" ]; then cp -r /opt/foxhunt/bin "$BACKUP_DIR/" echo "✅ Binaries backed up ($(du -sh $BACKUP_DIR/bin | awk '{print $1}'))" else echo "⚠️ Binary directory not found, skipping" fi # Backup configuration echo "[2/5] Backing up configuration..." if [ -d "/opt/foxhunt/config" ]; then cp -r /opt/foxhunt/config "$BACKUP_DIR/" 2>/dev/null || echo "⚠️ No config directory found" echo "✅ Configuration backed up" else echo "⚠️ Config directory not found, skipping" fi # Backup environment files echo "[3/5] Backing up environment files..." mkdir -p "$BACKUP_DIR/env" for env_file in /etc/foxhunt/*/.env; do if [ -f "$env_file" ]; then cp "$env_file" "$BACKUP_DIR/env/$(basename $(dirname $env_file)).env" 2>/dev/null || true fi done echo "✅ Environment files backed up" # Backup database echo "[4/5] Backing up database..." DB_NAME="${POSTGRES_DB:-foxhunt_production}" if sudo -u postgres pg_dump $DB_NAME 2>/dev/null | gzip > "$BACKUP_DIR/database.sql.gz"; then DB_SIZE=$(du -sh "$BACKUP_DIR/database.sql.gz" | awk '{print $1}') echo "✅ Database backed up ($DB_SIZE)" else echo "⚠️ Database backup failed (PostgreSQL may not be running)" fi # Backup Redis (RDB snapshot) echo "[5/5] Backing up Redis..." if redis-cli BGSAVE > /dev/null 2>&1; then sleep 2 # Wait for background save to complete if [ -f "/var/lib/redis/dump.rdb" ]; then cp /var/lib/redis/dump.rdb "$BACKUP_DIR/redis.rdb" 2>/dev/null || echo "⚠️ Redis RDB file not accessible" echo "✅ Redis backed up" else echo "⚠️ Redis RDB file not found" fi else echo "⚠️ Redis backup failed (Redis may not be running)" fi # Create manifest echo "" echo "Creating backup manifest..." cat > "$BACKUP_DIR/manifest.txt" </dev/null || echo "unknown") Backup Contents: - Binaries: $(du -sh "$BACKUP_DIR/bin" 2>/dev/null | awk '{print $1}' || echo "N/A") - Configuration: $(du -sh "$BACKUP_DIR/config" 2>/dev/null | awk '{print $1}' || echo "N/A") - Database: $(du -sh "$BACKUP_DIR/database.sql.gz" 2>/dev/null | awk '{print $1}' || echo "N/A") - Redis: $(du -sh "$BACKUP_DIR/redis.rdb" 2>/dev/null | awk '{print $1}' || echo "N/A") Total Backup Size: $(du -sh "$BACKUP_DIR" | awk '{print $1}') Service Status at Backup: $(systemctl is-active foxhunt-trading 2>/dev/null || echo "unknown") - Trading Service $(systemctl is-active foxhunt-backtesting 2>/dev/null || echo "unknown") - Backtesting Service $(systemctl is-active foxhunt-ml-training 2>/dev/null || echo "unknown") - ML Training Service Restore Command: $(dirname $0)/rollback.sh $BACKUP_DIR EOF echo "✅ Manifest created" # Cleanup old backups (keep last 30 days by default) RETENTION_DAYS="${BACKUP_RETENTION_DAYS:-30}" echo "" echo "Cleaning up backups older than $RETENTION_DAYS days..." REMOVED_COUNT=$(find $BACKUP_BASE_DIR -type d -name "20??????_??????" -mtime +$RETENTION_DAYS -exec rm -rf {} \; -print | wc -l) if [ "$REMOVED_COUNT" -gt 0 ]; then echo "✅ Removed $REMOVED_COUNT old backup(s)" else echo "✅ No old backups to remove" fi # Display summary echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo " ✅ BACKUP COMPLETE" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" echo "Backup location: $BACKUP_DIR" echo "Total size: $(du -sh "$BACKUP_DIR" | awk '{print $1}')" echo "" echo "Backup manifest:" cat "$BACKUP_DIR/manifest.txt" echo "" echo "To restore this backup:" echo " $(dirname $0)/rollback.sh $BACKUP_DIR"