myTestFreqAI/tools/backtest.sh
zhangkun9038@dingtalk.com b368bd88d4 update backtest.sh
2025-10-14 09:49:11 +00:00

319 lines
10 KiB
Bash
Executable File
Raw Permalink 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
# 检查 .env 文件
if [ ! -f ".env" ]; then
echo "⚠️ 本地缺少 .env 文件,请创建并配置。示例内容如下:"
echo ""
echo "STRATEGY_NAME=TheForceV7"
echo "CONFIG_FILE=basic.json"
echo "TEST_BRANCH=theforce-noai-test"
echo "DRYRUN_BRANCH=theforce-noai-dryrun"
echo ""
exit 1
fi
# 加载 .env 文件中的变量
if [ -f .env ]; then
set -a
source .env
set +a
fi
# 设置默认值
# 设置默认策略名称
STRATEGY_NAME=${STRATEGY_NAME:-FreqaiPrimer}
CONFIG_FILE=${CONFIG_FILE:-basic.json}
TEST_BRANCH=${TEST_BRANCH:-develop}
# Function to extract the value of a parameter
get_param_value() {
local param="$1"
shift
local args=("$@")
local i=0
while [ $i -lt ${#args[@]} ]; do
case "${args[$i]}" in
$param=*)
echo "${args[$i]#*=}"
return 0
;;
$param)
# Check if the next argument exists and does not start with a dash
if [ $((i + 1)) -lt ${#args[@]} ] && [[ "${args[$((i + 1))]}" != -* ]]; then
echo "${args[$((i + 1))]}"
return 0
fi
# 如果参数存在但没有值,返回特殊标识"PARAM_WITHOUT_VALUE"
echo "PARAM_WITHOUT_VALUE"
return 0
;;
esac
i=$((i + 1))
done
# 如果参数不存在,返回空字符串
echo ""
return 0
}
# Check if we have named parameters
HAS_NAMED_PARAMS=false
for arg in "$@"; do
if [[ "$arg" == --* ]]; then
HAS_NAMED_PARAMS=true
break
fi
done
# Initialize variables
START_DATE_RAW=""
END_DATE_RAW=""
PAIRS_ARG=""
PAIR_REMOTE_LIST_URL=""
# Parse parameters based on whether we have named parameters
if [ "$HAS_NAMED_PARAMS" = true ]; then
# Use named parameter parsing
START_DATE_RAW=$(get_param_value "--start-date" "$@")
END_DATE_RAW=$(get_param_value "--end-date" "$@")
PAIRS_ARG=$(get_param_value "--pairs" "$@")
PAIR_REMOTE_LIST_URL=$(get_param_value "--pairRemoteList" "$@")
STRATEGY_ARG=$(get_param_value "--strategy" "$@")
# 支持 -t 作为 --strategy 的简化参数
if [ -z "$STRATEGY_ARG" ]; then
STRATEGY_ARG=$(get_param_value "-t" "$@")
fi
CONFIG_ARG=$(get_param_value "--config" "$@")
else
# Use positional parameter parsing
if [ $# -gt 0 ]; then
START_DATE_RAW="$1"
fi
if [ $# -gt 1 ]; then
END_DATE_RAW="$2"
fi
if [ $# -gt 2 ]; then
THIRD_PARAM="$3"
# Check if it's a URL
if [[ "$THIRD_PARAM" == http://* ]] || [[ "$THIRD_PARAM" == https://* ]]; then
PAIR_REMOTE_LIST_URL="$THIRD_PARAM"
echo "Detected URL parameter: $PAIR_REMOTE_LIST_URL"
# Check if it's a pair like "*/USDT"
elif [[ "$THIRD_PARAM" == */USDT ]] || [[ "$THIRD_PARAM" == */BUSD ]] || [[ "$THIRD_PARAM" == */USDC ]]; then
PAIRS_ARG="$THIRD_PARAM"
echo "Detected pair parameter: $PAIRS_ARG"
# Check if it's a strategy name
elif [[ "$THIRD_PARAM" == *.py ]] || [[ "$THIRD_PARAM" != -* ]]; then
STRATEGY_ARG="$THIRD_PARAM"
echo "Detected strategy parameter: $STRATEGY_ARG"
else
echo "Warning: Third parameter '$THIRD_PARAM' is neither a URL nor a pair nor a strategy"
fi
fi
if [ $# -gt 3 ]; then
FOURTH_PARAM="$4"
if [[ "$FOURTH_PARAM" == *.json ]]; then
CONFIG_ARG="$FOURTH_PARAM"
echo "Detected config parameter: $CONFIG_ARG"
fi
fi
fi
# Set default values if parameters not provided
if [ -z "$START_DATE_RAW" ]; then
START_DATE_RAW=$(date -d "2 days ago" +"%Y-%m-%d %H:%M:%S")
fi
if [ -z "$END_DATE_RAW" ]; then
END_DATE_RAW=$(date -d "tomorrow" +"%Y-%m-%d %H:%M:%S")
fi
# Parse dates
if [[ "$START_DATE_RAW" == *" "* ]]; then
START_DATE=$(date -d "$START_DATE_RAW" +"%s")
else
# 兼容旧格式20250616 -> 转换为 2025-06-16 00:00:00 再转为时间戳
START_DATE=$(date -d "${START_DATE_RAW:0:4}-${START_DATE_RAW:4:2}-${START_DATE_RAW:6:2} 00:00:00" +"%s")
fi
if [[ "$END_DATE_RAW" == *" "* ]]; then
END_DATE=$(date -d "$END_DATE_RAW" +"%s")
else
END_DATE=$(date -d "${END_DATE_RAW:0:4}-${END_DATE_RAW:4:2}-${END_DATE_RAW:6:2} 00:00:00" +"%s")
fi
# 处理交易对参数:优先级为 --pairRemoteList > --pairs > 默认值
if [ -n "$PAIR_REMOTE_LIST_URL" ]; then
# 从远程API获取交易对列表
echo "Fetching pairs from remote URL: $PAIR_REMOTE_LIST_URL"
pairs_json=$(curl -s "$PAIR_REMOTE_LIST_URL")
# 检查API响应是否成功
if [[ $? -ne 0 || -z "$pairs_json" ]]; then
echo "Error: Failed to fetch pairs from remote URL, using --pairs parameter or default"
if [ -n "$PAIRS_ARG" ]; then
PAIRS_FLAG="--pairs $PAIRS_ARG"
echo "Using pairs from --pairs parameter: $PAIRS_ARG"
else
# 使用默认的交易对列表
DEFAULT_PAIRS="BTC/USDT TON/USDT DOT/USDT XRP/USDT OKB/USDT SOL/USDT DOGE/USDT WCT/USDT TRUMP/USDT SUI/USDT PEPE/USDT TRB/USDT MASK/USDT UNI/USDT KAITO/USDT"
PAIRS_FLAG="--pairs $DEFAULT_PAIRS"
echo "Using default pairs: $DEFAULT_PAIRS"
fi
else
# 解析JSON并提取交易对将连字符替换为斜杠
remote_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 "$remote_pairs" ]]; then
PAIRS_FLAG="--pairs $remote_pairs"
echo "Successfully fetched $(echo "$remote_pairs" | wc -w) pairs from remote URL"
echo "Pairs: $remote_pairs"
else
echo "Error: Failed to parse or empty pairlist from remote URL, using --pairs parameter or default"
if [ -n "$PAIRS_ARG" ]; then
PAIRS_FLAG="--pairs $PAIRS_ARG"
echo "Using pairs from --pairs parameter: $PAIRS_ARG"
else
# 使用默认的交易对列表
DEFAULT_PAIRS="BTC/USDT TON/USDT DOT/USDT XRP/USDT OKB/USDT SOL/USDT DOGE/USDT WCT/USDT TRUMP/USDT SUI/USDT PEPE/USDT TRB/USDT MASK/USDT UNI/USDT KAITO/USDT"
PAIRS_FLAG="--pairs $DEFAULT_PAIRS"
echo "Using default pairs: $DEFAULT_PAIRS"
fi
fi
fi
elif [ -n "$PAIRS_ARG" ]; then
# 使用 --pairs 参数提供的交易对
PAIRS_FLAG="--pairs $PAIRS_ARG"
echo "Using pairs from --pairs parameter: $PAIRS_ARG"
else
# 没有提供任何交易对参数,使用默认值
DEFAULT_PAIRS="BTC/USDT TON/USDT DOT/USDT XRP/USDT OKB/USDT SOL/USDT DOGE/USDT WCT/USDT TRUMP/USDT SUI/USDT PEPE/USDT TRB/USDT MASK/USDT UNI/USDT KAITO/USDT"
PAIRS_FLAG="--pairs $DEFAULT_PAIRS"
echo "No pairs parameter provided, using default pairs: $DEFAULT_PAIRS"
fi
# 如果命令行提供了有效的策略参数,覆盖.env文件设置
if [ -n "$STRATEGY_ARG" ] && [ "$STRATEGY_ARG" != "PARAM_WITHOUT_VALUE" ]; then
# 策略类名保持不变如MyStrategy但文件名使用小写
STRATEGY_CLASS_NAME="$STRATEGY_ARG"
STRATEGY_FILE_NAME="$(echo "$STRATEGY_ARG" | tr '[:upper:]' '[:lower:]').py"
STRATEGY_NAME="$STRATEGY_CLASS_NAME"
echo "Overriding strategy with command line parameter: $STRATEGY_CLASS_NAME"
echo "Strategy class name: $STRATEGY_CLASS_NAME"
echo "Strategy file name: $STRATEGY_FILE_NAME"
# 自动匹配策略对应的配置文件(使用小写)
STRATEGY_CONFIG_LOWER="$(echo "$STRATEGY_ARG" | tr '[:upper:]' '[:lower:]').json"
echo "Checking auto-matched config file: freqtrade/templates/$STRATEGY_CONFIG_LOWER"
# 检查小写配置文件
if [ -f "../freqtrade/templates/$STRATEGY_CONFIG_LOWER" ]; then
CONFIG_FILE="$STRATEGY_CONFIG_LOWER"
echo "Auto-matched config file for strategy: $CONFIG_FILE"
else
echo "Warning: Auto-matched config file '$STRATEGY_CONFIG_LOWER' not found in templates directory"
echo "Available config files in templates directory:"
ls ../freqtrade/templates/*.json 2>/dev/null | sed 's|.*/||' || echo "No JSON config files found"
echo "Using current config: $CONFIG_FILE"
fi
fi
# 如果命令行提供了配置参数,覆盖.env文件设置
if [ -n "$CONFIG_ARG" ]; then
CONFIG_FILE="$CONFIG_ARG"
echo "Overriding config with command line parameter: $CONFIG_FILE"
fi
# 检查指定的配置文件是否存在,如果不存在则使用默认配置
echo "Checking config file: freqtrade/templates/$CONFIG_FILE"
if [ ! -f "../freqtrade/templates/$CONFIG_FILE" ]; then
echo "Warning: Config file freqtrade/templates/$CONFIG_FILE not found, using default configuration"
CONFIG_FILE="basic.json"
else
echo "Config file found: freqtrade/templates/$CONFIG_FILE"
fi
# 最后确认STRATEGY_NAME有值
if [ -z "$STRATEGY_NAME" ]; then
echo "Warning: STRATEGY_NAME is empty, using default FreqaiPrimer"
STRATEGY_NAME="FreqaiPrimer"
fi
# 确保STRATEGY_CLASS_NAME有值
if [ -z "$STRATEGY_CLASS_NAME" ]; then
echo "Warning: STRATEGY_CLASS_NAME is empty, setting to STRATEGY_NAME value"
STRATEGY_CLASS_NAME="$STRATEGY_NAME"
fi
# 在参数处理完成后输出最终使用的值
echo "Using strategy: $STRATEGY_NAME"
echo "Using config: $CONFIG_FILE"
echo "Using testBranch: $TEST_BRANCH"
cd ../
source .venv/bin/activate
rm -rf user_data/models/*
rm -rf ./freqtrade/user_data/data/backtest_results/*
rm -fr ./user_data/dryrun_results/*
rm -f result/*
rm ./user_data/backtest_results/*
echo "docker-compose run --rm freqtrade backtesting $PAIRS_FLAG \
--logfile /freqtrade/user_data/logs/freqtrade.log \
--freqaimodel LightGBMRegressorMultiTarget \
--config /freqtrade/config_examples/$CONFIG_FILE \
--config /freqtrade/templates/$CONFIG_FILE \
--strategy $STRATEGY_NAME \
--strategy-path /freqtrade/templates \
--timerange $START_DATE-$END_DATE \
--fee 0.0008 \
--breakdown day \
--cache none >output.log"
docker-compose run --rm freqtrade backtesting $PAIRS_FLAG \
--logfile /freqtrade/user_data/logs/freqtrade.log \
--freqaimodel LightGBMRegressorMultiTarget \
--config /freqtrade/config_examples/$CONFIG_FILE \
--config /freqtrade/templates/$CONFIG_FILE \
--strategy $STRATEGY_CLASS_NAME \
--strategy-path /freqtrade/templates \
--enable-protections \
--timerange $START_DATE-$END_DATE \
--fee 0.0008 \
--breakdown day \
--cache none >output.log 2>&1
sed -i 's/\x1B\[[0-9;]*m//g' output.log
rm ./result/*.json -fr
rm ./result/*.py -fr
cp ./user_data/backtest_results/* ./result/
cd ./result
# 查找当前目录下的所有 zip 文件
zip_files=(*.zip)
# 检查是否只有一个 zip 文件
if [ ${#zip_files[@]} -eq 1 ]; then
# 解压缩该 zip 文件到当前目录
unzip "${zip_files[0]}"
rm *.zip
rm *.feather
else
echo "当前目录下没有 zip 文件或者有多个 zip 文件,无法操作。"
fi
cd -
sed -i 's/\x1B\[[0-9;]*m//g' output.log
cp output.log result/ -f
cd tools/
python tradestocsv.py
python analytic.py >../result/analytic.log
cd ../