zhangkun9038@dingtalk.com cbfdcf4cd7 config
2025-11-26 23:27:19 +08:00

371 lines
10 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
set -e # 出错立即停止
### 函数定义区 ###
# 定义 remove_existing_containers 函数
remove_existing_containers() {
echo "正在查找并移除所有名称符合 'freqtrade-dryrun-*' 的容器..."
# 查找所有名称以 freqtrade-dryrun- 开头的容器
CONTAINERS=$(docker ps -aq --filter "name=freqtrade-dryrun-*")
if [ -z "$CONTAINERS" ]; then
echo "未找到任何名称符合 'freqtrade-dryrun-*' 的容器。"
return
fi
echo "找到以下容器:"
docker ps -a --filter "name=freqtrade-dryrun-*"
echo "正在自动移除所有符合条件的容器..."
# 停止并移除容器
for CONTAINER in $CONTAINERS; do
echo "正在停止容器 $CONTAINER..."
docker stop "$CONTAINER" >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "警告:无法停止容器 $CONTAINER"
continue
fi
echo "正在移除容器 $CONTAINER..."
docker rm "$CONTAINER" >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "警告:无法移除容器 $CONTAINER"
continue
fi
echo "容器 $CONTAINER 已成功移除。"
done
echo "所有符合条件的容器已处理完毕。"
}
# 1. 从SQLite数据库获取当前开放交易的币对列表
get_open_trades_pairs() {
local db_path="$1"
local pairs=()
if [ ! -f "$db_path" ]; then
echo "⚠️ 交易数据库文件 $db_path 不存在,开放交易对列表为空" >&2
echo ""
return
fi
local query_result=$(sqlite3 -header -csv "$db_path" "SELECT id, pair, open_date, amount, open_rate, max_rate, close_profit, stake_amount FROM trades WHERE is_open = 1 ORDER BY open_date DESC LIMIT 10;")
pairs=($(echo "$query_result" | awk -F ',' 'NR > 1 {print $2}' | tr -d '"'))
echo "从数据库获取到开放交易对: ${pairs[*]}" >&2
echo "${pairs[@]}"
}
# 2. 从远程接口获取币对列表
get_remote_pairs() {
local remote_url="$1"
local pairs=()
if [ -z "$remote_url" ]; then
echo "⚠️ 未提供远程币对列表URL远程币对列表为空" >&2
echo ""
return
fi
echo "正在从远程URL获取币对列表: $remote_url" >&2
local pairs_json=$(curl -s "$remote_url")
if [ $? -ne 0 ] || [ -z "$pairs_json" ]; then
echo "⚠️ 远程币对列表获取失败,使用空列表" >&2
echo ""
return
fi
local parsed_pairs=$(echo "$pairs_json" | python3 -c "
import sys, json
data = json.load(sys.stdin)
pairs = [pair.replace('-', '/') for pair in data.get('pairlist', [])]
print(' '.join(pairs) if pairs else '')
")
if [ -n "$parsed_pairs" ]; then
pairs=($parsed_pairs)
echo "从远程获取到币对: ${pairs[*]}" >&2
else
echo "⚠️ 远程币对列表解析为空" >&2
fi
echo "${pairs[@]}"
}
# 3. 合并并去重两个币对列表
merge_and_deduplicate_pairs() {
local -a db_pairs=($1)
local -a remote_pairs=($2)
local -a merged=()
merged=($(printf "%s\n" "${db_pairs[@]}" "${remote_pairs[@]}" | sort -u | tr '\n' ' '))
echo "合并去重后的币对列表: ${merged[*]}" >&2
echo "${merged[@]}"
}
# 4. 验证JSON文件格式是否有效
validate_json_file() {
local json_path="$1"
if ! command -v jq &>/dev/null; then
echo "❌ 未安装jq工具请先安装jq" >&2
exit 1
fi
if [ ! -f "$json_path" ]; then
echo "❌ JSON配置文件 $json_path 不存在" >&2
exit 1
fi
if ! jq . "$json_path" >/dev/null 2>&1; then
echo "❌ JSON文件格式错误$json_path" >&2
exit 1
fi
}
# 5. 更新live.json中的pair_whitelist
update_live_json_pair_whitelist() {
local json_path="$1"
local -a pairlist=($2)
validate_json_file "$json_path"
local json_array=$(printf '%s\n' "${pairlist[@]}" | jq -R . | jq -s .)
echo "正在更新 $json_path 中的exchange.pair_whitelist..." >&2
jq --argjson pairs "$json_array" '.exchange.pair_whitelist = $pairs' "$json_path" >"$json_path.tmp" && mv "$json_path.tmp" "$json_path"
if [ $? -eq 0 ]; then
echo "✅ 成功更新 $json_path新的pair_whitelist包含 ${#pairlist[@]} 个币对" >&2
else
echo "❌ 更新 $json_path 失败" >&2
exit 1
fi
}
### 主逻辑区 ###
# 检查 .env 文件
if [ ! -f ".env" ]; then
echo "⚠️ 本地缺少 .env 文件,请创建并配置" >&2
exit 1
fi
# 加载 .env 变量
export $(grep -v '^#' .env | xargs)
# 检查必要环境变量
if [ -z "$TEST_BRANCH" ] || [ -z "$DRYRUN_BRANCH" ]; then
echo "⚠️ .env 文件缺少 TEST_BRANCH 或 DRYRUN_BRANCH 配置" >&2
exit 1
fi
# 检查当前分支
current_branch=$(git rev-parse --abbrev-ref HEAD)
if [[ "$current_branch" != "$TEST_BRANCH" && "$current_branch" != "$DRYRUN_BRANCH" ]]; then
echo "⚠️ 错误:当前分支 '$current_branch' 不符合配置要求" >&2
exit 1
else
echo "✅ 当前分支 '$current_branch' 符合配置要求" >&2
fi
# dryrun分支清理
if [[ "$current_branch" == *"dryrun"* ]]; then
echo "当前为dryrun分支执行git reset --hard清理工作区..." >&2
git reset --hard || {
echo "⚠️ git reset失败"
exit 1
}
echo "✅ Git工作区已清理" >&2
fi
# 设置默认远程币对列表URL支持命令行参数覆盖
DEFAULT_PAIR_REMOTE_URL="http://pairlist.xl.home/api/pairlist?mute=true&count=30"
PAIR_REMOTE_LIST_URL="$DEFAULT_PAIR_REMOTE_URL"
# 初始化策略配置(从 .env 加载)
STRATEGY_NAME=${STRATEGY_NAME:-TheForceV7}
CONFIG_FILE=${CONFIG_FILE:-basic.json}
PAIRS_ARG=""
# 解析命令行参数:支持策略名、配置文件、币对列表
while [[ $# -gt 0 ]]; do
case "$1" in
--strategy=*)
STRATEGY_NAME="${1#*=}"
shift
;;
--strategy|-t)
if [[ -n "$2" && "$2" != -* ]]; then
STRATEGY_NAME="$2"
shift 2
else
echo "错误:--strategy需要指定策略名" >&2
exit 1
fi
;;
--config=*)
CONFIG_FILE="${1#*=}"
shift
;;
--config|-c)
if [[ -n "$2" && "$2" != -* ]]; then
CONFIG_FILE="$2"
shift 2
else
echo "错误:--config需要指定配置文件" >&2
exit 1
fi
;;
--pairs=*)
PAIRS_ARG="${1#*=}"
shift
;;
--pairs)
if [[ -n "$2" && "$2" != -* ]]; then
PAIRS_ARG="$2"
shift 2
else
echo "错误:--pairs需要指定值" >&2
exit 1
fi
;;
--pairRemoteList=*)
PAIR_REMOTE_LIST_URL="${1#*=}"
shift
;;
--pairRemoteList)
if [[ -n "$2" && "$2" != -* ]]; then
PAIR_REMOTE_LIST_URL="$2"
shift 2
else
echo "错误:--pairRemoteList需要指定值" >&2
exit 1
fi
;;
*)
shift
;;
esac
done
# 处理策略名称,自动匹配配置文件
if [ -n "$STRATEGY_NAME" ]; then
STRATEGY_CONFIG_LOWER="$(echo "$STRATEGY_NAME" | tr '[:upper:]' '[:lower:]').json"
# 如果没有明确指定配置文件,优先在 config_examples 中查找
if [ -f "../config_examples/$STRATEGY_CONFIG_LOWER" ]; then
CONFIG_FILE="$STRATEGY_CONFIG_LOWER"
echo "✅ 自动匹配配置文件 (config_examples): $CONFIG_FILE" >&2
elif [ -f "../freqtrade/templates/$STRATEGY_CONFIG_LOWER" ]; then
# 其次在 templates 中查找(仅罢材材)
CONFIG_FILE="$STRATEGY_CONFIG_LOWER"
echo "✅ 自动匹配配置文件 (templates): $CONFIG_FILE" >&2
fi
fi
PARAMS_NAME=$(echo "$STRATEGY_NAME" | tr '[:upper:]' '[:lower:]')
echo "✅ 使用策略: $STRATEGY_NAME" >&2
echo "✅ 使用配置: $CONFIG_FILE" >&2
echo "✅ 远程币对列表URL: $PAIR_REMOTE_LIST_URL" >&2
### 核心:处理币对列表 ###
# 0. 判断是否使用 --pairs 传入的币对列表
if [ -n "$PAIRS_ARG" ]; then
echo "✅ 使用命令行 --pairs 参数:$PAIRS_ARG" >&2
# 更新配置文件中的 pair_whitelist
if [ -f "../config_examples/live.json" ]; then
update_live_json_pair_whitelist "../config_examples/live.json" "$PAIRS_ARG"
else
echo "⚠️ 找不到 ../config_examples/live.json跳过配置更新" >&2
fi
else
# 使用旧的逻辑:数据库 + 遥程 API
echo "✅ 使用旧逻辑(数据库 + 遥程 API" >&2
# 1. 获取数据库币对(使用绝对路径)
db_path="/home/ubuntu/freqtrade/user_data/tradesv3.sqlite"
db_pairs=$(get_open_trades_pairs "$db_path")
# 2. 获取遥程币对
remote_pairs=$(get_remote_pairs "$PAIR_REMOTE_LIST_URL")
# 3. 合并去重
merged_pairs=$(merge_and_deduplicate_pairs "$db_pairs" "$remote_pairs")
# 4. 更新配置文件
if [ -f "../config_examples/live.json" ]; then
update_live_json_pair_whitelist "../config_examples/live.json" "$merged_pairs"
else
echo "⚠️ 找不到 ../config_examples/live.json跳过配置更新" >&2
fi
fi
# 编辑参数文件,删除包含 "protection": {}, 的行(如果文件存在)
PARAMS_FILE="../freqtrade/templates/${PARAMS_NAME}.json"
if [ -f "$PARAMS_FILE" ]; then
echo "正在编辑 $PARAMS_FILE 文件,删除 'protection': {} 行..." >&2
# macOS 兼容的 sed 命令
if [[ "$OSTYPE" == "darwin"* ]]; then
sed -i '' '/'"protection"': {},/d' "$PARAMS_FILE"
else
sed -i '/'"protection"': {},/d' "$PARAMS_FILE"
fi
if [ $? -eq 0 ]; then
echo "✅ 成功编辑 $PARAMS_FILE 文件" >&2
else
echo "❌ 编辑 $PARAMS_FILE 文件失败" >&2
exit 1
fi
else
echo "⚠️ 参数文件 $PARAMS_FILE 不存在,跳过编辑" >&2
fi
### 启动容器 ###
GIT_COMMIT_SHORT=$(git rev-parse HEAD | cut -c 1-8)
CONTAINER_NAME="freqtrade-dryrun-${GIT_COMMIT_SHORT}"
echo "准备启动容器: $CONTAINER_NAME" >&2
# 移除已存在的同名容器
remove_existing_containers "$CONTAINER_NAME"
# 清理临时文件放置交叉感染
cd ../
source .venv/bin/activate
rm -rf user_data/models/*
rm -rf ./freqtrade/user_data/data/backtest_results/*
rm -fr ./user_data/dryrun_results/*
cd -
# 启动新容器
echo "启动容器: $CONTAINER_NAME" >&2
docker-compose run -d --rm \
--name "$CONTAINER_NAME" \
-p 8080:8080 \
freqtrade trade \
--logfile /freqtrade/user_data/logs/freqtrade.log \
--db-url sqlite:////freqtrade/user_data/tradesv3.sqlite \
--fee 0.0008 \
--config /freqtrade/config_examples/$CONFIG_FILE \
--config /freqtrade/config_examples/live.json \
--strategy $STRATEGY_NAME \
--strategy-path /freqtrade/templates
if [ $? -eq 0 ]; then
echo "✅ 容器 $CONTAINER_NAME 启动完成" >&2
else
echo "❌ 容器启动失败" >&2
exit 1
fi