myTestFreqAI/tools/cover_params.sh
2025-11-19 09:39:48 +08:00

388 lines
11 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
# 通用工具脚本 v1.0.0
# 功能:提供参数处理、配置管理、分级日志等通用功能
# 全局变量
SCRIPT_NAME="$(basename "$0")"
SCRIPT_VERSION="v1.0.0"
CONFIG_LOADED=false
# 默认配置
DEFAULT_CONFIG_FILE="/Users/zhangkun/myTestFreqAI/freqtrade/templates/freqaiprimer.json"
DEFAULT_LOG_LEVEL="info"
# 配置变量(可通过参数或.env文件覆盖
CONFIG_FILE="${CONFIG_FILE:-$DEFAULT_CONFIG_FILE}"
LOG_LEVEL="${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}"
VERBOSE=false
DRY_RUN=false
# 获取当前日期时间
get_timestamp() {
date "+%Y-%m-%d %H:%M:%S"
}
# 获取日志级别对应的数值
# 0: debug, 1: info, 2: warn, 3: error
log_level_to_num() {
case "$1" in
debug) echo 0 ;;
info) echo 1 ;;
warn) echo 2 ;;
error) echo 3 ;;
*) echo 1 ;;
esac
}
# 获取日志级别对应的颜色
log_level_to_color() {
case "$1" in
debug) echo "\033[0;36m" ;;
info) echo "\033[0;32m" ;;
warn) echo "\033[0;33m" ;;
error) echo "\033[0;31m" ;;
*) echo "\033[0m" ;;
esac
}
# 日志函数
log() {
local level=$1
local message=$2
local current_level_num=$(log_level_to_num "$LOG_LEVEL")
local message_level_num=$(log_level_to_num "$level")
# 只输出大于等于当前日志级别的消息
if [ "$message_level_num" -ge "$current_level_num" ]; then
local color=$(log_level_to_color "$level")
local reset="\033[0m"
local timestamp=$(get_timestamp)
echo -e "$color[$timestamp] [$level] $message$reset"
fi
}
# 显示错误消息并退出
error_exit() {
log "error" "$1"
exit 1
}
# 加载环境变量
load_env() {
if [ -f ".env" ]; then
log "info" "加载环境变量文件: .env"
# 安全加载环境变量
set -a
source .env
set +a
# 检查是否有.env中设置的CONFIG_FILE
if [ ! -z "$CONFIG_FILE" ] && [ "$CONFIG_FILE" != "$DEFAULT_CONFIG_FILE" ]; then
# 如果是相对路径,则将其转换为绝对路径(相对于脚本所在目录)
if [[ ! "$CONFIG_FILE" = /* ]]; then
# 检查是否需要添加../freqtrade/templates/前缀
if [ ! -f "$CONFIG_FILE" ] && [ "$CONFIG_FILE" = "freqaiprimer.json" ]; then
CONFIG_FILE="/Users/zhangkun/myTestFreqAI/freqtrade/templates/freqaiprimer.json"
log "debug" "自动修正配置文件路径为: $CONFIG_FILE"
fi
fi
fi
# 确保配置变量使用默认值(如果环境变量未设置)
LOG_LEVEL="${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}"
return 0
else
log "warn" "环境变量文件 .env 不存在"
return 1
fi
}
# 函数: 获取配置文件的绝对路径
get_absolute_path() {
local path=$1
# 如果是相对路径,则转换为绝对路径
if [[ ! "$path" = /* ]]; then
# 获取脚本所在目录的绝对路径
local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
echo "$script_dir/$path"
else
echo "$path"
fi
}
# 函数: 加载配置文件
load_config() {
local config_file=$1
# 直接使用传入的路径(已经是绝对路径)
if [ ! -f "$config_file" ]; then
log "warn" "配置文件 $config_file 不存在,将使用默认配置"
return 1
fi
log "info" "加载配置文件: $config_file"
# 检查是否有 jq 工具可用
if command -v jq &> /dev/null; then
# 使用 jq 解析 JSON 配置文件
CONFIG_LOADED=true
log "debug" "使用 jq 解析配置文件"
# 这里可以根据需要添加具体的配置解析逻辑
else
log "warn" "未找到 jq 工具,无法解析 JSON 配置文件"
fi
}
# 显示帮助信息
show_help() {
cat << EOF
$SCRIPT_NAME $SCRIPT_VERSION
用法: $SCRIPT_NAME [选项]
选项:
-h, --help 显示此帮助信息
-v, --version 显示脚本版本
-c, --config <文件路径> 指定配置文件路径(默认: $DEFAULT_CONFIG_FILE
-l, --log-level <级别> 设置日志级别 (debug, info, warn, error),默认: info
--verbose 启用详细输出模式
--dry-run 试运行模式,不执行实际操作
--custom-param <值> 自定义参数
示例:
$SCRIPT_NAME --help
$SCRIPT_NAME --config custom.json --log-level debug
$SCRIPT_NAME --dry-run --verbose
EOF
}
# 解析命令行参数
parse_args() {
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
show_help
exit 0
;;
-v|--version)
echo "$SCRIPT_NAME $SCRIPT_VERSION"
exit 0
;;
-c|--config)
CONFIG_FILE="$2"
shift 2
;;
-l|--log-level)
LOG_LEVEL="$2"
shift 2
;;
--verbose)
VERBOSE=true
shift
;;
--dry-run)
DRY_RUN=true
shift
;;
--custom-param)
CUSTOM_PARAM="$2"
shift 2
;;
*)
error_exit "未知参数: $1"
;;
esac
done
}
# 函数将JSON配置覆盖到Python文件中的hyperopt参数
override_hyperopt_params() {
local json_file=$1
local py_file=$2
local dry_run=$3
log "info" "开始从 $json_file 覆盖参数到 $py_file"
# 检查jq工具是否可用
if ! command -v jq &> /dev/null; then
log "error" "未找到 jq 工具,无法解析 JSON 配置文件"
return 1
fi
# 检查Python文件是否存在
if [ ! -f "$py_file" ]; then
log "error" "Python 文件 $py_file 不存在"
return 1
fi
# 获取脚本所在目录
local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# 确保路径正确
if [[ ! "$json_file" = /* ]]; then
json_file="$script_dir/$json_file"
fi
if [[ ! "$py_file" = /* ]]; then
py_file="$script_dir/$py_file"
fi
log "debug" "使用JSON文件: $json_file"
log "debug" "目标Python文件: $py_file"
# 创建临时文件用于记录修改
local changes_log=$(mktemp)
# 解析所有一级参数类别buy, sell, stoploss等
local param_categories=$(jq -r '.params | keys[]' "$json_file")
for category in $param_categories; do
log "debug" "处理参数类别: $category"
# 获取该类别下的所有参数
local params=$(jq -r ".params.$category | keys[]" "$json_file")
for param in $params; do
# 获取参数值
local value=$(jq -r ".params.$category.$param" "$json_file")
log "debug" " 原始值: $value"
# 检查value是否为空或null
if [ -z "$value" ] || [ "$value" = "null" ]; then
log "error" "参数 $param 的默认值为空或未定义,无法进行参数覆盖,请检查 $json_file 中的配置"
return 1
fi
# 特殊处理字符串值,添加引号
if [[ "$value" =~ ^[a-zA-Z]+$ ]] && [[ ! "$value" == "true" ]] && [[ ! "$value" == "false" ]]; then
value="\"$value\""
fi
log "debug" " 处理后的值: $value"
log "debug" " 参数: $param = $value"
# 检查参数是否存在
if grep -q "$param.*default=" "$py_file"; then
log "debug" " 找到参数: $param"
# 显示原始行
local original_line=$(grep "$param.*default=" "$py_file" | head -1)
log "debug" " 原始行: $original_line"
else
log "warn" " 参数 $param$py_file 中未找到"
fi
# 构建sed命令来替换Python文件中的默认值
if [ "$dry_run" = true ]; then
# 试运行模式:显示将要进行的修改
log "info" "[DRY RUN] 将替换参数 $param 的默认值为 $value"
# 检查该参数是否存在于文件中
if grep -q "$param.*default=" "$py_file"; then
echo "$param: $value" >> "$changes_log"
else
log "warn" " 参数 $param$py_file 中未找到"
fi
else
# 实际运行模式:执行替换
if grep -q "$param.*default=" "$py_file"; then
# 使用sed替换默认值保留其他属性完全兼容macOS
# 创建临时文件保存替换结果
local temp_file=$(mktemp)
log "debug" " sed替换模式: s/\\($param.*default=\\)[^,}]*/\\1$value/"
log "debug" " 执行 sed 替换..."
sed "s/\\($param.*default=\\)[^,}]*/\\1$value/" "$py_file" > "$temp_file"
log "debug" " 替换结果保存到临时文件: $temp_file"
# 检查替换是否成功
if grep -q "$param.*default=$value" "$temp_file"; then
log "debug" " 替换成功,更新文件..."
else
log "warn" " 替换未成功或值未与预旧符合"
fi
# 将临时文件内容复制回原文件
mv "$temp_file" "$py_file"
log "info" " 已更新参数 $param 的默认值为 $value"
echo "$param: $value" >> "$changes_log"
else
log "warn" " 参数 $param$py_file 中未找到"
fi
fi
done
done
# 显示修改摘要
local change_count=$(wc -l < "$changes_log")
log "info" "参数更新完成,共修改 $change_count 个参数"
if [ "$VERBOSE" = true ] && [ -s "$changes_log" ]; then
log "info" "修改的参数列表:"
cat "$changes_log" | while read line; do
log "info" " $line"
done
fi
# 清理临时文件
rm -f "$changes_log"
return 0
}
# 核心任务执行函数
execute_core_task() {
log "info" "开始执行核心任务"
# 默认的JSON和Python文件路径
local default_json_file="../freqtrade/templates/freqaiprimer.json"
local default_py_file="../freqtrade/templates/freqaiprimer.py"
# 如果通过--custom-param指定了特殊操作处理它
if [ "$CUSTOM_PARAM" = "update_params" ]; then
log "info" "执行参数更新操作"
override_hyperopt_params "$default_json_file" "$default_py_file" "$DRY_RUN"
else
# 常规模式:从配置文件读取参数
if [ "$DRY_RUN" = true ]; then
log "info" "[DRY RUN] 模拟执行核心任务"
# 试运行时也执行参数更新的试运行
override_hyperopt_params "$default_json_file" "$default_py_file" "true"
else
log "info" "执行参数更新任务"
override_hyperopt_params "$default_json_file" "$default_py_file" "false"
fi
fi
# 显示当前配置信息(如果启用了详细模式)
if [ "$VERBOSE" = true ]; then
log "debug" "当前配置信息:"
log "debug" " 配置文件: $CONFIG_FILE"
log "debug" " 日志级别: $LOG_LEVEL"
log "debug" " 详细模式: $VERBOSE"
log "debug" " 试运行模式: $DRY_RUN"
if [ -n "$CUSTOM_PARAM" ]; then
log "debug" " 自定义参数: $CUSTOM_PARAM"
fi
fi
log "info" "核心任务执行完成"
}
# 主函数
main() {
# 加载环境变量
load_env
# 解析命令行参数(命令行参数优先级高于环境变量)
parse_args "$@"
# 加载配置文件
load_config "$CONFIG_FILE"
# 执行核心任务
execute_core_task
log "info" "脚本执行完成"
}
# 入口点
main "$@"