修正逻辑

This commit is contained in:
2026-04-25 15:11:19 +08:00
parent 6d1611d08c
commit 95bf0c3342
2 changed files with 61 additions and 30 deletions
+9 -9
View File
@@ -14,13 +14,13 @@ type StockDaily struct {
func (StockDaily) TableName() string { return "stock_daily" } func (StockDaily) TableName() string { return "stock_daily" }
type AnalysisResponse struct { type AnalysisResponse struct {
Code string `json:"code"` Code string `json:"code"`
Name string `json:"name"` Name string `json:"name"`
DayOpen float64 `json:"day_open"` DayOpen float64 `json:"day_open"`
DayHigh float64 `json:"day_high"` DayHigh float64 `json:"day_high"`
MaxHigh float64 `json:"max_high"` MaxHigh float64 `json:"max_high"`
MaxDate string `json:"max_date"` MaxDate string `json:"max_date"`
PostMinLow float64 `json:"post_min_low"` PostMinLow float64 `json:"post_min_low"`
DropPct float64 `json:"drop_pct"` DropPct *float64 `json:"drop_pct"` // 改为指针以支持 null
ReboundPct float64 `json:"rebound_pct"` ReboundPct *float64 `json:"rebound_pct"` // 改为指针以支持 null
} }
+52 -21
View File
@@ -18,7 +18,6 @@ func roundTo4(val float64) float64 {
func (s *StockService) AnalyzePerformance(startDate, endDate string) ([]model.AnalysisResponse, error) { func (s *StockService) AnalyzePerformance(startDate, endDate string) ([]model.AnalysisResponse, error) {
var results []model.AnalysisResponse var results []model.AnalysisResponse
var limits []struct { var limits []struct {
TsCode string TsCode string
Name string Name string
@@ -26,7 +25,7 @@ func (s *StockService) AnalyzePerformance(startDate, endDate string) ([]model.An
High float64 High float64
} }
// 1. 查找涨停股票 // 1. 获取选定日期当天涨停的股票
query := ` query := `
SELECT l.ts_code, l.name, d.open, d.high SELECT l.ts_code, l.name, d.open, d.high
FROM stock_limit_data l FROM stock_limit_data l
@@ -37,7 +36,6 @@ func (s *StockService) AnalyzePerformance(startDate, endDate string) ([]model.An
return nil, err return nil, err
} }
// 2. 分析区间数据
for _, stock := range limits { for _, stock := range limits {
var dailies []model.StockDaily var dailies []model.StockDaily
s.DB.Where("ts_code = ? AND trade_date BETWEEN ? AND ?", stock.TsCode, startDate, endDate). s.DB.Where("ts_code = ? AND trade_date BETWEEN ? AND ?", stock.TsCode, startDate, endDate).
@@ -47,31 +45,57 @@ func (s *StockService) AnalyzePerformance(startDate, endDate string) ([]model.An
continue continue
} }
// A. 找最高点 // --- 步骤 1:寻找全区间的最高点 (MaxHigh) ---
maxPrice := -1.0 maxPrice := -1.0
maxIdx := 0 maxIdx := 0
for i, d := range dailies { for i, d := range dailies {
if d.High >= maxPrice { if d.High > maxPrice {
maxPrice = d.High maxPrice = d.High
maxIdx = i maxIdx = i
} }
} }
// B. 找最高点后的最低点 var dropPct, reboundPct *float64
postData := dailies[maxIdx+1:] var postMinLow float64
var minLow, dropPct, reboundPct float64 maxDateStr := dailies[maxIdx].TradeDate.Format("2006-01-02")
if len(postData) > 0 { // --- 步骤 2:寻找最高点之后的最低点 (PostMinLow) ---
minLow = postData[0].Low if maxIdx < len(dailies)-1 {
for _, p := range postData { postMaxData := dailies[maxIdx+1:]
if p.Low < minLow { minLow := postMaxData[0].Low
minLow = p.Low minLowIdx := 0
for i, d := range postMaxData {
if d.Low < minLow {
minLow = d.Low
minLowIdx = i
} }
} }
lastClose := postData[len(postData)-1].Close postMinLow = minLow
dropPct = roundTo4(((maxPrice - minLow) / maxPrice) * 100)
if minLow > 0 { // 只要出现比 MaxHigh 低的价格,就计算回落幅度
reboundPct = roundTo4(((lastClose - minLow) / minLow) * 100) if minLow < maxPrice {
dVal := roundTo4(((maxPrice - minLow) / maxPrice) * 100)
dropPct = &dVal
// --- 步骤 3:寻找最低点之后的反弹 ---
if minLowIdx < len(postMaxData)-1 {
lastClose := postMaxData[len(postMaxData)-1].Close
if lastClose > minLow {
rVal := roundTo4(((lastClose - minLow) / minLow) * 100)
reboundPct = &rVal
}
}
}
}
// --- 步骤 4:处理特殊形态(如持续上涨无回落) ---
if dropPct == nil {
lastClose := dailies[len(dailies)-1].Close
firstDayHigh := dailies[0].High
if lastClose > firstDayHigh {
rVal := roundTo4(((lastClose - firstDayHigh) / firstDayHigh) * 100)
reboundPct = &rVal
} }
} }
@@ -81,16 +105,23 @@ func (s *StockService) AnalyzePerformance(startDate, endDate string) ([]model.An
DayOpen: stock.Open, DayOpen: stock.Open,
DayHigh: stock.High, DayHigh: stock.High,
MaxHigh: maxPrice, MaxHigh: maxPrice,
MaxDate: dailies[maxIdx].TradeDate.Format("2006-01-02"), MaxDate: maxDateStr,
PostMinLow: minLow, PostMinLow: postMinLow,
DropPct: dropPct, DropPct: dropPct,
ReboundPct: reboundPct, ReboundPct: reboundPct,
}) })
} }
// 3. 按降幅排序 // 5. 基础排序(仅按回落幅度降序,不处理 null 特殊逻辑)
sort.Slice(results, func(i, j int) bool { sort.Slice(results, func(i, j int) bool {
return results[i].DropPct > results[j].DropPct valI, valJ := -1.0, -1.0
if results[i].DropPct != nil {
valI = *results[i].DropPct
}
if results[j].DropPct != nil {
valJ = *results[j].DropPct
}
return valI > valJ
}) })
return results, nil return results, nil