package service import ( "level_go/internal/model" "math" "sort" "gorm.io/gorm" ) type StockService struct { DB *gorm.DB } func roundTo4(val float64) float64 { return math.Round(val*10000) / 10000 } func (s *StockService) AnalyzePerformance(startDate, endDate string) ([]model.AnalysisResponse, error) { var results []model.AnalysisResponse var limits []struct { TsCode string Name string Open float64 High float64 } // 1. 查找涨停股票 query := ` SELECT l.ts_code, l.name, d.open, d.high FROM stock_limit_data l LEFT JOIN stock_daily d ON l.ts_code = d.ts_code AND l.trade_date = d.trade_date WHERE l.trade_date = ? AND l.status = 1` if err := s.DB.Raw(query, startDate).Scan(&limits).Error; err != nil { return nil, err } // 2. 分析区间数据 for _, stock := range limits { var dailies []model.StockDaily s.DB.Where("ts_code = ? AND trade_date BETWEEN ? AND ?", stock.TsCode, startDate, endDate). Order("trade_date ASC").Find(&dailies) if len(dailies) == 0 { continue } // A. 找最高点 maxPrice := -1.0 maxIdx := 0 for i, d := range dailies { if d.High >= maxPrice { maxPrice = d.High maxIdx = i } } // B. 找最高点后的最低点 postData := dailies[maxIdx+1:] var minLow, dropPct, reboundPct float64 if len(postData) > 0 { minLow = postData[0].Low for _, p := range postData { if p.Low < minLow { minLow = p.Low } } lastClose := postData[len(postData)-1].Close dropPct = roundTo4(((maxPrice - minLow) / maxPrice) * 100) if minLow > 0 { reboundPct = roundTo4(((lastClose - minLow) / minLow) * 100) } } results = append(results, model.AnalysisResponse{ Code: stock.TsCode, Name: stock.Name, DayOpen: stock.Open, DayHigh: stock.High, MaxHigh: maxPrice, MaxDate: dailies[maxIdx].TradeDate.Format("2006-01-02"), PostMinLow: minLow, DropPct: dropPct, ReboundPct: reboundPct, }) } // 3. 按降幅排序 sort.Slice(results, func(i, j int) bool { return results[i].DropPct > results[j].DropPct }) return results, nil }