From 81dc55baafbbcf281a1caa224faa4cb15faa2b1d Mon Sep 17 00:00:00 2001 From: yangfan <784310601@qq.com> Date: Tue, 12 May 2026 17:23:53 +0800 Subject: [PATCH] =?UTF-8?q?11=E7=82=B9=E6=B6=A8=E5=81=9C=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E5=8F=98=E6=9B=B4=E4=B8=BA10=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...it_board_break_next_performance_service.go | 35 ++++++++-- ...ard_break_next_performance_service_test.go | 66 ------------------- internal/service/second_cal_service.go | 4 +- 3 files changed, 33 insertions(+), 72 deletions(-) delete mode 100644 internal/service/limit_board_break_next_performance_service_test.go diff --git a/internal/service/limit_board_break_next_performance_service.go b/internal/service/limit_board_break_next_performance_service.go index d803f07..e3cb27a 100644 --- a/internal/service/limit_board_break_next_performance_service.go +++ b/internal/service/limit_board_break_next_performance_service.go @@ -2,6 +2,7 @@ package service import ( "math" + "strconv" "strings" "level_go/internal/model" @@ -193,7 +194,7 @@ func buildLimitBreakNextPerformanceStock(row limitBreakNextPerformanceRow) model if row.FirstTime != nil { item.FirstTime = formatLimitTime(*row.FirstTime) } - item.BreakTimeBefore1100 = isLimitBreakTimeBeforeEleven(item.FirstTime) + item.BreakTimeBefore1100 = isLimitBreakTimeBeforeTen(item.FirstTime) if row.TPreClose != nil && *row.TPreClose > 0 { // T 日开盘涨幅以 T 日前收为基准,低于 101% 用于筛选低开/小幅高开炸板。 item.TOpenPctChg = pctChangePtr(row.TOpen, *row.TPreClose) @@ -251,12 +252,38 @@ func formatLimitTime(value string) string { return timeText[0:2] + ":" + timeText[2:4] + ":" + timeText[4:6] } -// isLimitBreakTimeBeforeEleven 判断炸板时间是否早于 11:00。 +// isLimitBreakTimeBeforeTen 判断炸板时间是否早于 10:00。 // // 空时间在当前业务中视为满足条件,保持历史接口行为。 -func isLimitBreakTimeBeforeEleven(limitTime string) bool { +func isLimitBreakTimeBeforeTen(limitTime string) bool { if strings.TrimSpace(limitTime) == "" { return true } - return isBeforeEleven(&limitTime) + + timeText := formatLimitTime(limitTime) + parts := strings.Split(timeText, ":") + if len(parts) < 2 || len(parts) > 3 { + return false + } + + hour, err := strconv.Atoi(parts[0]) + if err != nil { + return false + } + minute, err := strconv.Atoi(parts[1]) + if err != nil { + return false + } + second := 0 + if len(parts) == 3 { + second, err = strconv.Atoi(parts[2]) + if err != nil { + return false + } + } + if hour < 0 || hour > 23 || minute < 0 || minute > 59 || second < 0 || second > 59 { + return false + } + + return hour < 10 } diff --git a/internal/service/limit_board_break_next_performance_service_test.go b/internal/service/limit_board_break_next_performance_service_test.go deleted file mode 100644 index fc7df0a..0000000 --- a/internal/service/limit_board_break_next_performance_service_test.go +++ /dev/null @@ -1,66 +0,0 @@ -package service - -import "testing" - -// TestBuildLimitBreakNextPerformanceStockIntradayProfitableUsesTHigh 验证 T+1 盘中可盈利口径。 -// -// 业务要求用 T+1 最高价覆盖 T 日最高价来判断是否可解套,而不是只和 T 日收盘价比较。 -func TestBuildLimitBreakNextPerformanceStockIntradayProfitableUsesTHigh(t *testing.T) { - tClose := 9.50 - tHigh := 10.00 - - tests := []struct { - name string - nextHigh *float64 - want *bool - }{ - { - name: "next high below T high cannot cover T high buy loss", - nextHigh: float64Ptr(9.99), - want: boolPtr(false), - }, - { - name: "next high equal T high covers T high buy loss", - nextHigh: float64Ptr(10.00), - want: boolPtr(true), - }, - { - name: "missing next high returns nil", - nextHigh: nil, - want: nil, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - item := buildLimitBreakNextPerformanceStock(limitBreakNextPerformanceRow{ - TClose: &tClose, - THigh: &tHigh, - NextHigh: tt.nextHigh, - }) - - if tt.want == nil { - if item.NextIntradayProfitable != nil { - t.Fatalf("NextIntradayProfitable = %v, want nil", *item.NextIntradayProfitable) - } - return - } - if item.NextIntradayProfitable == nil { - t.Fatalf("NextIntradayProfitable = nil, want %v", *tt.want) - } - if *item.NextIntradayProfitable != *tt.want { - t.Fatalf("NextIntradayProfitable = %v, want %v", *item.NextIntradayProfitable, *tt.want) - } - }) - } -} - -// float64Ptr 是测试用指针辅助函数。 -func float64Ptr(value float64) *float64 { - return &value -} - -// boolPtr 是测试用指针辅助函数。 -func boolPtr(value bool) *bool { - return &value -} diff --git a/internal/service/second_cal_service.go b/internal/service/second_cal_service.go index 70e818a..25acbd1 100644 --- a/internal/service/second_cal_service.go +++ b/internal/service/second_cal_service.go @@ -167,9 +167,9 @@ candidate AS ( LEFT JOIN limit_list_d ppl ON ppl.ts_code = pl.ts_code AND ppl.trade_date = c.previous_two_trade_date AND ppl.` + "`limit`" + ` = 'U' INNER JOIN stock_daily d - ON d.ts_code = pl.ts_code AND d.trade_date = c.trade_date + ON d.ts_code = pl.ts_code COLLATE utf8mb4_0900_ai_ci AND d.trade_date = c.trade_date LEFT JOIN stock_daily nd - ON nd.ts_code = pl.ts_code AND nd.trade_date = c.next_trade_date + ON nd.ts_code = pl.ts_code COLLATE utf8mb4_0900_ai_ci AND nd.trade_date = c.next_trade_date LEFT JOIN stock_basic sb ON sb.ts_code = pl.ts_code COLLATE utf8mb4_unicode_ci WHERE c.trade_date BETWEEN ? AND ?