455 lines
No EOL
11 KiB
Text
455 lines
No EOL
11 KiB
Text
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Running Your Trading Bot 24/7 with nohup\n",
|
|
"\n",
|
|
"## Option 1: nohup (No Hang Up) - Simplest Method\n",
|
|
"\n",
|
|
"**Best for:** Beginners, single bot deployment, simple setups\n",
|
|
"\n",
|
|
"**What nohup does:**\n",
|
|
"- Runs your process immune to hangups (SIGHUP signals)\n",
|
|
"- Continues running even after you close SSH connection\n",
|
|
"- Redirects output to files for logging\n",
|
|
"- Simple and lightweight solution"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Step 1: Basic nohup Usage\n",
|
|
"\n",
|
|
"**⚠️ Run these commands on your server via SSH, not in Jupyter!**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"source": [
|
|
"# Basic nohup command\n",
|
|
"# This runs your bot in background and logs output to nohup.out\n",
|
|
"nohup python3 main.py &\n",
|
|
"\n",
|
|
"# Better version - custom log file\n",
|
|
"nohup python3 main.py > bot.log 2>&1 &\n",
|
|
"\n",
|
|
"# Even better - with timestamp in log filename\n",
|
|
"nohup python3 main.py > bot_$(date +%Y%m%d_%H%M%S).log 2>&1 &"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Command Breakdown:\n",
|
|
"- `nohup` - Makes process immune to hangup signals\n",
|
|
"- `python3 main.py` - Your bot command\n",
|
|
"- `> bot.log` - Redirect stdout (normal output) to bot.log\n",
|
|
"- `2>&1` - Redirect stderr (errors) to same file as stdout\n",
|
|
"- `&` - Run in background"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Step 2: Using PID Files for Better Management"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"source": [
|
|
"# Start bot and save Process ID (PID) to file\n",
|
|
"nohup python3 main.py > bot.log 2>&1 &\n",
|
|
"echo $! > bot.pid\n",
|
|
"\n",
|
|
"# Check what PID was saved\n",
|
|
"cat bot.pid\n",
|
|
"\n",
|
|
"# Verify the process is running\n",
|
|
"ps aux | grep $(cat bot.pid)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Step 3: Managing Your Bot"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"source": [
|
|
"# Check if bot is running\n",
|
|
"if kill -0 $(cat bot.pid) 2>/dev/null; then\n",
|
|
" echo \"Bot is running with PID $(cat bot.pid)\"\n",
|
|
"else\n",
|
|
" echo \"Bot is not running\"\n",
|
|
"fi\n",
|
|
"\n",
|
|
"# View live logs\n",
|
|
"tail -f bot.log\n",
|
|
"\n",
|
|
"# View last 50 lines of logs\n",
|
|
"tail -n 50 bot.log\n",
|
|
"\n",
|
|
"# Search for errors in logs\n",
|
|
"grep -i error bot.log"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Step 4: Stopping Your Bot"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"source": [
|
|
"# Graceful stop (recommended)\n",
|
|
"kill -TERM $(cat bot.pid)\n",
|
|
"\n",
|
|
"# Force stop if graceful doesn't work\n",
|
|
"kill -KILL $(cat bot.pid)\n",
|
|
"\n",
|
|
"# Clean up PID file\n",
|
|
"rm bot.pid\n",
|
|
"\n",
|
|
"# One-liner to stop and cleanup\n",
|
|
"kill $(cat bot.pid) && rm bot.pid"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Step 5: Create Start/Stop Scripts\n",
|
|
"\n",
|
|
"### Create start_bot.sh script"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"source": [
|
|
"# Create start script\n",
|
|
"nano start_bot.sh"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"**Contents of start_bot.sh:**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"source": [
|
|
"#!/bin/bash\n",
|
|
"\n",
|
|
"# Check if bot is already running\n",
|
|
"if [ -f bot.pid ] && kill -0 $(cat bot.pid) 2>/dev/null; then\n",
|
|
" echo \"Bot is already running with PID $(cat bot.pid)\"\n",
|
|
" exit 1\n",
|
|
"fi\n",
|
|
"\n",
|
|
"# Start the bot\n",
|
|
"echo \"Starting trading bot...\"\n",
|
|
"cd /root/trading-bot\n",
|
|
"nohup python3 main.py > bot_$(date +%Y%m%d_%H%M%S).log 2>&1 &\n",
|
|
"echo $! > bot.pid\n",
|
|
"\n",
|
|
"echo \"Bot started with PID $(cat bot.pid)\"\n",
|
|
"echo \"Log file: bot_$(date +%Y%m%d_%H%M%S).log\"\n",
|
|
"echo \"To view logs: tail -f bot_$(date +%Y%m%d_%H%M%S).log\""
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Create stop_bot.sh script"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"source": [
|
|
"# Create stop script\n",
|
|
"nano stop_bot.sh"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"**Contents of stop_bot.sh:**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"source": [
|
|
"#!/bin/bash\n",
|
|
"\n",
|
|
"# Check if PID file exists\n",
|
|
"if [ ! -f bot.pid ]; then\n",
|
|
" echo \"No PID file found. Bot may not be running.\"\n",
|
|
" exit 1\n",
|
|
"fi\n",
|
|
"\n",
|
|
"# Get PID\n",
|
|
"PID=$(cat bot.pid)\n",
|
|
"\n",
|
|
"# Check if process is running\n",
|
|
"if ! kill -0 $PID 2>/dev/null; then\n",
|
|
" echo \"Process $PID is not running. Cleaning up PID file.\"\n",
|
|
" rm bot.pid\n",
|
|
" exit 1\n",
|
|
"fi\n",
|
|
"\n",
|
|
"# Stop the bot\n",
|
|
"echo \"Stopping trading bot (PID: $PID)...\"\n",
|
|
"kill -TERM $PID\n",
|
|
"\n",
|
|
"# Wait for graceful shutdown\n",
|
|
"sleep 5\n",
|
|
"\n",
|
|
"# Check if still running\n",
|
|
"if kill -0 $PID 2>/dev/null; then\n",
|
|
" echo \"Process still running. Force killing...\"\n",
|
|
" kill -KILL $PID\n",
|
|
"fi\n",
|
|
"\n",
|
|
"# Clean up\n",
|
|
"rm bot.pid\n",
|
|
"echo \"Bot stopped successfully.\""
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Make scripts executable"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"source": [
|
|
"chmod +x start_bot.sh\n",
|
|
"chmod +x stop_bot.sh\n",
|
|
"\n",
|
|
"# Now you can use:\n",
|
|
"./start_bot.sh\n",
|
|
"./stop_bot.sh"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Step 6: Enhanced Python Bot with PID Management\n",
|
|
"\n",
|
|
"**Add this to your main.py to handle PID files properly:**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"source": [
|
|
"import os\n",
|
|
"import sys\n",
|
|
"import atexit\n",
|
|
"import signal\n",
|
|
"from datetime import datetime\n",
|
|
"\n",
|
|
"# PID file management\n",
|
|
"PID_FILE = 'bot.pid'\n",
|
|
"\n",
|
|
"def write_pid_file():\n",
|
|
" \"\"\"Write current process PID to file\"\"\"\n",
|
|
" with open(PID_FILE, 'w') as f:\n",
|
|
" f.write(str(os.getpid()))\n",
|
|
" print(f\"PID {os.getpid()} written to {PID_FILE}\")\n",
|
|
"\n",
|
|
"def cleanup_pid_file():\n",
|
|
" \"\"\"Remove PID file on exit\"\"\"\n",
|
|
" if os.path.exists(PID_FILE):\n",
|
|
" os.remove(PID_FILE)\n",
|
|
" print(f\"Cleaned up {PID_FILE}\")\n",
|
|
"\n",
|
|
"def signal_handler(signum, frame):\n",
|
|
" \"\"\"Handle termination signals gracefully\"\"\"\n",
|
|
" print(f\"\\nReceived signal {signum}. Shutting down gracefully...\")\n",
|
|
" cleanup_pid_file()\n",
|
|
" sys.exit(0)\n",
|
|
"\n",
|
|
"# Set up signal handlers for graceful shutdown\n",
|
|
"signal.signal(signal.SIGTERM, signal_handler)\n",
|
|
"signal.signal(signal.SIGINT, signal_handler)\n",
|
|
"\n",
|
|
"# Register cleanup function\n",
|
|
"atexit.register(cleanup_pid_file)\n",
|
|
"\n",
|
|
"# Write PID file when starting\n",
|
|
"write_pid_file()\n",
|
|
"\n",
|
|
"# Your trading bot code here\n",
|
|
"def main():\n",
|
|
" print(f\"Trading bot started at {datetime.now()}\")\n",
|
|
" \n",
|
|
" while True:\n",
|
|
" try:\n",
|
|
" # Your trading logic here\n",
|
|
" print(f\"Bot running... {datetime.now()}\")\n",
|
|
" time.sleep(60) # Sleep for 1 minute\n",
|
|
" \n",
|
|
" except KeyboardInterrupt:\n",
|
|
" print(\"\\nKeyboard interrupt received. Shutting down...\")\n",
|
|
" break\n",
|
|
" except Exception as e:\n",
|
|
" print(f\"Error occurred: {e}\")\n",
|
|
" time.sleep(10) # Wait before retrying\n",
|
|
"\n",
|
|
"if __name__ == \"__main__\":\n",
|
|
" main()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Step 7: Monitoring and Troubleshooting"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"source": [
|
|
"# Check all your Python processes\n",
|
|
"ps aux | grep python3\n",
|
|
"\n",
|
|
"# Monitor system resources\n",
|
|
"top\n",
|
|
"# or\n",
|
|
"htop\n",
|
|
"\n",
|
|
"# Check disk space (logs can grow large)\n",
|
|
"df -h\n",
|
|
"\n",
|
|
"# Check memory usage\n",
|
|
"free -h\n",
|
|
"\n",
|
|
"# Find large log files\n",
|
|
"find . -name \"*.log\" -size +10M\n",
|
|
"\n",
|
|
"# Rotate logs (keep last 100 lines)\n",
|
|
"tail -n 100 bot.log > bot.log.tmp && mv bot.log.tmp bot.log"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Common Issues and Solutions\n",
|
|
"\n",
|
|
"### Issue 1: \"Bot.pid file exists but process not running\"\n",
|
|
"**Solution:** Clean up stale PID file\n",
|
|
"```bash\n",
|
|
"rm bot.pid\n",
|
|
"./start_bot.sh\n",
|
|
"```\n",
|
|
"\n",
|
|
"### Issue 2: \"Permission denied\"\n",
|
|
"**Solution:** Check file permissions\n",
|
|
"```bash\n",
|
|
"chmod +x start_bot.sh stop_bot.sh\n",
|
|
"chmod 755 main.py\n",
|
|
"```\n",
|
|
"\n",
|
|
"### Issue 3: \"Module not found errors\"\n",
|
|
"**Solution:** Install missing packages\n",
|
|
"```bash\n",
|
|
"pip3 install package_name\n",
|
|
"```\n",
|
|
"\n",
|
|
"### Issue 4: \"Log files growing too large\"\n",
|
|
"**Solution:** Implement log rotation\n",
|
|
"```bash\n",
|
|
"# Add to crontab for daily log rotation\n",
|
|
"0 0 * * * /root/trading-bot/rotate_logs.sh\n",
|
|
"```"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Pros and Cons Summary\n",
|
|
"\n",
|
|
"### ✅ Pros:\n",
|
|
"- **Simple to use** - just one command\n",
|
|
"- **Lightweight** - minimal system overhead\n",
|
|
"- **Built-in** - available on all Unix/Linux systems\n",
|
|
"- **Perfect for single bot** deployments\n",
|
|
"- **Easy debugging** - direct log file access\n",
|
|
"\n",
|
|
"### ❌ Cons:\n",
|
|
"- **No automatic restart** on crash\n",
|
|
"- **Manual management** - need scripts for start/stop\n",
|
|
"- **No built-in monitoring** - need external tools\n",
|
|
"- **PID file management** - manual cleanup needed\n",
|
|
"- **Not suitable for multiple bots** - becomes complex\n",
|
|
"\n",
|
|
"### 🎯 Best Use Cases:\n",
|
|
"- Learning and development\n",
|
|
"- Single trading bot deployment\n",
|
|
"- Short to medium-term trading strategies\n",
|
|
"- When you want full control over the process"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "Python 3",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": {
|
|
"name": "ipython",
|
|
"version": 3
|
|
},
|
|
"file_extension": ".py",
|
|
"mimetype": "text/x-python",
|
|
"name": "python",
|
|
"nbconvert_exporter": "python",
|
|
"pygments_lexer": "ipython3",
|
|
"version": "3.8.5"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 4
|
|
} |