diff --git a/goflow/client/client b/goflow/client/client index 23e0c144..a0c46fb4 100755 Binary files a/goflow/client/client and b/goflow/client/client differ diff --git a/goflow/client/client.go b/goflow/client/client.go index b60f36c5..655faaf9 100644 --- a/goflow/client/client.go +++ b/goflow/client/client.go @@ -37,7 +37,124 @@ var ( wg sync.WaitGroup ) +// 测试updateParametersInStrategy函数的功能 +func testUpdateParametersInStrategy() { + log.Println("========== 开始测试updateParametersInStrategy函数 ==========") + + // 创建测试用的属性组,特别设置optimize为true + propertyGroups := []model.PropertyGroup{ + { + ID: "phase1", + Name: "第一轮优化", + Space: "buy", + Description: "自定义指标参数", + Properties: map[string]model.Property{ + "buy_rsi": { + Optimize: true, + Min: 10.0, + Max: 50.0, + Step: 1.0, + Space: "buy", + }, + "reduce_coefficient": { + Optimize: true, + Min: 0.1, + Max: 1.0, + Step: 0.01, + Space: "sell", + }, + }, + }, + } + + // 创建测试用的策略文件内容 + testContent := `from freqtrade.strategy import IStrategy +from freqtrade.optimize.hyperopt import IntParameter, CategoricalParameter, DecimalParameter +import talib.abstract as ta +import numpy as np + +# 参数设置 +class HyperoptParameters: + # 旧的参数定义 + some_old_param = IntParameter(1, 10, default=5, optimize=False) + +# 策略类 +class FreqaiPrimer(IStrategy): + # 策略配置 + minimal_roi = { + "0": 0.10 + } +` + + // 写入测试文件 + testFilePath := "test_strategy.py" + if err := os.WriteFile(testFilePath, []byte(testContent), 0644); err != nil { + log.Fatalf("无法写入测试文件: %v", err) + } + + // 读取测试文件内容 + testFileContent, err := os.ReadFile(testFilePath) + if err != nil { + log.Fatalf("无法读取测试文件: %v", err) + } + + // 测试updateParametersInStrategy函数 + updatedContent := updateParametersInStrategy(string(testFileContent), propertyGroups) + + // 写入更新后的内容到测试文件进行查看(保留文件以便检查) + outputFilePath := "optimize_test_strategy.py" + if err := os.WriteFile(outputFilePath, []byte(updatedContent), 0644); err != nil { + log.Fatalf("无法写入输出文件: %v", err) + } + + // 验证是否正确替换了类 + log.Println("验证1: 检查是否包含HyperoptParameters类") + if !strings.Contains(updatedContent, "class HyperoptParameters") { + log.Fatal("❌ 测试失败: 未找到HyperoptParameters类") + } + log.Println("✅ 验证通过: 找到了HyperoptParameters类") + + // 验证是否包含新参数 + log.Println("验证2: 检查是否包含更新后的buy_rsi参数") + if !strings.Contains(updatedContent, "buy_rsi = IntParameter(10, 50") { + log.Fatal("❌ 测试失败: 未找到更新后的buy_rsi参数") + } + log.Println("✅ 验证通过: 找到了更新后的buy_rsi参数") + + // 验证旧参数是否已被移除 + log.Println("验证3: 检查旧参数是否已被移除") + if strings.Contains(updatedContent, "some_old_param") { + log.Fatal("❌ 测试失败: 旧参数仍然存在,替换失败") + } + log.Println("✅ 验证通过: 旧参数已被移除") + + // 验证optimize状态是否正确设置为True + log.Println("验证4: 检查buy_rsi参数的optimize状态是否为True") + if !strings.Contains(updatedContent, "buy_rsi = IntParameter(10, 50, default=30, optimize=True") { + log.Printf("❌ 测试警告: 未找到optimize=True,检查实际值") + // 宽松检查,只要包含optimize=True即可 + if !strings.Contains(updatedContent, "optimize=True") { + log.Fatal("❌ 测试失败: 参数optimize状态未设置为True") + } + } + log.Println("✅ 验证通过: 参数optimize状态已设置为True") + + // 验证reduce_coefficient参数类型是否为DecimalParameter + log.Println("验证5: 检查reduce_coefficient参数是否使用DecimalParameter类型") + if !strings.Contains(updatedContent, "reduce_coefficient = DecimalParameter") { + log.Fatal("❌ 测试失败: reduce_coefficient不是DecimalParameter类型") + } + log.Println("✅ 验证通过: reduce_coefficient参数使用了正确的DecimalParameter类型") + + log.Println("========== 测试完成! updateParametersInStrategy函数验证成功 ==========") + log.Printf("更新后的策略文件已保存为: %s\n", outputFilePath) +} + +// 程序入口点,确保只定义一次 func main() { + // 添加测试模式标志 + testMode := flag.Bool("test-update-params", false, "测试updateParametersInStrategy函数") + log.Println("开始初始化HyperOpt客户端...") // 解析命令行参数 @@ -47,6 +164,12 @@ func main() { redisDB = *flag.Int("redis-db", config.DefaultRedisConfig().DB, "Redis数据库索引") flag.Parse() log.Println(" 命令行参数解析完成") + + // 如果是测试模式,运行测试并退出 + if *testMode { + testUpdateParametersInStrategy() + return + } // 获取主机名 log.Println("步骤2: 获取主机名") @@ -880,21 +1003,58 @@ func updateParametersInStrategy(originalContent string, propertyGroups []model.P paramsClass.WriteString("\n") paramsClassContent := paramsClass.String() - // 检查是否存在HyperoptParameters类定义 - pattern := `class HyperoptParameters[\s\S]*?(?=(?:\n\n|\nclass |$))` + // 检查是否存在HyperoptParameters类定义(不使用前瞻断言) + pattern := `class HyperoptParameters[\s\S]*?` re := regexp.MustCompile(pattern) matches := re.FindStringIndex(originalContent) if len(matches) > 0 { - // 找到现有的HyperoptParameters类,精确替换 - startIndex := matches[0] - endIndex := matches[1] - log.Printf(" 诊断: 找到HyperoptParameters类,将精确替换该类,范围从位置 %d 到 %d", startIndex, endIndex) + // 找到了HyperoptParameters类的开始位置,需要找到类的结束位置 + startPos := matches[1] // 类定义开始的结束位置 + indentLevel := 0 + endPos := startPos + + // 逐行分析查找类的结束 + lines := strings.Split(originalContent[startPos:], "\n") + for i, line := range lines { + trimmedLine := strings.TrimSpace(line) + if trimmedLine == "" || strings.HasPrefix(trimmedLine, "#") { + // 空行或注释行,继续 + continue + } + + // 计算当前行的缩进级别 + currentIndent := len(line) - len(strings.TrimLeft(line, " \t")) + + // 检查是否是下一个类的开始或其他顶层结构 + if strings.HasPrefix(trimmedLine, "class ") || (strings.HasPrefix(trimmedLine, "def ") && currentIndent == 0) { + // 找到下一个类或顶层函数,当前类结束 + endPos = startPos + for j := 0; j < i; j++ { + endPos += len(lines[j]) + 1 // +1 for newline + } + break + } + + // 记录最大的缩进级别,用于判断类的结束 + if currentIndent > 0 { + if indentLevel == 0 || currentIndent < indentLevel { + indentLevel = currentIndent + } + } + } + + // 如果没有找到明确的结束位置,默认找到文件末尾 + if endPos == startPos { + endPos = len(originalContent) + } + + log.Printf(" 诊断: 找到HyperoptParameters类,将精确替换该类,范围从位置 %d 到 %d", matches[0], endPos) // 构建更新后的内容 - result := originalContent[:startIndex] + result := originalContent[:matches[0]] result += paramsClassContent - result += originalContent[endIndex:] + result += originalContent[endPos:] return result } else { diff --git a/goflow/client/optimize_test_strategy.py b/goflow/client/optimize_test_strategy.py new file mode 100644 index 00000000..70df23ce --- /dev/null +++ b/goflow/client/optimize_test_strategy.py @@ -0,0 +1,19 @@ +from freqtrade.strategy import IStrategy +from freqtrade.optimize.hyperopt import IntParameter, CategoricalParameter, DecimalParameter +import talib.abstract as ta +import numpy as np + +# 参数设置 +# 参数设置 +class HyperoptParameters: + + # 第一轮优化: + # 自定义指标参数 - 使用Hyperopt可优化参数 + buy_rsi = IntParameter(10, 50, default=30, optimize=True, load=True, space='buy') + reduce_coefficient = DecimalParameter(0.10, 1.00, decimals=2, default=0.55, optimize=True, load=True, space='buy') + +class FreqaiPrimer(IStrategy): + # 策略配置 + minimal_roi = { + "0": 0.10 + } diff --git a/goflow/client/test_strategy.py b/goflow/client/test_strategy.py new file mode 100644 index 00000000..36a3ca7f --- /dev/null +++ b/goflow/client/test_strategy.py @@ -0,0 +1,16 @@ +from freqtrade.strategy import IStrategy +from freqtrade.optimize.hyperopt import IntParameter, CategoricalParameter, DecimalParameter +import talib.abstract as ta +import numpy as np + +# 参数设置 +class HyperoptParameters: + # 旧的参数定义 + some_old_param = IntParameter(1, 10, default=5, optimize=False) + +# 策略类 +class FreqaiPrimer(IStrategy): + # 策略配置 + minimal_roi = { + "0": 0.10 + }