修正逻辑
This commit is contained in:
@@ -21,6 +21,6 @@ type AnalysisResponse struct {
|
|||||||
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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user