344 lines
11 KiB
Bash
Executable File
344 lines
11 KiB
Bash
Executable File
#!/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:-TheForceV7}
|
||
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
|
||
# 处理命名参数时跳过已解析的参数
|
||
parsed_args=()
|
||
while [ $# -gt 0 ]; do
|
||
case "$1" in
|
||
--start-date | --end-date | --pairs | --pairRemoteList | --strategy | -t | --config)
|
||
parsed_args+=("$1" "$2")
|
||
shift 2
|
||
;;
|
||
*)
|
||
parsed_args+=("$1")
|
||
shift
|
||
;;
|
||
esac
|
||
done
|
||
set -- "${parsed_args[@]}"
|
||
|
||
# 使用命名参数解析
|
||
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" "$@")
|
||
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
|
||
# 参数顺序说明
|
||
# 位置参数模式:
|
||
# $0 [开始日期] [结束日期] [策略名] [交易对/URL]
|
||
# 命名参数模式:
|
||
# --start-date=YYYYMMDD --end-date=YYYYMMDD --strategy=NAME --pairs=PAIRS
|
||
# 混合使用位置和命名参数时,命名参数优先
|
||
if [ $# -gt 2 ]; then
|
||
STRATEGY_ARG="$3"
|
||
echo "Detected strategy parameter: $STRATEGY_ARG"
|
||
fi
|
||
|
||
# 第4参数处理交易对或URL
|
||
if [ $# -gt 3 ]; then
|
||
FOURTH_PARAM="$4"
|
||
if [[ "$FOURTH_PARAM" == http://* ]] || [[ "$FOURTH_PARAM" == https://* ]]; then
|
||
PAIR_REMOTE_LIST_URL="$FOURTH_PARAM"
|
||
echo "Detected URL parameter: $PAIR_REMOTE_LIST_URL"
|
||
elif [[ "$FOURTH_PARAM" == */USDT ]] || [[ "$FOURTH_PARAM" == */BUSD ]] || [[ "$FOURTH_PARAM" == */USDC ]]; then
|
||
PAIRS_ARG="$FOURTH_PARAM"
|
||
echo "Detected pair parameter: $PAIRS_ARG"
|
||
fi
|
||
fi
|
||
# 增强策略名检测逻辑
|
||
# 增强参数类型校验
|
||
if [ $# -gt 3 ]; then
|
||
FOURTH_PARAM="$4"
|
||
if [[ "$FOURTH_PARAM" =~ ^[0-9]{8}$ ]]; then
|
||
echo "错误:第4个参数应该是交易对或URL,而不是日期"
|
||
exit 1
|
||
elif [[ "$FOURTH_PARAM" == http://* ]] || [[ "$FOURTH_PARAM" == https://* ]]; then
|
||
PAIR_REMOTE_LIST_URL="$FOURTH_PARAM"
|
||
echo "检测到远程交易对列表URL: $PAIR_REMOTE_LIST_URL"
|
||
elif [[ "$FOURTH_PARAM" == */* ]]; then
|
||
PAIRS_ARG="$FOURTH_PARAM"
|
||
echo "检测到交易对参数: $PAIRS_ARG"
|
||
elif [[ "$FOURTH_PARAM" == *.py ]]; then
|
||
echo "警告:策略参数应通过-t或--strategy指定"
|
||
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" =~ ^[0-9]{8}$ ]]; then
|
||
# 处理YYYYMMDD格式
|
||
START_DATE=$(date -d "${START_DATE_RAW:0:4}-${START_DATE_RAW:4:2}-${START_DATE_RAW:6:2}" +"%s" 2>/dev/null)
|
||
if [ -z "$START_DATE" ]; then
|
||
echo "错误:无效的起始日期格式 $START_DATE_RAW,请使用 YYYY-MM-DD 或 YYYYMMDD"
|
||
exit 1
|
||
fi
|
||
elif [[ "$START_DATE_RAW" == *" "* ]]; then
|
||
START_DATE=$(date -d "$START_DATE_RAW" +"%s" 2>/dev/null)
|
||
if [ -z "$START_DATE" ]; then
|
||
echo "错误:无效的起始日期格式 $START_DATE_RAW"
|
||
exit 1
|
||
fi
|
||
else
|
||
echo "错误:未知的日期格式 $START_DATE_RAW"
|
||
exit 1
|
||
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_FILE_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 TheForceV7"
|
||
STRATEGY_NAME="TheForceV7"
|
||
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 "正确用法示例:"
|
||
echo "位置参数模式:"
|
||
echo " $0 20230901 20231001 MartinGale BTC/USDT"
|
||
echo "命名参数模式:"
|
||
echo " $0 --start-date=20230901 --end-date=20231001 -t MartinGale"
|
||
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/*
|
||
|
||
PARAMS_NAME=freqaiprimer
|
||
echo "docker-compose run --rm freqtrade hyperopt $PAIRS_FLAG \
|
||
--logfile /freqtrade/user_data/logs/freqtrade.log \
|
||
--freqaimodel LightGBMRegressorMultiTarget \
|
||
--strategy $STRATEGY_CLASS_NAME \
|
||
--config /freqtrade/config_examples/$CONFIG_FILE \
|
||
--config /freqtrade/templates/${PARAMS_NAME}.json \
|
||
--enable-protections \
|
||
--strategy-path /freqtrade/templates \
|
||
--timerange ${START_DATE}-${END_DATE} \
|
||
--random-state 19 \
|
||
-e 2500 \
|
||
-j 4 \
|
||
--hyperopt-loss SharpeHyperOptLossDaily \
|
||
--spaces sell \
|
||
--fee 0.001"
|
||
|
||
docker-compose run --rm freqtrade hyperopt $PAIRS_FLAG \
|
||
--logfile /freqtrade/user_data/logs/freqtrade.log \
|
||
--freqaimodel LightGBMRegressorMultiTarget \
|
||
--strategy $STRATEGY_CLASS_NAME \
|
||
--config /freqtrade/config_examples/$CONFIG_FILE \
|
||
--config /freqtrade/templates/${PARAMS_NAME}.json \
|
||
--enable-protections \
|
||
--strategy-path /freqtrade/templates \
|
||
--timerange ${START_DATE}-${END_DATE} \
|
||
--random-state 19 \
|
||
-e 2500 \
|
||
-j 24 \
|
||
--hyperopt-loss SharpeHyperOptLossDaily \
|
||
--spaces sell \
|
||
--fee 0.001
|