diff --git a/manual_trading_hub/scripts/check_agents.sh b/manual_trading_hub/scripts/check_agents.sh new file mode 100644 index 0000000..b3cf210 --- /dev/null +++ b/manual_trading_hub/scripts/check_agents.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +# 检查四路子代理端口与 /status(在服务器上运行) +set -e + +check_one() { + local name="$1" port="$2" + echo "=== ${name} :${port} ===" + if command -v ss >/dev/null 2>&1; then + ss -tlnp 2>/dev/null | grep ":${port} " && echo " 端口: 已被占用" || echo " 端口: 空闲" + fi + if command -v curl >/dev/null 2>&1; then + local body + body=$(curl -sf --max-time 8 "http://127.0.0.1:${port}/status" 2>/dev/null) || { + echo " /status: 无法连接(agent 未启动或崩溃)" + return + } + echo " /status: ${body:0:200}" + if echo "${body}" | grep -q '"ok":true'; then + echo " 结果: OK" + else + echo " 结果: ok=false,见上 JSON" + fi + else + echo " (未安装 curl,跳过 HTTP 检测)" + fi + echo +} + +check_one "binance" 15200 +check_one "okx" 15201 +check_one "gate" 15202 +check_one "gate_bot" 15203 + +echo "PM2 状态:" +pm2 status 2>/dev/null | grep -E 'manual-agent|manual-trading' || true diff --git a/manual_trading_hub/scripts/fix_env_crlf.sh b/manual_trading_hub/scripts/fix_env_crlf.sh new file mode 100644 index 0000000..b0d9e5c --- /dev/null +++ b/manual_trading_hub/scripts/fix_env_crlf.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +# 去掉各目录 .env 的 Windows 换行符(解决 PM2 agent errored: $'\r': command not found) +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO="$(cd "${SCRIPT_DIR}/../.." && pwd)" + +dirs=( + "${REPO}/manual_trading_hub" + "${REPO}/crypto_monitor_binance" + "${REPO}/crypto_monitor_okx" + "${REPO}/crypto_monitor_gate" + "${REPO}/crypto_monitor_gate_bot" +) + +fixed=0 +for d in "${dirs[@]}"; do + f="${d}/.env" + if [[ ! -f "${f}" ]]; then + echo "跳过(无文件): ${f}" + continue + fi + if grep -q $'\r' "${f}" 2>/dev/null; then + sed -i 's/\r$//' "${f}" + echo "已修复 CRLF: ${f}" + fixed=$((fixed + 1)) + else + echo "已是 LF: ${f}" + fi +done + +echo "完成,共修复 ${fixed} 个 .env。请执行: pm2 restart ecosystem.config.cjs" diff --git a/manual_trading_hub/scripts/lib_load_dotenv.sh b/manual_trading_hub/scripts/lib_load_dotenv.sh new file mode 100644 index 0000000..633de54 --- /dev/null +++ b/manual_trading_hub/scripts/lib_load_dotenv.sh @@ -0,0 +1,16 @@ +# shellcheck shell=bash +# 供 run_agent.sh / run_hub.sh source:加载 .env 并去掉 Windows CRLF($'\r') +load_dotenv_file() { + local f="$1" + if [[ ! -f "${f}" ]]; then + return 1 + fi + set -a + set +e + # shellcheck disable=SC1090 + . <(sed 's/\r$//' "${f}") + local rc=$? + set -e + set +a + return "${rc}" +} diff --git a/manual_trading_hub/scripts/pm2_restart_agents.sh b/manual_trading_hub/scripts/pm2_restart_agents.sh new file mode 100644 index 0000000..52d09da --- /dev/null +++ b/manual_trading_hub/scripts/pm2_restart_agents.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# 仅重启失败的子代理(保留 hub / 已 online 的 agent) +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +HUB_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" +ECO="${HUB_DIR}/ecosystem.config.cjs" + +cd "${HUB_DIR}" +chmod +x scripts/run_agent.sh scripts/run_hub.sh 2>/dev/null || true + +AGENTS=(manual-agent-binance manual-agent-okx manual-agent-gate manual-agent-gate-bot) + +for n in "${AGENTS[@]}"; do + pm2 delete "${n}" 2>/dev/null || true +done + +pm2 start "${ECO}" --only manual-agent-binance +pm2 start "${ECO}" --only manual-agent-gate +pm2 start "${ECO}" --only manual-agent-gate-bot + +# OKX 若已 online 可跳过;若也挂了则: +# pm2 start "${ECO}" --only manual-agent-okx + +pm2 save 2>/dev/null || true +echo "已重建 binance / gate / gate-bot 子代理,请执行: bash scripts/check_agents.sh" diff --git a/manual_trading_hub/scripts/run_agent.sh b/manual_trading_hub/scripts/run_agent.sh index 5da8527..4a613d7 100644 --- a/manual_trading_hub/scripts/run_agent.sh +++ b/manual_trading_hub/scripts/run_agent.sh @@ -4,10 +4,12 @@ set -e set -o pipefail HUB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +# shellcheck source=lib_load_dotenv.sh +source "${HUB_DIR}/scripts/lib_load_dotenv.sh" + VENV_PY="${HUB_DIR}/.venv/bin/python" AGENT_PY="${HUB_DIR}/agent.py" -# PM2 ecosystem 注入,须在 source .env 之后再次强制(避免 .env 覆盖 PORT/EXCHANGE) _PM2_EXCHANGE="${EXCHANGE:-}" _PM2_PORT="${PORT:-}" _PM2_HOST="${HOST:-}" @@ -18,10 +20,10 @@ if [[ ! -x "${VENV_PY}" ]]; then fi if [[ -f .env ]]; then - set -a - # shellcheck disable=SC1091 - . ./.env - set +a + if ! load_dotenv_file ".env"; then + echo "错误: $(pwd)/.env 加载失败" >&2 + exit 1 + fi else echo "警告: $(pwd) 下无 .env,agent 可能缺少 API 密钥" >&2 fi @@ -30,5 +32,12 @@ fi [[ -n "${_PM2_PORT}" ]] && export PORT="${_PM2_PORT}" [[ -n "${_PM2_HOST}" ]] && export HOST="${_PM2_HOST}" +if command -v ss >/dev/null 2>&1 && [[ -n "${PORT:-}" ]]; then + if ss -tln 2>/dev/null | grep -q ":${PORT} "; then + echo "错误: 端口 ${PORT} 已被占用,agent 无法监听(exchange=${EXCHANGE:-?})" >&2 + exit 1 + fi +fi + echo "agent start: exchange=${EXCHANGE:-?} port=${PORT:-?} cwd=$(pwd)" >&2 exec "${VENV_PY}" "${AGENT_PY}" diff --git a/manual_trading_hub/scripts/run_hub.sh b/manual_trading_hub/scripts/run_hub.sh index 5a25cc3..d35d01e 100644 --- a/manual_trading_hub/scripts/run_hub.sh +++ b/manual_trading_hub/scripts/run_hub.sh @@ -1,21 +1,25 @@ #!/usr/bin/env bash # PM2 / 手动启动入口:加载 manual_trading_hub/.env 后运行 hub.py -set -euo pipefail +set -e +set -o pipefail HUB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" cd "${HUB_DIR}" +# shellcheck source=lib_load_dotenv.sh +source "${HUB_DIR}/scripts/lib_load_dotenv.sh" + VENV_PY="${HUB_DIR}/.venv/bin/python" if [[ ! -x "${VENV_PY}" ]]; then echo "未找到 ${VENV_PY},请先: python3 -m venv .venv && pip install -r requirements.txt" >&2 exit 1 fi -set -a if [[ -f "${HUB_DIR}/.env" ]]; then - # shellcheck disable=SC1091 - . "${HUB_DIR}/.env" + load_dotenv_file "${HUB_DIR}/.env" || { + echo "错误: ${HUB_DIR}/.env 加载失败" >&2 + exit 1 + } fi -set +a exec "${VENV_PY}" "${HUB_DIR}/hub.py" diff --git a/manual_trading_hub/部署文档.md b/manual_trading_hub/部署文档.md index 53b0619..25ab462 100644 --- a/manual_trading_hub/部署文档.md +++ b/manual_trading_hub/部署文档.md @@ -216,7 +216,8 @@ pm2 restart ecosystem.config.cjs |------|------| | PM2 启动后立刻退出 | `pm2 logs manual-trading-hub`;检查 `.venv`、`.env`、`run_hub.sh` 可执行 | | 余额显示 —、无报错 | 子代理未加载策略目录 `.env`(旧版 PM2 直接跑 agent.py) | 更新代码后 `pm2 restart ecosystem.config.cjs`;`curl http://127.0.0.1:15200/status` 应 `ok:true` 且有 `balance_usdt` | -| PM2 里 agent **stopped**(hub 仍 online) | 启动失败:端口占用、无 `.env`/密钥、`run_agent.sh` 无执行权限、venv 缺失 | `pm2 logs manual-agent-binance --lines 80`;`chmod +x scripts/run_agent.sh`;`ss -tlnp \| grep 15200` | +| PM2 里 agent **errored**,日志 `$'\r': command not found` | `.env` 为 Windows **CRLF** 换行 | `bash scripts/fix_env_crlf.sh` 后 `pm2 restart ecosystem.config.cjs`(新版 `run_agent.sh` 也会自动去 `\r`) | +| PM2 里 agent **stopped / errored**(其它) | 端口占用、无密钥、venv 缺失 | `bash scripts/check_agents.sh`;`pm2 logs manual-agent-binance --lines 80` | | 监控无持仓 | 子代理未起或 Agent URL 错;或交易所确实无仓 | `curl http://127.0.0.1:15200/status` | | 无关键位/下单 401 | Flask 未起或 `HUB_BRIDGE_TOKEN` 不一致;或设 `APP_AUTH_DISABLED=true` | | 子代理 SOCKS 报错 | 在 **manual_trading_hub/.venv** 安装 `PySocks` 后 **pm2 restart** 子代理 |