Last active
August 4, 2025 08:54
-
-
Save hoangtrung99/73593690940ff91015063f2b6f9366a3 to your computer and use it in GitHub Desktop.
AutoTrader Bot Script - Updated 2025-08-04 08:54:48 UTC
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| #!/bin/bash | |
| # AutoTrader Bot - Compact Version (Server Deployment Script) | |
| # Focused on core deployment and system operations | |
| # Complex logic moved to Python CLI tools | |
| set -euo pipefail | |
| # Version and basic config | |
| SCRIPT_VERSION="3.3.3" | |
| VERSION="$SCRIPT_VERSION" | |
| SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | |
| DOCKER_CMD="docker" | |
| # =============================== | |
| # Constants and Utilities (inlined - no external dependencies) | |
| # =============================== | |
| # Directory constants | |
| AUTOTRADER_DIR="$HOME/.autotrader" | |
| CREDENTIALS_DIR="$AUTOTRADER_DIR/credentials" | |
| CONFIG_DIR="./configs" | |
| DATA_DIR="./data" | |
| LOGS_DIR="./logs" | |
| # Safe docker inspect with timeout (works on both Linux and macOS) | |
| safe_docker_inspect() { | |
| local image="$1" | |
| local timeout_seconds="${2:-5}" | |
| # Try with timeout if available, otherwise fallback to regular command | |
| if command -v timeout &>/dev/null; then | |
| timeout "$timeout_seconds" docker image inspect "$image" &>/dev/null | |
| elif command -v gtimeout &>/dev/null; then | |
| gtimeout "$timeout_seconds" docker image inspect "$image" &>/dev/null | |
| else | |
| # Fallback without timeout (risk of hanging) | |
| docker image inspect "$image" &>/dev/null | |
| fi | |
| } | |
| # Docker image names - smart detection | |
| detect_and_set_images() { | |
| local silent="${1:-false}" | |
| local registry_telegram="ghcr.io/hoangtrung99/autotrader-telegram:latest" | |
| local registry_trader="ghcr.io/hoangtrung99/autotrader-trader:latest" | |
| local local_telegram="autotrader-telegram:latest" | |
| local local_trader="autotrader-trader:latest" | |
| # Check if LOCAL mode is explicitly enabled | |
| if [[ "${LOCAL:-false}" == "true" ]]; then | |
| TELEGRAM_IMAGE="$local_telegram" | |
| TRADER_IMAGE="$local_trader" | |
| [[ "$silent" != "true" ]] && echo "🔧 LOCAL mode enabled - using local Docker images" | |
| return | |
| fi | |
| # Auto-detect available images (prefer registry, fallback to local) | |
| [[ "$silent" != "true" ]] && echo "🔍 Auto-detecting available Docker images..." | |
| # Check Telegram image with safe timeout | |
| if safe_docker_inspect "$registry_telegram" 5; then | |
| TELEGRAM_IMAGE="$registry_telegram" | |
| [[ "$silent" != "true" ]] && echo "✅ Found registry Telegram image: $registry_telegram" | |
| elif safe_docker_inspect "$local_telegram" 5; then | |
| TELEGRAM_IMAGE="$local_telegram" | |
| [[ "$silent" != "true" ]] && echo "✅ Found local Telegram image: $local_telegram" | |
| else | |
| TELEGRAM_IMAGE="$local_telegram" | |
| [[ "$silent" != "true" ]] && echo "⚠️ No Telegram image found, will build: $local_telegram" | |
| fi | |
| # Check Trader image with safe timeout | |
| if safe_docker_inspect "$registry_trader" 5; then | |
| TRADER_IMAGE="$registry_trader" | |
| [[ "$silent" != "true" ]] && echo "✅ Found registry Trader image: $registry_trader" | |
| elif safe_docker_inspect "$local_trader" 5; then | |
| TRADER_IMAGE="$local_trader" | |
| [[ "$silent" != "true" ]] && echo "✅ Found local Trader image: $local_trader" | |
| else | |
| TRADER_IMAGE="$local_trader" | |
| [[ "$silent" != "true" ]] && echo "⚠️ No Trader image found, will build: $local_trader" | |
| fi | |
| } | |
| # Set images based on detection (silent for system-status) | |
| # Only detect if Docker is available to prevent script exit | |
| if command -v docker &> /dev/null && docker ps &> /dev/null; then | |
| # Use registry images directly to avoid hanging issue | |
| TELEGRAM_IMAGE="ghcr.io/hoangtrung99/autotrader-telegram:latest" | |
| TRADER_IMAGE="ghcr.io/hoangtrung99/autotrader-trader:latest" | |
| else | |
| # Set default images when Docker is not available | |
| TELEGRAM_IMAGE="autotrader-telegram:latest" | |
| TRADER_IMAGE="autotrader-trader:latest" | |
| fi | |
| # Environment variable names | |
| TELEGRAM_BOT_TOKEN_VAR="TELEGRAM_BOT_TOKEN" | |
| BYBIT_API_KEY_VAR="BYBIT_API_KEY" | |
| BYBIT_API_SECRET_VAR="BYBIT_API_SECRET" | |
| BYBIT_SECRET_KEY_VAR="BYBIT_SECRET_KEY" | |
| # Default values | |
| DEFAULT_TRADING_AMOUNT="50" | |
| DEFAULT_SYMBOL_SUFFIX="/USDT:USDT" | |
| DEFAULT_DIRECTION="LONG" | |
| DEFAULT_TEST_MODE="false" | |
| DEFAULT_CREDENTIAL_PROFILE="default" | |
| CREDENTIAL_FILE_PERMISSIONS="600" | |
| # Utility functions (inlined) | |
| ensure_directories() { | |
| mkdir -p "$AUTOTRADER_DIR" "$CREDENTIALS_DIR" "$CONFIG_DIR" "$DATA_DIR" "$LOGS_DIR" | |
| chmod 755 "$AUTOTRADER_DIR" "$CREDENTIALS_DIR" "$CONFIG_DIR" "$DATA_DIR" 2>/dev/null || true | |
| # Set 777 for logs directory to ensure container can write logs | |
| chmod 777 "$LOGS_DIR" 2>/dev/null || true | |
| } | |
| # Standardized messaging functions | |
| print_error() { | |
| echo "❌ $1" >&2 | |
| } | |
| print_success() { | |
| echo "✅ $1" | |
| } | |
| print_warning() { | |
| echo "⚠️ $1" | |
| } | |
| print_info() { | |
| echo "ℹ️ $1" | |
| } | |
| print_step() { | |
| echo "🔄 $1" | |
| } | |
| # Standardized error handling | |
| handle_command_error() { | |
| local command="$1" | |
| local error_msg="$2" | |
| local suggestion="${3:-}" | |
| print_error "$error_msg" | |
| if [[ -n "$suggestion" ]]; then | |
| echo "" | |
| echo "💡 Suggestion: $suggestion" | |
| fi | |
| echo "" | |
| echo "📖 For help: ./bot.sh help" | |
| echo "🔍 For system status: ./bot.sh system-status" | |
| return 1 | |
| } | |
| normalize_symbol() { | |
| local symbol="$1" | |
| local upper_symbol=$(echo "$symbol" | tr '[:lower:]' '[:upper:]') | |
| if [[ "$upper_symbol" =~ / ]]; then | |
| echo "$upper_symbol" | |
| return | |
| fi | |
| if [[ "$upper_symbol" =~ USDT$ ]]; then | |
| local base_symbol="${upper_symbol%USDT}" | |
| echo "${base_symbol}/USDT:USDT" | |
| else | |
| echo "${upper_symbol}$DEFAULT_SYMBOL_SUFFIX" | |
| fi | |
| } | |
| get_container_name() { | |
| local symbol="$1" | |
| local profile="$2" | |
| local base_symbol=$(echo "$symbol" | cut -d'/' -f1 | tr '[:upper:]' '[:lower:]') | |
| base_symbol="${base_symbol%usdt}" | |
| if [[ -n "$profile" ]]; then | |
| echo "${profile}-${base_symbol}usdt" | |
| else | |
| # Backward compatibility - return old format | |
| echo "${base_symbol}usdt" | |
| fi | |
| } | |
| # Auto-load .env file if exists | |
| if [[ -f ".env" ]]; then | |
| source .env | |
| fi | |
| # Environment variables with defaults | |
| TELEGRAM_BOT_TOKEN="${TELEGRAM_BOT_TOKEN:-}" | |
| # =============================== | |
| # Additional Utility Functions | |
| # =============================== | |
| # (Core utilities are now in src/core/shell_constants.sh) | |
| check_docker() { | |
| if ! command -v docker &> /dev/null; then | |
| print_error "Docker chưa được cài đặt hoặc không có trong PATH" | |
| echo "" | |
| echo "💡 Cách khắc phục:" | |
| echo " - macOS: Tải Docker Desktop từ docker.com" | |
| echo " - Linux: curl -fsSL https://get.docker.com -o get-docker.sh && sh get-docker.sh" | |
| echo " - Hoặc chạy: ./bot.sh setup" | |
| return 1 | |
| fi | |
| if ! docker info &> /dev/null; then | |
| print_error "Docker daemon không chạy" | |
| echo "" | |
| echo "💡 Cách khắc phục:" | |
| echo " - macOS: Mở Docker Desktop application" | |
| echo " - Linux: sudo systemctl start docker" | |
| echo " - Hoặc khởi động Docker service trên hệ thống của bạn" | |
| return 1 | |
| fi | |
| return 0 | |
| } | |
| # Fallback to local runner when Docker is not available | |
| suggest_local_runner() { | |
| echo "" | |
| print_info "Docker không có sẵn. Các phương án thay thế:" | |
| echo "" | |
| echo "🐍 Local Runner (Python):" | |
| echo " ./run_local.sh setup # Setup môi trường local" | |
| echo " ./run_local.sh telegram # Chạy Telegram bot local" | |
| echo " ./run_local.sh start eth # Chạy trading bot local" | |
| echo "" | |
| echo "🐳 Cài đặt Docker (khuyến nghị):" | |
| echo " - macOS: Tải Docker Desktop từ docker.com" | |
| echo " - Linux: curl -fsSL https://get.docker.com -o get-docker.sh && sh get-docker.sh" | |
| echo " - Hoặc chạy: ./bot.sh setup" | |
| echo "" | |
| echo "📖 Để biết thêm thông tin: ./bot.sh help" | |
| } | |
| check_python() { | |
| if ! command -v python3 &> /dev/null; then | |
| print_error "Python3 chưa được cài đặt" | |
| echo "" | |
| echo "💡 Cách khắc phục:" | |
| echo " - macOS: brew install python3" | |
| echo " - Ubuntu/Debian: sudo apt install python3" | |
| echo " - CentOS/RHEL: sudo yum install python3" | |
| echo " - Hoặc tải từ python.org" | |
| return 1 | |
| fi | |
| return 0 | |
| } | |
| # Docker CLI wrapper - runs Python CLI commands in Docker container | |
| run_docker_cli() { | |
| local cli_script="$1" | |
| shift | |
| # Check if Docker is available | |
| if ! check_docker; then | |
| print_error "Docker cần thiết để chạy lệnh này" | |
| echo "" | |
| echo "💡 Các lựa chọn khác:" | |
| echo " - Cài đặt Docker: ./bot.sh setup" | |
| echo " - Sử dụng local runner: ./run_local.sh (nếu có)" | |
| return 1 | |
| fi | |
| # Ensure directories exist for volume mounts | |
| ensure_directories | |
| # Get absolute paths for volume mounts | |
| local ABS_CONFIG_DIR="$(realpath "$CONFIG_DIR")" | |
| local ABS_DATA_DIR="$(realpath "$DATA_DIR")" | |
| local ABS_LOGS_DIR="$(realpath "$LOGS_DIR")" | |
| local ABS_AUTOTRADER_DIR="$(realpath "$AUTOTRADER_DIR")" | |
| # Use TRADER_IMAGE for CLI commands that need full dependencies | |
| local image_to_use="$TRADER_IMAGE" | |
| if [[ "$cli_script" == "assets_cli" ]]; then | |
| echo "🔍 Using trader image for assets command (requires ccxt)..." | |
| image_to_use="$TRADER_IMAGE" | |
| elif [[ "$cli_script" == "python3" && "$1" == "/app/src/core/unified_command_processor.py" ]]; then | |
| echo "🔍 Using local telegram image for unified processor..." | |
| image_to_use="autotrader-telegram:latest" | |
| else | |
| image_to_use="$TELEGRAM_IMAGE" | |
| fi | |
| # Check if this is a unified processor call | |
| if [[ "$cli_script" == "python3" && "$1" == "/app/src/core/unified_command_processor.py" ]]; then | |
| # Unified processor call - use direct path | |
| shift # Remove the path argument | |
| docker run --rm \ | |
| --user root \ | |
| -v "$ABS_CONFIG_DIR:/app/configs" \ | |
| -v "$ABS_DATA_DIR:/app/data" \ | |
| -v "$ABS_LOGS_DIR:/app/logs" \ | |
| -v "$ABS_AUTOTRADER_DIR:/root/.autotrader" \ | |
| -v /var/run/docker.sock:/var/run/docker.sock \ | |
| -e BYBIT_API_KEY="${BYBIT_API_KEY:-}" \ | |
| -e BYBIT_API_SECRET="${BYBIT_API_SECRET:-}" \ | |
| -e BYBIT_SECRET_KEY="${BYBIT_SECRET_KEY:-}" \ | |
| "$image_to_use" \ | |
| python3 "/app/src/core/unified_command_processor.py" "$@" | |
| else | |
| # Traditional CLI script call | |
| docker run --rm \ | |
| --user root \ | |
| -v "$ABS_CONFIG_DIR:/app/configs" \ | |
| -v "$ABS_DATA_DIR:/app/data" \ | |
| -v "$ABS_LOGS_DIR:/app/logs" \ | |
| -v "$ABS_AUTOTRADER_DIR:/root/.autotrader" \ | |
| -v /var/run/docker.sock:/var/run/docker.sock \ | |
| -e BYBIT_API_KEY="${BYBIT_API_KEY:-}" \ | |
| -e BYBIT_API_SECRET="${BYBIT_API_SECRET:-}" \ | |
| -e BYBIT_SECRET_KEY="${BYBIT_SECRET_KEY:-}" \ | |
| "$image_to_use" \ | |
| python3 "src/cli/${cli_script}.py" "$@" | |
| fi | |
| } | |
| # =============================== | |
| # System Setup Functions | |
| # =============================== | |
| extract_template_from_image() { | |
| echo "📄 Extracting template config from Docker image..." | |
| # Pull trader image if not exists | |
| if ! docker image inspect "$TRADER_IMAGE" &>/dev/null; then | |
| echo "🐳 Pulling trader image: $TRADER_IMAGE" | |
| if ! docker pull "$TRADER_IMAGE"; then | |
| echo "❌ Failed to pull trader image" | |
| return 1 | |
| fi | |
| fi | |
| # Extract template.json from image | |
| local temp_container="temp_extract_$$" | |
| # Create temporary container and copy template | |
| if docker create --name "$temp_container" "$TRADER_IMAGE" >/dev/null 2>&1; then | |
| if docker cp "$temp_container:/app/template.json" "$CONFIG_DIR/template.json" 2>/dev/null; then | |
| echo "✅ Extracted template.json from image" | |
| else | |
| echo "⚠️ Could not extract template.json from image, creating basic template..." | |
| create_basic_template | |
| fi | |
| docker rm "$temp_container" >/dev/null 2>&1 | |
| else | |
| echo "⚠️ Could not create temporary container, creating basic template..." | |
| create_basic_template | |
| fi | |
| } | |
| create_basic_template() { | |
| cat > "$CONFIG_DIR/template.json" << 'EOF' | |
| { | |
| "symbol": "SYMBOL_PLACEHOLDER", | |
| "exchange": "bybit", | |
| "direction": "LONG", | |
| "amount": 50.0, | |
| "use_test_mode": false, | |
| "use_sandbox": false, | |
| "order_type": "limit", | |
| "signal_cooldown_minutes": 3.0, | |
| "trading_loop_interval_seconds": 10, | |
| "log_level": "INFO", | |
| "save_trades_to_csv": true, | |
| "enable_notifications": true | |
| } | |
| EOF | |
| } | |
| ensure_docker_images() { | |
| echo "🔍 Ensuring Docker images are available..." | |
| # Re-detect images in case they were pulled/built since startup | |
| detect_and_set_images | |
| local need_build=false | |
| local need_pull=false | |
| # Check if current Telegram image exists | |
| if ! docker image inspect "$TELEGRAM_IMAGE" &>/dev/null; then | |
| echo "⚠️ Telegram image not found: $TELEGRAM_IMAGE" | |
| # If it's a registry image, try to pull it first | |
| if [[ "$TELEGRAM_IMAGE" == ghcr.io/* ]]; then | |
| echo "🐳 Attempting to pull Telegram image from registry..." | |
| if docker pull "$TELEGRAM_IMAGE" 2>/dev/null; then | |
| echo "✅ Successfully pulled Telegram image" | |
| else | |
| echo "⚠️ Failed to pull from registry, will build locally" | |
| TELEGRAM_IMAGE="autotrader-telegram:latest" | |
| need_build=true | |
| fi | |
| else | |
| need_build=true | |
| fi | |
| else | |
| echo "✅ Telegram image found: $TELEGRAM_IMAGE" | |
| fi | |
| # Check if current Trader image exists | |
| if ! docker image inspect "$TRADER_IMAGE" &>/dev/null; then | |
| echo "⚠️ Trader image not found: $TRADER_IMAGE" | |
| # If it's a registry image, try to pull it first | |
| if [[ "$TRADER_IMAGE" == ghcr.io/* ]]; then | |
| echo "🐳 Attempting to pull Trader image from registry..." | |
| if docker pull "$TRADER_IMAGE" 2>/dev/null; then | |
| echo "✅ Successfully pulled Trader image" | |
| else | |
| echo "⚠️ Failed to pull from registry, will build locally" | |
| TRADER_IMAGE="autotrader-trader:latest" | |
| need_build=true | |
| fi | |
| else | |
| need_build=true | |
| fi | |
| else | |
| echo "✅ Trader image found: $TRADER_IMAGE" | |
| fi | |
| # Build images if needed | |
| if [[ "$need_build" == "true" ]]; then | |
| echo "🔨 Building missing Docker images locally..." | |
| build_docker_images | |
| return $? | |
| else | |
| echo "✅ All required Docker images are available" | |
| return 0 | |
| fi | |
| } | |
| build_docker_images() { | |
| echo "🔨 Building Docker Images" | |
| echo "=========================" | |
| # Check Docker is available | |
| if ! check_docker; then | |
| echo "❌ Docker is required to build images" | |
| return 1 | |
| fi | |
| echo "🐳 Building Telegram bot image..." | |
| if docker build -f Dockerfile.telegram -t autotrader-telegram:latest .; then | |
| echo "✅ Telegram image built successfully" | |
| else | |
| echo "❌ Failed to build Telegram image" | |
| return 1 | |
| fi | |
| echo "🐳 Building Trader bot image..." | |
| if docker build -f Dockerfile.trader -t autotrader-trader:latest .; then | |
| echo "✅ Trader image built successfully" | |
| else | |
| echo "❌ Failed to build Trader image" | |
| return 1 | |
| fi | |
| echo "✅ All Docker images built successfully!" | |
| echo "" | |
| echo "📋 Built images:" | |
| echo " autotrader-telegram:latest" | |
| echo " autotrader-trader:latest" | |
| } | |
| list_docker_images() { | |
| echo "🐳 Available Docker Images" | |
| echo "==========================" | |
| if ! check_docker; then | |
| echo "❌ Docker is not available" | |
| return 1 | |
| fi | |
| echo "" | |
| echo "📋 All AutoTrader related images:" | |
| docker images | grep -E "(autotrader|ghcr.io/hoangtrung99)" || echo " No AutoTrader images found" | |
| echo "" | |
| echo "🔍 Current configuration:" | |
| detect_and_set_images | |
| echo " TELEGRAM_IMAGE: $TELEGRAM_IMAGE" | |
| echo " TRADER_IMAGE: $TRADER_IMAGE" | |
| echo "" | |
| echo "✅ Image availability check:" | |
| if docker image inspect "$TELEGRAM_IMAGE" &>/dev/null; then | |
| echo " ✅ Telegram image available: $TELEGRAM_IMAGE" | |
| else | |
| echo " ❌ Telegram image missing: $TELEGRAM_IMAGE" | |
| fi | |
| if docker image inspect "$TRADER_IMAGE" &>/dev/null; then | |
| echo " ✅ Trader image available: $TRADER_IMAGE" | |
| else | |
| echo " ❌ Trader image missing: $TRADER_IMAGE" | |
| fi | |
| } | |
| fix_docker_images() { | |
| echo "🔧 Fixing Docker Images" | |
| echo "=======================" | |
| if ! check_docker; then | |
| echo "❌ Docker is not available" | |
| return 1 | |
| fi | |
| echo "" | |
| echo "🧹 Cleaning up potentially conflicting images..." | |
| # Remove old conflicting images | |
| local old_images=("autotrader:latest") | |
| for image in "${old_images[@]}"; do | |
| if docker image inspect "$image" &>/dev/null; then | |
| echo "🗑️ Removing old image: $image" | |
| docker rmi "$image" 2>/dev/null || echo " ⚠️ Could not remove (may be in use)" | |
| fi | |
| done | |
| echo "" | |
| echo "🔄 Re-detecting and ensuring images..." | |
| if ensure_docker_images; then | |
| echo "" | |
| echo "✅ Image fix completed successfully!" | |
| echo "" | |
| echo "📋 Final status:" | |
| list_docker_images | |
| else | |
| echo "" | |
| echo "❌ Image fix failed" | |
| return 1 | |
| fi | |
| } | |
| check_image_updates() { | |
| echo "🔍 Checking for Docker Image Updates" | |
| echo "====================================" | |
| if ! check_docker; then | |
| echo "❌ Docker is not available" | |
| return 1 | |
| fi | |
| local registry_images=( | |
| "ghcr.io/hoangtrung99/autotrader-telegram:latest" | |
| "ghcr.io/hoangtrung99/autotrader-trader:latest" | |
| ) | |
| local updates_available=false | |
| echo "" | |
| for image in "${registry_images[@]}"; do | |
| echo "🔍 Checking: $image" | |
| # Get local image digest if exists | |
| local local_digest="" | |
| if docker image inspect "$image" &>/dev/null; then | |
| local_digest=$(docker image inspect "$image" --format '{{.RepoDigests}}' 2>/dev/null | grep -o 'sha256:[a-f0-9]*' | head -1) | |
| echo " 📦 Local digest: ${local_digest:-not found}" | |
| else | |
| echo " ⚠️ Image not found locally" | |
| fi | |
| # Try to get remote digest (this will also pull latest manifest) | |
| echo " 🌐 Checking remote version..." | |
| if timeout 30 docker manifest inspect "$image" &>/dev/null; then | |
| # Pull latest version to compare | |
| if timeout 60 docker pull "$image" &>/dev/null; then | |
| local new_digest=$(docker image inspect "$image" --format '{{.RepoDigests}}' 2>/dev/null | grep -o 'sha256:[a-f0-9]*' | head -1) | |
| echo " 📦 Remote digest: ${new_digest:-not found}" | |
| if [[ -n "$local_digest" && -n "$new_digest" && "$local_digest" != "$new_digest" ]]; then | |
| echo " 🆕 Update available!" | |
| updates_available=true | |
| elif [[ -z "$local_digest" ]]; then | |
| echo " 🆕 New image downloaded!" | |
| updates_available=true | |
| else | |
| echo " ✅ Up to date" | |
| fi | |
| else | |
| echo " ❌ Failed to check remote version" | |
| fi | |
| else | |
| echo " ❌ Cannot access remote registry" | |
| fi | |
| echo "" | |
| done | |
| if [[ "$updates_available" == "true" ]]; then | |
| echo "🎉 Image updates completed!" | |
| echo "" | |
| echo "📋 Updated images:" | |
| list_docker_images | |
| # Auto-restart containers with updated images | |
| echo "" | |
| echo "🔄 Auto-restarting containers with updated images..." | |
| restart_containers_with_updated_images | |
| else | |
| echo "✅ All images are up to date" | |
| fi | |
| } | |
| restart_containers_with_updated_images() { | |
| echo "🔄 Restarting containers with updated images..." | |
| # Get list of running containers | |
| local running_containers=$(docker ps --format "table {{.Names}}\t{{.Image}}" | tail -n +2) | |
| if [[ -z "$running_containers" ]]; then | |
| echo " ℹ️ No running containers found" | |
| return 0 | |
| fi | |
| echo " 📋 Checking running containers:" | |
| echo "$running_containers" | |
| echo "" | |
| # Check each running container | |
| while IFS=$'\t' read -r container_name container_image; do | |
| if [[ -z "$container_name" || -z "$container_image" ]]; then | |
| continue | |
| fi | |
| # Check if container is using updated images | |
| if [[ "$container_image" == "ghcr.io/hoangtrung99/autotrader-telegram:latest" ]] || | |
| [[ "$container_image" == "ghcr.io/hoangtrung99/autotrader-trader:latest" ]] || | |
| [[ "$container_image" == "autotrader-telegram:latest" ]] || | |
| [[ "$container_image" == "autotrader-trader:latest" ]]; then | |
| echo " 🔄 Restarting container: $container_name (using $container_image)" | |
| # Restart the container | |
| if docker restart "$container_name" &>/dev/null; then | |
| echo " ✅ Successfully restarted: $container_name" | |
| else | |
| echo " ⚠️ Failed to restart: $container_name" | |
| fi | |
| else | |
| echo " ⏭️ Skipping: $container_name (not using autotrader images)" | |
| fi | |
| done <<< "$running_containers" | |
| echo "" | |
| echo "✅ Container restart process completed" | |
| } | |
| setup_environment() { | |
| echo "🔧 AutoTrader Complete Setup" | |
| echo "============================" | |
| # Check and install Docker (Linux only) | |
| if ! command -v docker &> /dev/null; then | |
| if [[ "$OSTYPE" == "linux-gnu"* ]]; then | |
| echo "🐳 Installing Docker..." | |
| curl -fsSL https://get.docker.com -o get-docker.sh | |
| sudo sh get-docker.sh | |
| sudo usermod -aG docker $USER | |
| rm get-docker.sh | |
| echo "✅ Docker installed. Please log out and back in." | |
| else | |
| echo "❌ Please install Docker manually for your OS" | |
| return 1 | |
| fi | |
| fi | |
| # Verify Docker is running | |
| if ! docker info &> /dev/null; then | |
| echo "❌ Docker daemon is not running. Please start Docker." | |
| return 1 | |
| else | |
| echo "✅ Docker is running" | |
| fi | |
| # Build Docker images locally instead of pulling from registry | |
| if check_docker; then | |
| echo "� Building Docker images locally..." | |
| if ! build_docker_images; then | |
| echo "❌ Failed to build Docker images" | |
| return 1 | |
| fi | |
| fi | |
| # Create directories and config files | |
| echo "📁 Creating directories and config files..." | |
| ensure_directories | |
| # Extract template config from Docker image | |
| if [[ ! -f "$CONFIG_DIR/template.json" ]]; then | |
| extract_template_from_image | |
| echo "✅ Created template config: $CONFIG_DIR/template.json" | |
| else | |
| echo "✅ Template config already exists" | |
| fi | |
| # Check Telegram setup | |
| echo "📱 Checking Telegram configuration..." | |
| if [[ -z "$TELEGRAM_BOT_TOKEN" ]]; then | |
| echo "⚠️ Telegram not configured. Set environment variable:" | |
| echo " export TELEGRAM_BOT_TOKEN='your_bot_token'" | |
| else | |
| echo "✅ Telegram configured" | |
| fi | |
| echo "" | |
| echo "🎉 Setup finished!" | |
| echo "" | |
| echo "📋 Next steps:" | |
| echo "1. Configure Telegram (if not done):" | |
| echo " export TELEGRAM_BOT_TOKEN='your_token'" | |
| echo "2. Setup Telegram bot authorization:" | |
| echo " ./bot.sh setup-auth" | |
| echo "3. Start Telegram bot:" | |
| echo " ./bot.sh telegram" | |
| echo "4. Use Telegram commands to manage trading bots" | |
| } | |
| upgrade_script() { | |
| echo "🔄 Upgrading bot.sh from GitHub Gist..." | |
| echo "========================================" | |
| # Check if curl is available | |
| if ! command -v curl &> /dev/null; then | |
| echo "❌ curl is required for upgrade. Please install curl first." | |
| return 1 | |
| fi | |
| local gist_url="${BOT_GIST_URL:-https://gist.githubusercontent.com/hoangtrung99/73593690940ff91015063f2b6f9366a3/raw/autotrader.sh}" | |
| local script_path="$(realpath "${BASH_SOURCE[0]}")" | |
| local backup_file="${script_path}.backup.$(date +%Y%m%d-%H%M%S)" | |
| echo "📄 Current script: $script_path" | |
| echo "💾 Backup will be saved to: $backup_file" | |
| echo "🌐 Gist URL: $gist_url" | |
| # Create backup | |
| if cp "$script_path" "$backup_file"; then | |
| echo "✅ Backup created: $backup_file" | |
| else | |
| echo "❌ Failed to create backup. Aborting upgrade." | |
| return 1 | |
| fi | |
| # Download new version to temporary file | |
| echo "" | |
| echo "📥 Downloading latest version..." | |
| local temp_file=$(mktemp) | |
| if curl -fsSL "$gist_url" -o "$temp_file"; then | |
| echo "✅ Downloaded successfully" | |
| # Show version comparison if possible | |
| local current_version=$(grep "^SCRIPT_VERSION=" "$script_path" | cut -d'"' -f2 2>/dev/null || echo "unknown") | |
| local new_version=$(grep "^SCRIPT_VERSION=" "$temp_file" | cut -d'"' -f2 2>/dev/null || echo "unknown") | |
| echo "" | |
| echo "📊 Version Comparison:" | |
| echo "Current: $current_version" | |
| echo "New: $new_version" | |
| # Confirm upgrade | |
| echo "" | |
| echo "❓ Do you want to proceed with the upgrade? (y/N)" | |
| read -r response | |
| if [[ ! "$response" =~ ^[Yy]$ ]]; then | |
| echo "❌ Upgrade cancelled" | |
| rm -f "$temp_file" | |
| return 0 | |
| fi | |
| # Replace current script with new version | |
| echo "" | |
| echo "🔄 Installing new version..." | |
| if mv "$temp_file" "$script_path"; then | |
| chmod +x "$script_path" | |
| echo "✅ Upgrade completed successfully!" | |
| echo "" | |
| echo "🎉 Upgrade completed!" | |
| echo "========================================" | |
| echo "📄 New version installed: $script_path" | |
| echo "💾 Backup available: $backup_file" | |
| echo "" | |
| echo "🔍 To verify the upgrade worked:" | |
| echo " ./bot.sh version" | |
| echo "" | |
| # Check for Docker image updates if Docker is available | |
| if check_docker &>/dev/null; then | |
| echo "🐳 Checking for Docker image updates..." | |
| echo "" | |
| check_image_updates | |
| else | |
| echo "💡 Docker not available - skipping image updates" | |
| echo " Use './bot.sh update-images' later if needed" | |
| fi | |
| else | |
| echo "❌ Failed to install new version" | |
| echo "🔄 Restoring from backup..." | |
| if cp "$backup_file" "$script_path"; then | |
| echo "✅ Restored from backup" | |
| else | |
| echo "❌ Failed to restore backup!" | |
| fi | |
| return 1 | |
| fi | |
| else | |
| echo "❌ Failed to download new version" | |
| return 1 | |
| fi | |
| } | |
| start_all() { | |
| echo "🚀 Starting Complete AutoTrader System" | |
| echo "======================================" | |
| echo "" | |
| local success=true | |
| # Check Docker availability | |
| if ! check_docker; then | |
| echo "❌ Docker is required for system startup" | |
| return 1 | |
| fi | |
| # Ensure Docker images are available | |
| echo "🔍 Ensuring Docker images are available..." | |
| if ! ensure_docker_images; then | |
| echo "❌ Failed to ensure Docker images" | |
| return 1 | |
| fi | |
| # Start Telegram bot first | |
| echo "📱 Starting Telegram bot..." | |
| if start_telegram_bot; then | |
| echo "✅ Telegram bot started successfully" | |
| else | |
| echo "❌ Failed to start Telegram bot" | |
| success=false | |
| fi | |
| echo "" | |
| echo "📊 System startup completed!" | |
| echo "" | |
| echo "📋 Next steps:" | |
| echo "1. Check system status: ./bot.sh system-status" | |
| echo "2. Use Telegram bot to create trading bots: /createbot" | |
| echo "3. Monitor with: ./bot.sh list" | |
| echo "" | |
| if [[ "$success" == "true" ]]; then | |
| return 0 | |
| else | |
| return 1 | |
| fi | |
| } | |
| stop_all() { | |
| echo "🛑 Stopping All AutoTrader Services" | |
| echo "===================================" | |
| echo "" | |
| local stopped_count=0 | |
| local failed_count=0 | |
| # Check Docker availability | |
| if ! check_docker; then | |
| echo "❌ Docker is not available" | |
| return 1 | |
| fi | |
| # Get all AutoTrader containers | |
| echo "🔍 Finding AutoTrader containers..." | |
| local containers=($(docker ps -a --format "{{.Names}}" | grep -E "(telegram-bot|.*usdt$)" || true)) | |
| if [[ ${#containers[@]} -eq 0 ]]; then | |
| echo "📭 No AutoTrader containers found" | |
| return 0 | |
| fi | |
| echo "📋 Found ${#containers[@]} containers to stop:" | |
| for container in "${containers[@]}"; do | |
| echo " - $container" | |
| done | |
| echo "" | |
| # Stop each container | |
| for container in "${containers[@]}"; do | |
| echo "🛑 Stopping $container..." | |
| if docker stop "$container" &>/dev/null; then | |
| echo "✅ Stopped: $container" | |
| ((stopped_count++)) | |
| else | |
| echo "❌ Failed to stop: $container" | |
| ((failed_count++)) | |
| fi | |
| done | |
| echo "" | |
| echo "📊 Stop Summary:" | |
| echo " ✅ Successfully stopped: $stopped_count" | |
| echo " ❌ Failed to stop: $failed_count" | |
| echo "" | |
| if [[ $failed_count -eq 0 ]]; then | |
| echo "🎉 All services stopped successfully!" | |
| return 0 | |
| else | |
| echo "⚠️ Some services failed to stop" | |
| return 1 | |
| fi | |
| } | |
| system_status() { | |
| echo "📊 AutoTrader System Status" | |
| echo "==========================" | |
| echo "" | |
| local docker_available=false | |
| # Check Docker | |
| echo "🐳 Docker Status:" | |
| if command -v docker &> /dev/null; then | |
| echo " ✅ Docker: Command available" | |
| echo " 📊 Docker version: $(docker --version 2>/dev/null || echo 'Unknown')" | |
| # Check if daemon is running (without hanging) | |
| if docker ps &>/dev/null || false; then | |
| echo " ✅ Docker daemon: Running" | |
| docker_available=true | |
| else | |
| echo " ❌ Docker daemon: Not running" | |
| echo "" | |
| echo "💡 To fix: Start Docker daemon" | |
| fi | |
| else | |
| echo " ❌ Docker: Not installed" | |
| echo "" | |
| echo "💡 To fix: Install Docker with ./bot.sh setup" | |
| fi | |
| echo "" | |
| # Check Docker Images (only if Docker is available) | |
| echo "🖼️ Docker Images Status:" | |
| if [[ "$docker_available" == "true" ]]; then | |
| # Quietly detect images without output | |
| local registry_telegram="ghcr.io/hoangtrung99/autotrader-telegram:latest" | |
| local registry_trader="ghcr.io/hoangtrung99/autotrader-trader:latest" | |
| local local_telegram="autotrader-telegram:latest" | |
| local local_trader="autotrader-trader:latest" | |
| # Check Telegram image | |
| if docker image inspect "$registry_telegram" &>/dev/null; then | |
| echo " ✅ Telegram image: $registry_telegram" | |
| elif docker image inspect "$local_telegram" &>/dev/null; then | |
| echo " ✅ Telegram image: $local_telegram" | |
| else | |
| echo " ❌ Telegram image: Not found" | |
| fi | |
| # Check Trader image | |
| if docker image inspect "$registry_trader" &>/dev/null; then | |
| echo " ✅ Trader image: $registry_trader" | |
| elif docker image inspect "$local_trader" &>/dev/null; then | |
| echo " ✅ Trader image: $local_trader" | |
| else | |
| echo " ❌ Trader image: Not found" | |
| fi | |
| else | |
| echo " ⚠️ Cannot check images (Docker not available)" | |
| fi | |
| echo "" | |
| # Check running containers | |
| echo "📦 Container Status:" | |
| local containers=() | |
| if [[ "$docker_available" == "true" ]]; then | |
| containers=($(docker ps -a --format "{{.Names}}" | grep -E "(telegram-bot|.*usdt$)" || true)) | |
| if [[ ${#containers[@]} -eq 0 ]]; then | |
| echo " 📭 No AutoTrader containers found" | |
| else | |
| local running=0 | |
| local stopped=0 | |
| for container in "${containers[@]}"; do | |
| if docker ps --format "{{.Names}}" | grep -q "^${container}$"; then | |
| echo " 🟢 Running: $container" | |
| ((running++)) | |
| else | |
| echo " 🔴 Stopped: $container" | |
| ((stopped++)) | |
| fi | |
| done | |
| echo "" | |
| echo " 📊 Summary: $running running, $stopped stopped" | |
| fi | |
| else | |
| echo " ⚠️ Cannot check containers (Docker not available)" | |
| fi | |
| echo "" | |
| # Check environment | |
| echo "🔧 Environment Status:" | |
| if [[ -n "$TELEGRAM_BOT_TOKEN" ]]; then | |
| echo " ✅ Telegram token: Configured" | |
| else | |
| echo " ❌ Telegram token: Not configured" | |
| fi | |
| if [[ -n "${BYBIT_API_KEY:-}" ]]; then | |
| echo " ✅ Bybit API: Configured" | |
| else | |
| echo " ⚠️ Bybit API: Not configured (use profiles instead)" | |
| fi | |
| echo "" | |
| # Check credentials | |
| echo "🔑 Credentials Status:" | |
| local creds_count=0 | |
| if [[ -d "$CREDENTIALS_DIR" ]]; then | |
| creds_count=$(find "$CREDENTIALS_DIR" -name "*.json" 2>/dev/null | wc -l || echo "0") | |
| fi | |
| echo " 📊 Credential profiles: $creds_count" | |
| echo "" | |
| # Check configuration | |
| echo "⚙️ Configuration Status:" | |
| local config_count=0 | |
| if [[ -d "$CONFIG_DIR" ]]; then | |
| config_count=$(find "$CONFIG_DIR" -name "*.json" 2>/dev/null | wc -l || echo "0") | |
| fi | |
| echo " 📊 Config files: $config_count" | |
| local data_count=0 | |
| if [[ -d "$DATA_DIR" ]]; then | |
| data_count=$(find "$DATA_DIR" -type f 2>/dev/null | wc -l || echo "0") | |
| fi | |
| echo " 📁 Data directory: $data_count files" | |
| local logs_count=0 | |
| if [[ -d "$LOGS_DIR" ]]; then | |
| logs_count=$(find "$LOGS_DIR" -type f 2>/dev/null | wc -l || echo "0") | |
| fi | |
| echo " 📝 Log directory: $logs_count files" | |
| echo "" | |
| # Overall health check | |
| echo "🏥 Overall Health:" | |
| local health_score=0 | |
| local max_score=5 | |
| check_docker && ((health_score++)) || true | |
| docker image inspect "$TELEGRAM_IMAGE" &>/dev/null && ((health_score++)) || true | |
| [[ -n "$TELEGRAM_BOT_TOKEN" ]] && ((health_score++)) || true | |
| [[ $creds_count -gt 0 ]] && ((health_score++)) || true | |
| [[ ${#containers[@]} -gt 0 ]] && ((health_score++)) || true | |
| local health_percent=$((health_score * 100 / max_score)) | |
| if [[ $health_percent -ge 80 ]]; then | |
| echo " 🟢 System Health: $health_percent% (Excellent)" | |
| elif [[ $health_percent -ge 60 ]]; then | |
| echo " 🟡 System Health: $health_percent% (Good)" | |
| elif [[ $health_percent -ge 40 ]]; then | |
| echo " 🟠 System Health: $health_percent% (Fair)" | |
| else | |
| echo " 🔴 System Health: $health_percent% (Poor)" | |
| fi | |
| echo "" | |
| echo "💡 Quick Actions:" | |
| echo " - Start system: ./bot.sh start-all" | |
| echo " - Stop system: ./bot.sh stop-all" | |
| echo " - List containers: ./bot.sh list" | |
| echo " - Start Telegram bot: ./bot.sh telegram" | |
| } | |
| bind_global_command() { | |
| echo "🔗 Binding bot.sh as global 'traderbot' command..." | |
| echo "========================================" | |
| # Detect OS for different approaches | |
| local os="unknown" | |
| if [[ "$OSTYPE" == "linux-gnu"* ]]; then | |
| os="linux" | |
| elif [[ "$OSTYPE" == "darwin"* ]]; then | |
| os="macos" | |
| fi | |
| local script_path="$(realpath "${BASH_SOURCE[0]}")" | |
| local installed=false | |
| # Try different installation paths | |
| local install_paths=( | |
| "$HOME/.local/bin/traderbot" | |
| "$HOME/bin/traderbot" | |
| "/usr/local/bin/traderbot" | |
| ) | |
| for install_path in "${install_paths[@]}"; do | |
| local install_dir=$(dirname "$install_path") | |
| # Create directory if it doesn't exist | |
| if [[ ! -d "$install_dir" ]]; then | |
| if mkdir -p "$install_dir" 2>/dev/null; then | |
| echo "✅ Created directory: $install_dir" | |
| else | |
| echo "❌ Cannot create directory: $install_dir" | |
| continue | |
| fi | |
| fi | |
| # Try to install | |
| if cp "$script_path" "$install_path" 2>/dev/null; then | |
| chmod +x "$install_path" | |
| echo "✅ Installed to: $install_path" | |
| # Add to PATH if needed | |
| if [[ ":$PATH:" != *":$install_dir:"* ]]; then | |
| echo "💡 Adding $install_dir to PATH..." | |
| # Determine shell profile | |
| local shell_profile="" | |
| if [[ -n "$ZSH_VERSION" ]]; then | |
| shell_profile="$HOME/.zshrc" | |
| elif [[ -n "$BASH_VERSION" ]]; then | |
| shell_profile="$HOME/.bashrc" | |
| fi | |
| if [[ -n "$shell_profile" ]]; then | |
| echo "export PATH=\"$install_dir:\$PATH\"" >> "$shell_profile" | |
| echo "✅ Added to $shell_profile" | |
| echo "💡 Run: source $shell_profile" | |
| fi | |
| fi | |
| installed=true | |
| break | |
| else | |
| echo "❌ Failed to install to: $install_path" | |
| fi | |
| done | |
| if [[ "$installed" == "true" ]]; then | |
| echo "" | |
| echo "🎉 Global 'traderbot' command installed!" | |
| echo "========================================" | |
| echo "" | |
| echo "📋 Usage Examples:" | |
| echo " traderbot setup # Setup environment" | |
| echo " traderbot start eth --amount 100 # Start ETH bot" | |
| echo " traderbot list # List containers" | |
| echo " traderbot telegram # Start Telegram bot" | |
| echo "" | |
| echo "💡 You may need to restart your terminal or run:" | |
| echo " source ~/.bashrc # or ~/.zshrc" | |
| else | |
| echo "" | |
| echo "❌ Failed to install global command" | |
| echo "💡 Manual installation:" | |
| echo " sudo cp $script_path /usr/local/bin/traderbot" | |
| echo " sudo chmod +x /usr/local/bin/traderbot" | |
| fi | |
| } | |
| unbind_global_command() { | |
| echo "🗑️ Removing 'traderbot' global command..." | |
| echo "========================================" | |
| # List of possible installation paths | |
| local remove_paths=( | |
| "/usr/local/bin/traderbot" | |
| "$HOME/.local/bin/traderbot" | |
| "$HOME/bin/traderbot" | |
| ) | |
| local removed=false | |
| for remove_path in "${remove_paths[@]}"; do | |
| if [[ -f "$remove_path" ]]; then | |
| if rm "$remove_path" 2>/dev/null; then | |
| echo "✅ Removed: $remove_path" | |
| removed=true | |
| else | |
| echo "❌ Failed to remove: $remove_path (try with sudo)" | |
| fi | |
| fi | |
| done | |
| if [[ "$removed" == "true" ]]; then | |
| echo "" | |
| echo "✅ Global 'traderbot' command removed" | |
| echo "💡 You can still use: ./bot.sh" | |
| else | |
| echo "" | |
| echo "ℹ️ No global 'traderbot' command found" | |
| fi | |
| } | |
| # =============================== | |
| # Docker Operations | |
| # =============================== | |
| start_telegram_bot() { | |
| echo "📱 Starting Telegram Bot" | |
| echo "========================" | |
| # Check Docker | |
| if ! check_docker; then | |
| print_warning "Docker không có sẵn, đang tìm phương án thay thế..." | |
| suggest_local_runner | |
| # Try to run with local runner | |
| if [[ -f "./run_local.sh" ]]; then | |
| print_step "Đang chạy với local runner..." | |
| exec ./run_local.sh telegram | |
| else | |
| print_error "Local runner không tìm thấy" | |
| echo "" | |
| echo "💡 Cách khắc phục:" | |
| echo " - Cài đặt Docker: ./bot.sh setup" | |
| echo " - Hoặc tạo file run_local.sh để chạy local" | |
| return 1 | |
| fi | |
| fi | |
| # Ensure Docker images are available | |
| print_step "Đang kiểm tra Docker images..." | |
| if ! ensure_docker_images; then | |
| print_error "Không thể đảm bảo Docker images có sẵn" | |
| echo "" | |
| echo "💡 Cách khắc phục:" | |
| echo " - Build images: ./bot.sh build" | |
| echo " - Pull images: ./bot.sh update-images" | |
| echo " - Fix images: ./bot.sh fix-images" | |
| return 1 | |
| fi | |
| # Check authorization setup | |
| echo "🔐 Checking Telegram authorization setup..." | |
| if ! check_telegram_auth_setup; then | |
| echo "❌ Cannot start bot without proper authorization setup" | |
| return 1 | |
| fi | |
| echo "" | |
| # Check environment | |
| if [[ -z "$TELEGRAM_BOT_TOKEN" ]]; then | |
| echo "❌ Missing Telegram credentials" | |
| echo "" | |
| echo "💡 Set environment variable:" | |
| echo " export TELEGRAM_BOT_TOKEN='your_bot_token'" | |
| return 1 | |
| fi | |
| # Check if container already exists | |
| if docker ps -a --format "{{.Names}}" | grep -q "^telegram-bot$"; then | |
| echo "🔄 Stopping existing Telegram bot container..." | |
| docker stop telegram-bot 2>/dev/null || true | |
| docker rm telegram-bot 2>/dev/null || true | |
| fi | |
| # Start Telegram bot container | |
| echo "🐳 Starting Telegram bot container..." | |
| # Ensure directories exist | |
| ensure_directories | |
| # Convert relative paths to absolute paths to avoid Docker volume mounting issues | |
| local abs_config_dir="$(cd "$CONFIG_DIR" && pwd)" | |
| local abs_data_dir="$(cd "$DATA_DIR" && pwd)" | |
| local abs_logs_dir="$(cd "$LOGS_DIR" && pwd)" | |
| local abs_autotrader_dir="$AUTOTRADER_DIR" | |
| echo "📁 Volume mounts:" | |
| echo " Config: $abs_config_dir -> /app/configs" | |
| echo " Data: $abs_data_dir -> /app/data" | |
| echo " Logs: $abs_logs_dir -> /app/logs" | |
| echo " AutoTrader: $abs_autotrader_dir -> /root/.autotrader" | |
| docker run -d \ | |
| --name telegram-bot \ | |
| --restart unless-stopped \ | |
| -e TELEGRAM_BOT_TOKEN="$TELEGRAM_BOT_TOKEN" \ | |
| -e RUNNING_IN_CONTAINER="true" \ | |
| -e HOST_CONFIG_DIR="$abs_config_dir" \ | |
| -e HOST_DATA_DIR="$abs_data_dir" \ | |
| -e HOST_LOGS_DIR="$abs_logs_dir" \ | |
| -v "$abs_config_dir:/app/configs" \ | |
| -v "$abs_data_dir:/app/data" \ | |
| -v "$abs_logs_dir:/app/logs" \ | |
| -v "$abs_autotrader_dir:/root/.autotrader" \ | |
| -v /var/run/docker.sock:/var/run/docker.sock \ | |
| "$TELEGRAM_IMAGE" | |
| if [[ $? -eq 0 ]]; then | |
| echo "✅ Telegram bot started successfully!" | |
| echo "📊 Container: telegram-bot" | |
| echo "🔗 Token: ${TELEGRAM_BOT_TOKEN:0:10}..." | |
| echo "" | |
| echo "📋 Monitor with:" | |
| echo " docker logs telegram-bot" | |
| echo " ./bot.sh simple-logs telegram-bot" | |
| else | |
| echo "❌ Failed to start Telegram bot container" | |
| return 1 | |
| fi | |
| } | |
| start_trading_bot() { | |
| local symbol="$1" | |
| shift | |
| echo "🤖 Starting Trading Bot: $symbol" | |
| echo "================================" | |
| # Validate symbol | |
| if [[ -z "$symbol" ]]; then | |
| echo "❌ Symbol is required" | |
| echo "Usage: ./bot.sh start <symbol> [options]" | |
| return 1 | |
| fi | |
| # Parse additional options first to get profile | |
| local amount="50" | |
| local dca_amount="25" # Default DCA amount (50% of amount) | |
| local test_mode="false" | |
| local direction="LONG" | |
| local profile="" | |
| local cmd_api_key="" | |
| local cmd_api_secret="" | |
| while [[ $# -gt 0 ]]; do | |
| case $1 in | |
| --amount) | |
| amount="$2" | |
| shift 2 | |
| ;; | |
| --dca-amount) | |
| dca_amount="$2" | |
| shift 2 | |
| ;; | |
| --test-mode|--test) | |
| test_mode="true" | |
| shift | |
| ;; | |
| --live-mode|--live) | |
| test_mode="false" | |
| shift | |
| ;; | |
| --direction) | |
| direction="$2" | |
| shift 2 | |
| ;; | |
| --profile) | |
| profile="$2" | |
| shift 2 | |
| ;; | |
| --api-key) | |
| cmd_api_key="$2" | |
| shift 2 | |
| ;; | |
| --api-secret) | |
| cmd_api_secret="$2" | |
| shift 2 | |
| ;; | |
| *) | |
| echo "⚠️ Unknown option: $1" | |
| shift | |
| ;; | |
| esac | |
| done | |
| # Normalize symbol and generate container name with profile | |
| local full_symbol=$(normalize_symbol "$symbol") | |
| local container_name=$(get_container_name "$symbol" "$profile") | |
| # Check if container already exists and cleanup | |
| if docker ps -a --format "{{.Names}}" | grep -q "^${container_name}$"; then | |
| echo "🔄 Stopping existing container '$container_name'..." | |
| docker stop "$container_name" 2>/dev/null || true | |
| echo "�️ Removing existing container '$container_name'..." | |
| docker rm "$container_name" 2>/dev/null || true | |
| echo "✅ Container '$container_name' cleaned up successfully" | |
| fi | |
| # Create symbol-specific config | |
| local config_file="$CONFIG_DIR/${container_name}.json" | |
| if [[ ! -f "$config_file" ]]; then | |
| echo "📝 Creating config for $symbol..." | |
| # Create config from template (escape special characters for sed) | |
| local escaped_symbol=$(echo "$full_symbol" | sed 's/[\/&]/\\&/g') | |
| sed "s/SYMBOL_PLACEHOLDER/$escaped_symbol/g" "$CONFIG_DIR/template.json" > "$config_file" | |
| echo "✅ Created config: $config_file" | |
| fi | |
| # Update config file with amount and dca_amount | |
| echo "📝 Updating config with amount=$amount, dca_amount=$dca_amount..." | |
| if [[ -f "$config_file" ]]; then | |
| # Use Python to update JSON config safely | |
| python3 -c " | |
| import json | |
| import sys | |
| try: | |
| with open('$config_file', 'r') as f: | |
| config = json.load(f) | |
| # Update amounts | |
| config['amount'] = float('$amount') | |
| config['dca_amount'] = float('$dca_amount') | |
| with open('$config_file', 'w') as f: | |
| json.dump(config, f, indent=2) | |
| print('✅ Config updated successfully') | |
| except Exception as e: | |
| print(f'❌ Failed to update config: {e}') | |
| sys.exit(1) | |
| " | |
| if [[ $? -ne 0 ]]; then | |
| echo "❌ Failed to update config file" | |
| return 1 | |
| fi | |
| fi | |
| # Resolve credentials using priority system | |
| if ! resolve_credentials "$profile" "$cmd_api_key" "$cmd_api_secret"; then | |
| echo "" | |
| echo "💡 Available credential sources (in priority order):" | |
| echo " 1. Profile: --profile <name> (highest priority)" | |
| echo " 2. Command line: --api-key <key> --api-secret <secret>" | |
| echo " 3. Environment: BYBIT_API_KEY, BYBIT_API_SECRET/BYBIT_SECRET_KEY" | |
| echo "" | |
| echo "📋 Examples:" | |
| echo " ./bot.sh start btc --profile main --amount 100" | |
| echo " ./bot.sh start btc --api-key 'key' --api-secret 'secret'" | |
| echo " export BYBIT_API_KEY='key' && ./bot.sh start btc" | |
| echo "" | |
| echo "💡 Manage profiles:" | |
| echo " python3 src/cli/credentials_cli.py list" | |
| echo " python3 src/cli/credentials_cli.py store <profile>" | |
| return 1 | |
| fi | |
| # Verify credentials are now available | |
| local api_key="${!BYBIT_API_KEY_VAR:-}" | |
| local api_secret="${!BYBIT_API_SECRET_VAR:-}" | |
| if [[ -z "$api_key" ]] || [[ -z "$api_secret" ]]; then | |
| echo "❌ Credential resolution failed" | |
| return 1 | |
| fi | |
| # Check Docker is available | |
| if ! check_docker; then | |
| echo "❌ Docker is required to run trading bots" | |
| return 1 | |
| fi | |
| # Ensure Docker images are available | |
| echo "🔍 Ensuring Docker images are available..." | |
| if ! ensure_docker_images; then | |
| echo "❌ Failed to ensure Docker images are available" | |
| return 1 | |
| fi | |
| # Start Docker container | |
| echo "🐳 Starting Docker container..." | |
| # Handle different execution contexts | |
| if [[ "${RUNNING_IN_CONTAINER:-}" == "true" ]]; then | |
| echo "🐳 Running in container - using host mount paths from environment" | |
| echo "🔍 DEBUG: RUNNING_IN_CONTAINER='${RUNNING_IN_CONTAINER:-}'" | |
| echo "🔍 DEBUG: HOST_CONFIG_DIR='${HOST_CONFIG_DIR:-}'" | |
| echo "🔍 DEBUG: HOST_DATA_DIR='${HOST_DATA_DIR:-}'" | |
| echo "🔍 DEBUG: HOST_LOGS_DIR='${HOST_LOGS_DIR:-}'" | |
| # When running in Telegram bot container, use the host paths that were mounted | |
| # These MUST be the actual host paths, not container paths | |
| local abs_config_dir="${HOST_CONFIG_DIR}" | |
| local abs_data_dir="${HOST_DATA_DIR}" | |
| local abs_logs_dir="${HOST_LOGS_DIR}" | |
| echo "🔍 DEBUG: abs_config_dir='$abs_config_dir'" | |
| echo "🔍 DEBUG: abs_data_dir='$abs_data_dir'" | |
| echo "🔍 DEBUG: abs_logs_dir='$abs_logs_dir'" | |
| # Validate that host paths are available and not empty | |
| if [[ -z "$abs_config_dir" || -z "$abs_data_dir" || -z "$abs_logs_dir" ]]; then | |
| echo "❌ ERROR: Host paths not available in container environment" | |
| echo " HOST_CONFIG_DIR: '$HOST_CONFIG_DIR'" | |
| echo " HOST_DATA_DIR: '$HOST_DATA_DIR'" | |
| echo " HOST_LOGS_DIR: '$HOST_LOGS_DIR'" | |
| echo "💡 This indicates a problem with Telegram bot container setup" | |
| return 1 | |
| fi | |
| echo "✅ Using host paths from environment variables" | |
| else | |
| echo "💻 Running on host - using local absolute paths" | |
| # Convert relative paths to absolute paths to avoid Docker volume mounting issues | |
| local abs_config_dir="$(cd "$CONFIG_DIR" && pwd)" | |
| local abs_data_dir="$(cd "$DATA_DIR" && pwd)" | |
| local abs_logs_dir="$(cd "$LOGS_DIR" && pwd)" | |
| fi | |
| echo "📁 Volume mounts:" | |
| echo " Config: $abs_config_dir -> /app/configs" | |
| echo " Data: $abs_data_dir -> /app/data" | |
| echo " Logs: $abs_logs_dir -> /app/logs" | |
| # Prepare Docker command arguments | |
| local docker_args=( | |
| "run" "-d" | |
| "--name" "$container_name" | |
| "--restart" "unless-stopped" | |
| "-e" "$BYBIT_API_KEY_VAR=$api_key" | |
| "-e" "$BYBIT_API_SECRET_VAR=$api_secret" | |
| "-e" "BOT_CONFIG_FILE=configs/${container_name}.json" | |
| "-e" "TRADE_SYMBOL=$full_symbol" | |
| "-e" "TRADE_AMOUNT=$amount" | |
| "-e" "TRADE_DIRECTION=$direction" | |
| "-e" "TEST_MODE=$test_mode" | |
| "-v" "$abs_config_dir:/app/configs" | |
| "-v" "$abs_data_dir:/app/data" | |
| "-v" "$abs_logs_dir:/app/logs" | |
| "$TRADER_IMAGE" | |
| "python" "main.py" "--start" | |
| ) | |
| # Add test flag if in test mode | |
| if [[ "$test_mode" == "true" ]]; then | |
| docker_args+=("--test") | |
| fi | |
| # Run Docker container | |
| docker "${docker_args[@]}" | |
| if [[ $? -eq 0 ]]; then | |
| echo "✅ Trading bot started successfully!" | |
| echo "📊 Container: $container_name" | |
| echo "💰 Symbol: $full_symbol" | |
| echo "💵 Amount: $amount USDT" | |
| echo "🧪 Test Mode: $test_mode" | |
| echo "" | |
| echo "📋 Monitor with:" | |
| echo " ./bot.sh logs $container_name" | |
| echo " python3 src/cli/autotrader_cli.py status $container_name" | |
| else | |
| echo "❌ Failed to start trading bot" | |
| return 1 | |
| fi | |
| } | |
| simple_logs() { | |
| local container_name="$1" | |
| local lines="${2:-50}" | |
| if [[ -z "$container_name" ]]; then | |
| echo "❌ Container name is required" | |
| return 1 | |
| fi | |
| echo "📋 Logs for container: $container_name (last $lines lines)" | |
| echo "=" * 60 | |
| if docker logs "$container_name" --tail "$lines" 2>/dev/null; then | |
| echo "" | |
| echo "✅ Logs retrieved successfully" | |
| else | |
| echo "❌ Failed to get logs for container: $container_name" | |
| echo "💡 Available containers:" | |
| docker ps --format "{{.Names}}" | head -5 | |
| return 1 | |
| fi | |
| } | |
| # =============================== | |
| # Credential Management Functions | |
| # =============================== | |
| check_telegram_profile() { | |
| # Check if Telegram bot has set a profile for this session | |
| local telegram_profile_file="/tmp/traderbot_telegram_profile_$$" | |
| local telegram_profile_global="/tmp/traderbot_telegram_profile" | |
| if [[ -f "$telegram_profile_file" ]]; then | |
| cat "$telegram_profile_file" | |
| return 0 | |
| elif [[ -f "$telegram_profile_global" ]]; then | |
| cat "$telegram_profile_global" | |
| return 0 | |
| fi | |
| return 1 | |
| } | |
| load_profile_credentials() { | |
| local profile="$1" | |
| if [[ -z "$profile" ]]; then | |
| return 1 | |
| fi | |
| echo "🔄 Loading credentials from profile: $profile" | |
| # Use centralized credentials directory | |
| local creds_dir="$CREDENTIALS_DIR" | |
| # Try Python CLI first (JSON format) | |
| local json_file="$creds_dir/${profile}.json" | |
| if [[ -f "$json_file" ]]; then | |
| # Load from JSON format (Python CLI) - get export commands | |
| if command -v python3 &> /dev/null; then | |
| local result=$(python3 src/cli/credentials_cli.py load "$profile" 2>/dev/null) | |
| if [[ $? -eq 0 ]]; then | |
| # Parse the export commands | |
| local api_key=$(echo "$result" | grep "export $BYBIT_API_KEY_VAR=" | cut -d"'" -f2) | |
| local api_secret=$(echo "$result" | grep "export $BYBIT_API_SECRET_VAR=" | cut -d"'" -f2) | |
| if [[ -n "$api_key" ]] && [[ -n "$api_secret" ]]; then | |
| export "$BYBIT_API_KEY_VAR"="$api_key" | |
| export "$BYBIT_API_SECRET_VAR"="$api_secret" | |
| echo "✅ Loaded credentials from profile: $profile" | |
| return 0 | |
| fi | |
| fi | |
| fi | |
| fi | |
| # Try legacy .env format (for backward compatibility) | |
| local env_file="$creds_dir/${profile}.env" | |
| if [[ -f "$env_file" ]]; then | |
| echo "🔄 Loading from .env format..." | |
| source "$env_file" | |
| if [[ -n "${!BYBIT_API_KEY_VAR}" ]] && [[ -n "${!BYBIT_API_SECRET_VAR}" ]]; then | |
| echo "✅ Loaded credentials from profile: $profile" | |
| return 0 | |
| fi | |
| fi | |
| echo "❌ Failed to load credentials from profile: $profile" | |
| return 1 | |
| } | |
| resolve_credentials() { | |
| local profile="$1" | |
| local cmd_api_key="$2" | |
| local cmd_api_secret="$3" | |
| echo "🔍 Resolving credentials with priority system..." | |
| # Priority 1: Profile credentials (from Telegram bot selection or command line) | |
| # Check Telegram profile first if no explicit profile provided | |
| if [[ -z "$profile" ]]; then | |
| local telegram_profile=$(check_telegram_profile 2>/dev/null) | |
| if [[ -n "$telegram_profile" ]]; then | |
| echo "🥇 Priority 1a: Found Telegram selected profile '$telegram_profile'" | |
| profile="$telegram_profile" | |
| fi | |
| fi | |
| if [[ -n "$profile" ]]; then | |
| echo "🥇 Priority 1b: Loading from profile '$profile'" | |
| if load_profile_credentials "$profile"; then | |
| return 0 | |
| else | |
| echo "⚠️ Failed to load profile '$profile', trying next priority..." | |
| fi | |
| fi | |
| # Priority 2: Command line arguments | |
| if [[ -n "$cmd_api_key" ]] && [[ -n "$cmd_api_secret" ]]; then | |
| echo "🥈 Priority 2: Using command line credentials" | |
| export "$BYBIT_API_KEY_VAR"="$cmd_api_key" | |
| export "$BYBIT_API_SECRET_VAR"="$cmd_api_secret" | |
| echo "✅ Loaded credentials from command line" | |
| return 0 | |
| fi | |
| # Priority 3: Environment variables | |
| local env_api_key="${!BYBIT_API_KEY_VAR:-}" | |
| local env_api_secret="${!BYBIT_API_SECRET_VAR:-${!BYBIT_SECRET_KEY_VAR:-}}" | |
| if [[ -n "$env_api_key" ]] && [[ -n "$env_api_secret" ]]; then | |
| echo "🥉 Priority 3: Using environment variables" | |
| export "$BYBIT_API_KEY_VAR"="$env_api_key" | |
| export "$BYBIT_API_SECRET_VAR"="$env_api_secret" | |
| echo "✅ Loaded credentials from environment" | |
| return 0 | |
| fi | |
| # No credentials found | |
| echo "❌ No credentials found in any source" | |
| return 1 | |
| } | |
| show_help() { | |
| cat << EOF | |
| 🤖 AutoTrader Bot - Compact Server Deployment Script | |
| USAGE: $0 <command> [options] | |
| � DEVELOPMENT MODE: | |
| export LOCAL=true && $0 <command> Use local Docker images for development | |
| Examples: | |
| export LOCAL=true && $0 telegram # Use local autotrader-telegram:latest | |
| export LOCAL=true && $0 start btc # Use local autotrader-trader:latest | |
| �📋 DEPLOYMENT COMMANDS: | |
| setup Complete environment setup (creates configs, directories) | |
| build Build Docker images locally | |
| images List available Docker images and check configuration | |
| fix-images Fix Docker image conflicts and issues | |
| update-images Check and update Docker images from registry | |
| upgrade Upgrade script from GitHub Gist | |
| bind Install as global 'traderbot' command | |
| unbind Remove global 'traderbot' command | |
| start-all Start complete system | |
| stop-all Stop all services | |
| system-status Show system status | |
| 📱 TELEGRAM BOT: | |
| telegram Start Telegram bot (curl-based, minimal dependencies) | |
| setup-auth Setup Telegram bot authorization (interactive wizard) | |
| config-auth View/manage Telegram bot authorization config | |
| 🚀 TRADING BOTS: | |
| start <symbol> [opts] Create trading bot | |
| Options: | |
| --amount <amount> Trading amount (default: 50) | |
| --test Enable test mode | |
| --live Enable live mode (default) | |
| --profile <name> Use credential profile (highest priority) | |
| --api-key <key> API key (medium priority) | |
| --api-secret <secret> API secret (medium priority) | |
| --direction <dir> Trading direction (LONG/SHORT) | |
| 📊 BOT MANAGEMENT (Multi-Profile Support): | |
| Docker CLI (Smart Detection): | |
| ./bot.sh list # List all bots grouped by profile | |
| ./bot.sh status <symbol|container> # Smart detection or specific container | |
| ./bot.sh logs <symbol|container> [lines] # Smart detection or specific container | |
| ./bot.sh stop <symbol|container> # Smart detection or specific container | |
| ./bot.sh restart <symbol|container> # Smart detection or specific container | |
| ./bot.sh remove <symbol|container> # Smart detection or specific container | |
| Telegram Commands (Smart Detection): | |
| /list, /status, /logs, /stop, /restart, /remove | |
| Multi-Profile Examples: | |
| ./bot.sh logs btc # Shows options if multiple BTC bots | |
| ./bot.sh logs main-btc # Specific container logs | |
| ./bot.sh stop test-eth # Stop specific profile's ETH bot | |
| 🔑 CREDENTIALS (Use Docker CLI): | |
| ./bot.sh list-credentials | |
| ./bot.sh store-credentials <profile> <api_key> <api_secret> [display_name] | |
| ./bot.sh load-credentials <profile> | |
| ./bot.sh assets <profile> # View account assets for profile | |
| EXAMPLES: | |
| # First time setup | |
| $0 setup # Complete environment setup (pulls images, extracts template) | |
| $0 setup-auth # Setup Telegram bot authorization | |
| $0 bind # Install as 'traderbot' command (optional) | |
| # Multi-Profile Trading Examples | |
| $0 start eth --profile main --amount 100 # Creates main-ethusdt container | |
| $0 start btc --profile test --amount 50 --test # Creates test-btcusdt container | |
| $0 start eth --profile prod --amount 200 # Creates prod-ethusdt container | |
| # Management Examples (Smart Detection) | |
| $0 logs eth # Shows options if multiple ETH bots exist | |
| $0 logs main-eth # Direct access to main profile's ETH bot | |
| $0 stop test-btc # Stop specific profile's BTC bot | |
| # Credential Priority (highest to lowest) | |
| $0 start btc --profile main --amount 100 # Use 'main' profile (highest) | |
| $0 start btc --api-key 'key' --api-secret 'sec' # Use command line credentials | |
| $0 start btc --amount 50 # Use environment variables (lowest) | |
| # System management | |
| $0 start-all # Start complete system | |
| $0 telegram # Start Telegram bot | |
| $0 system-status # Check system status | |
| # Global command usage (after bind) | |
| traderbot start eth --amount 100 | |
| traderbot list | |
| traderbot telegram | |
| EOF | |
| } | |
| # =============================== | |
| # Telegram Auth Setup Functions | |
| # =============================== | |
| check_telegram_auth_setup() { | |
| # Check if Telegram authorization is properly configured | |
| local auth_config="$AUTOTRADER_DIR/telegram_auth.json" | |
| # Check if auth config file exists | |
| if [[ ! -f "$auth_config" ]]; then | |
| echo "❌ Telegram bot authorization chưa được setup!" | |
| echo "" | |
| echo "🔐 Bạn cần setup authorization trước khi khởi động bot:" | |
| echo " ./bot.sh setup-auth" | |
| echo "" | |
| echo "💡 Hoặc chạy lệnh sau để setup ngay:" | |
| echo "" | |
| read -p "Bạn có muốn setup authorization ngay bây giờ? (y/N): " setup_now | |
| if [[ "$setup_now" =~ ^[Yy]$ ]]; then | |
| echo "" | |
| setup_telegram_auth | |
| return $? | |
| else | |
| echo "" | |
| echo "⚠️ Bot không thể khởi động mà không có authorization setup." | |
| echo " Chạy './bot.sh setup-auth' trước khi khởi động bot." | |
| return 1 | |
| fi | |
| fi | |
| # Validate auth config structure | |
| if ! python3 -c " | |
| import json | |
| import sys | |
| try: | |
| with open('$auth_config', 'r') as f: | |
| config = json.load(f) | |
| # Check required structure | |
| if 'authorized_users' not in config: | |
| print('❌ Config thiếu authorized_users section') | |
| sys.exit(1) | |
| if 'settings' not in config: | |
| print('❌ Config thiếu settings section') | |
| sys.exit(1) | |
| settings = config['settings'] | |
| if 'creator_username' not in settings: | |
| print('❌ Config thiếu creator_username setting') | |
| sys.exit(1) | |
| print('✅ Authorization config hợp lệ') | |
| except json.JSONDecodeError: | |
| print('❌ Config file không phải JSON hợp lệ') | |
| sys.exit(1) | |
| except Exception as e: | |
| print(f'❌ Lỗi đọc config: {e}') | |
| sys.exit(1) | |
| " 2>/dev/null; then | |
| echo "❌ Authorization config file bị lỗi!" | |
| echo "" | |
| echo "💡 Chạy lệnh sau để reset config:" | |
| echo " ./bot.sh setup-auth" | |
| echo "" | |
| read -p "Bạn có muốn reset authorization config? (y/N): " reset_config | |
| if [[ "$reset_config" =~ ^[Yy]$ ]]; then | |
| echo "" | |
| setup_telegram_auth | |
| return $? | |
| else | |
| return 1 | |
| fi | |
| fi | |
| echo "✅ Telegram authorization đã được setup" | |
| return 0 | |
| } | |
| setup_telegram_auth() { | |
| echo "🔐 Telegram Bot Authorization Setup" | |
| echo "==================================" | |
| echo "" | |
| # Ensure .autotrader directory exists | |
| ensure_directories | |
| local auth_config="$AUTOTRADER_DIR/telegram_auth.json" | |
| echo "This wizard will help you set up Telegram bot authorization." | |
| echo "You'll need to provide a super admin user (yourself)." | |
| echo "" | |
| # Get super admin input | |
| local super_admin_input="" | |
| local super_admin_username="" | |
| local super_admin_id="" | |
| while [[ -z "$super_admin_input" ]]; do | |
| echo "👑 Enter super admin (username or user ID):" | |
| echo " Examples: hoangtrungdev, @hoangtrungdev, or 1631630468" | |
| read -p "Super admin: " super_admin_input | |
| if [[ -z "$super_admin_input" ]]; then | |
| echo "❌ Super admin cannot be empty. Please try again." | |
| echo "" | |
| fi | |
| done | |
| # Parse input - detect if it's username or user ID | |
| if [[ "$super_admin_input" =~ ^[0-9]+$ ]]; then | |
| # It's a user ID | |
| super_admin_id="$super_admin_input" | |
| echo "📝 Enter username for user ID $super_admin_id (optional):" | |
| read -p "Username: " super_admin_username | |
| if [[ -z "$super_admin_username" ]]; then | |
| super_admin_username="user_$super_admin_id" | |
| fi | |
| else | |
| # It's a username - clean it up | |
| super_admin_username="${super_admin_input#@}" # Remove @ if present | |
| echo "📝 Enter user ID for @$super_admin_username (optional, leave empty for auto-detection):" | |
| read -p "User ID: " super_admin_id | |
| fi | |
| # Create auth config | |
| echo "" | |
| echo "🔧 Creating authorization config..." | |
| local config_content='{ | |
| "authorized_users": {}' | |
| # Add super admin if we have user ID | |
| if [[ -n "$super_admin_id" ]]; then | |
| config_content='{ | |
| "authorized_users": { | |
| "'$super_admin_id'": { | |
| "username": "'$super_admin_username'", | |
| "role": "SUPER_ADMIN", | |
| "added_by": "setup_wizard", | |
| "added_at": "'$(date -u +"%Y-%m-%dT%H:%M:%S")'.000Z" | |
| } | |
| }' | |
| fi | |
| config_content="$config_content, | |
| \"settings\": { | |
| \"default_rejection_message\": \"❌ Bạn không có quyền sử dụng bot này. Liên hệ @$super_admin_username để được cấp quyền.\", | |
| \"super_admin_only_commands\": [ | |
| \"/adduser\", | |
| \"/removeuser\", | |
| \"/listusers\" | |
| ], | |
| \"creator_username\": \"$super_admin_username\", | |
| \"audit_log\": true, | |
| \"strict_mode\": true, | |
| \"auto_promote_creator\": true | |
| } | |
| }" | |
| # Write config file | |
| echo "$config_content" > "$auth_config" | |
| chmod 600 "$auth_config" | |
| echo "✅ Authorization config created: $auth_config" | |
| echo "" | |
| echo "📋 Configuration Summary:" | |
| echo " Super Admin: @$super_admin_username" | |
| if [[ -n "$super_admin_id" ]]; then | |
| echo " User ID: $super_admin_id" | |
| else | |
| echo " User ID: Auto-detect on first use" | |
| fi | |
| echo " Config File: $auth_config" | |
| echo "" | |
| echo "🎯 Next Steps:" | |
| echo " 1. Start your Telegram bot: ./bot.sh telegram" | |
| echo " 2. Send /start to your bot to auto-promote yourself" | |
| echo " 3. Use /adduser to add other users" | |
| echo "" | |
| } | |
| config_telegram_auth() { | |
| echo "⚙️ Telegram Bot Authorization Config" | |
| echo "====================================" | |
| echo "" | |
| local auth_config="$AUTOTRADER_DIR/telegram_auth.json" | |
| if [[ ! -f "$auth_config" ]]; then | |
| echo "❌ Authorization config not found: $auth_config" | |
| echo "💡 Run './bot.sh setup-auth' first to create the config" | |
| return 1 | |
| fi | |
| echo "📋 Current Configuration:" | |
| echo "========================" | |
| # Display current config in a readable format | |
| if command -v python3 &> /dev/null; then | |
| python3 -c " | |
| import json | |
| import sys | |
| try: | |
| with open('$auth_config', 'r') as f: | |
| config = json.load(f) | |
| print('👑 Super Admin Settings:') | |
| settings = config.get('settings', {}) | |
| creator = settings.get('creator_username', 'Not set') | |
| print(f' Creator: @{creator}') | |
| print(f' Auto-promote: {settings.get(\"auto_promote_creator\", False)}') | |
| print(f' Strict mode: {settings.get(\"strict_mode\", False)}') | |
| print(f' Audit log: {settings.get(\"audit_log\", False)}') | |
| print() | |
| print('👥 Authorized Users:') | |
| users = config.get('authorized_users', {}) | |
| if not users: | |
| print(' No users configured') | |
| else: | |
| for user_id, user_info in users.items(): | |
| username = user_info.get('username', 'Unknown') | |
| role = user_info.get('role', 'USER') | |
| added_by = user_info.get('added_by', 'Unknown') | |
| print(f' @{username} ({user_id}) - {role} (added by {added_by})') | |
| print() | |
| print('🚫 Restricted Commands:') | |
| restricted = settings.get('super_admin_only_commands', []) | |
| for cmd in restricted: | |
| print(f' {cmd}') | |
| except Exception as e: | |
| print(f'❌ Error reading config: {e}') | |
| sys.exit(1) | |
| " | |
| else | |
| echo "⚠️ Python3 not available - showing raw config:" | |
| cat "$auth_config" | |
| fi | |
| echo "" | |
| echo "🔧 Available Actions:" | |
| echo " 1. Edit config file manually: $auth_config" | |
| echo " 2. Reset config: ./bot.sh setup-auth" | |
| echo " 3. Manage users via Telegram bot commands" | |
| echo "" | |
| } | |
| # =============================== | |
| # Main Command Router | |
| # =============================== | |
| main() { | |
| case "${1:-help}" in | |
| # Deployment commands | |
| setup) setup_environment ;; | |
| build) build_docker_images ;; | |
| images) list_docker_images ;; | |
| fix-images) fix_docker_images ;; | |
| update-images) check_image_updates ;; | |
| upgrade) upgrade_script ;; | |
| bind) bind_global_command ;; | |
| # Telegram Auth commands | |
| setup-auth) setup_telegram_auth ;; | |
| config-auth) config_telegram_auth ;; | |
| unbind) unbind_global_command ;; | |
| start-all) start_all ;; | |
| stop-all) stop_all ;; | |
| system-status) system_status ;; | |
| # Telegram commands | |
| telegram) start_telegram_bot ;; | |
| telegram-deploy) | |
| echo "⚠️ 'telegram-deploy' is deprecated. Use 'telegram' for simple bot." | |
| echo "💡 For Docker deployment, use: docker run with manual setup" | |
| start_telegram_bot | |
| ;; | |
| # Trading commands | |
| start) shift; start_trading_bot "$@" ;; | |
| # Delegated commands (use Unified Processor) | |
| list) | |
| print_step "Running list command..." | |
| run_docker_cli "python3" "/app/src/core/unified_command_processor.py" list | |
| ;; | |
| status) | |
| if [[ -z "${2:-}" ]]; then | |
| handle_command_error "status" "Cần tên symbol hoặc container" \ | |
| "Cách sử dụng: ./bot.sh status <symbol|container_name> | |
| Ví dụ: | |
| ./bot.sh status btc # Smart detection cho BTC | |
| ./bot.sh status main-btc # Container cụ thể" | |
| exit 1 | |
| fi | |
| local input_arg="$2" | |
| print_step "Đang lấy trạng thái cho: $input_arg" | |
| run_docker_cli "python3" "/app/src/core/unified_command_processor.py" status "$input_arg" | |
| ;; | |
| logs) | |
| if [[ -z "${2:-}" ]]; then | |
| handle_command_error "logs" "Cần tên symbol hoặc container" \ | |
| "Cách sử dụng: ./bot.sh logs <symbol|container_name> [lines] | |
| Ví dụ: | |
| ./bot.sh logs btc 100 # Smart detection cho BTC | |
| ./bot.sh logs main-btc 100 # Container cụ thể" | |
| exit 1 | |
| fi | |
| local input_arg="$2" | |
| local lines="${3:-50}" | |
| print_step "Đang lấy logs cho: $input_arg ($lines dòng cuối)" | |
| run_docker_cli "python3" "/app/src/core/unified_command_processor.py" logs "$input_arg" "$lines" | |
| ;; | |
| simple-logs) | |
| simple_logs "$2" "$3" | |
| ;; | |
| stop) | |
| if [[ -z "${2:-}" ]]; then | |
| handle_command_error "stop" "Cần tên symbol hoặc container" \ | |
| "Cách sử dụng: ./bot.sh stop <symbol|container_name> | |
| Ví dụ: | |
| ./bot.sh stop btc # Smart detection cho BTC | |
| ./bot.sh stop main-btc # Container cụ thể" | |
| exit 1 | |
| fi | |
| local input_arg="$2" | |
| print_step "Đang dừng: $input_arg" | |
| run_docker_cli "python3" "/app/src/core/unified_command_processor.py" stop "$input_arg" | |
| ;; | |
| restart) | |
| if [[ -z "${2:-}" ]]; then | |
| handle_command_error "restart" "Cần tên symbol hoặc container" \ | |
| "Cách sử dụng: ./bot.sh restart <symbol|container_name> | |
| Ví dụ: | |
| ./bot.sh restart btc # Smart detection cho BTC | |
| ./bot.sh restart main-btc # Container cụ thể" | |
| exit 1 | |
| fi | |
| local input_arg="$2" | |
| print_step "Đang khởi động lại: $input_arg" | |
| run_docker_cli "python3" "/app/src/core/unified_command_processor.py" restart "$input_arg" | |
| ;; | |
| remove) | |
| if [[ -z "${2:-}" ]]; then | |
| handle_command_error "remove" "Cần tên symbol hoặc container" \ | |
| "Cách sử dụng: ./bot.sh remove <symbol|container_name> [--force] | |
| Ví dụ: | |
| ./bot.sh remove btc # Smart detection cho BTC | |
| ./bot.sh remove main-btc # Container cụ thể | |
| ./bot.sh remove btc --force # Force remove container đang chạy" | |
| exit 1 | |
| fi | |
| local input_arg="$2" | |
| local force_flag="${3:-}" | |
| if [[ "$force_flag" == "--force" ]]; then | |
| print_step "Đang force remove: $input_arg" | |
| run_docker_cli "python3" "/app/src/core/unified_command_processor.py" remove "$input_arg" --force | |
| else | |
| print_step "Đang xóa: $input_arg" | |
| run_docker_cli "python3" "/app/src/core/unified_command_processor.py" remove "$input_arg" | |
| fi | |
| ;; | |
| # Credential commands (Docker CLI) | |
| list-credentials) | |
| print_step "Loading credential profiles..." | |
| run_docker_cli "credentials_cli" list | |
| ;; | |
| store-credentials) | |
| shift # Remove "store-credentials" | |
| profile="$1" | |
| api_key="$2" | |
| api_secret="$3" | |
| display_name="$4" | |
| if [[ -z "$profile" || -z "$api_key" || -z "$api_secret" ]]; then | |
| handle_command_error "store-credentials" "Missing required parameters" \ | |
| "Usage: ./bot.sh store-credentials <profile> <api_key> <api_secret> [display_name] | |
| Example: | |
| ./bot.sh store-credentials main 'your_api_key' 'your_api_secret' 'Main Account'" | |
| exit 1 | |
| fi | |
| print_step "Storing credentials for profile: $profile" | |
| run_docker_cli "credentials_cli" store "$profile" --api-key "$api_key" --api-secret "$api_secret" --display-name "$display_name" --non-interactive | |
| ;; | |
| load-credentials) | |
| if [[ -z "${2:-}" ]]; then | |
| handle_command_error "load-credentials" "Cần tên profile" \ | |
| "Cách sử dụng: ./bot.sh load-credentials <profile> | |
| Ví dụ: | |
| ./bot.sh load-credentials main" | |
| exit 1 | |
| fi | |
| print_step "Đang load credentials cho profile: $2" | |
| run_docker_cli "credentials_cli" load "$2" | |
| ;; | |
| # Assets command (Docker CLI) | |
| assets) | |
| if [[ -z "${2:-}" ]]; then | |
| handle_command_error "assets" "Cần tên profile" \ | |
| "Cách sử dụng: ./bot.sh assets <profile> | |
| Ví dụ: | |
| ./bot.sh assets main | |
| 💡 Dùng './bot.sh list-credentials' để xem các profiles có sẵn" | |
| exit 1 | |
| fi | |
| print_step "Đang load tài sản tài khoản cho profile: $2" | |
| run_docker_cli "assets_cli" show "$2" | |
| ;; | |
| # Utility commands | |
| help|--help|-h) show_help ;; | |
| version|--version|-v) | |
| echo "🤖 AutoTrader Bot v$SCRIPT_VERSION" | |
| echo "📅 Compact & Enhanced Version" | |
| echo "🐳 Docker-based Trading System" | |
| ;; | |
| check) | |
| echo "🔍 System Check" | |
| echo "===============" | |
| check_docker && echo "✅ Docker: Available" || echo "❌ Docker: Not available" | |
| check_python && echo "✅ Python: Available" || echo "❌ Python: Not available" | |
| [[ -n "$TELEGRAM_BOT_TOKEN" ]] && echo "✅ Telegram: Configured" || echo "⚠️ Telegram: Not configured" | |
| echo "📁 Configs: $(ls $CONFIG_DIR/*.json 2>/dev/null | wc -l) files" | |
| echo "🐳 Containers: $(docker ps -q | wc -l) running" | |
| ;; | |
| *) | |
| handle_command_error "unknown" "Lệnh không hợp lệ: $1" \ | |
| "Các lệnh phổ biến: | |
| ./bot.sh help # Xem tất cả lệnh | |
| ./bot.sh system-status # Kiểm tra trạng thái hệ thống | |
| ./bot.sh telegram # Khởi động Telegram bot | |
| ./bot.sh list # Liệt kê containers | |
| ./bot.sh start btc # Tạo trading bot cho BTC" | |
| exit 1 | |
| ;; | |
| esac | |
| } | |
| # Run main function | |
| main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment