新增首二一一模型
This commit is contained in:
@@ -3,6 +3,8 @@ package service
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"gorm.io/gorm"
|
||||
"level_go/internal/model"
|
||||
@@ -82,6 +84,113 @@ func (s *LimitBoardService) GetLimitBoardOverview(tradeDate string) (model.Limit
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (s *LimitBoardService) GetLimitOpenCompareGroups(tradeDate string) (model.LimitOpenCompareResponse, error) {
|
||||
resp := model.LimitOpenCompareResponse{TradeDate: tradeDate}
|
||||
|
||||
tradeDates, dateIndex, err := s.loadTradeCalendar(tradeDate)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
if dateIndex == -1 {
|
||||
resp.Groups = buildLimitOpenCompareGroups(nil, nil)
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
previousTradeDate := ""
|
||||
if dateIndex > 0 {
|
||||
previousTradeDate = tradeDates[dateIndex-1]
|
||||
}
|
||||
resp.PreviousTradeDate = previousTradeDate
|
||||
|
||||
previousTwoTradeDate := ""
|
||||
if dateIndex > 1 {
|
||||
previousTwoTradeDate = tradeDates[dateIndex-2]
|
||||
}
|
||||
resp.PreviousTwoTradeDate = previousTwoTradeDate
|
||||
|
||||
stocks, err := s.loadLimitOpenCompareStocks(tradeDate, previousTradeDate, previousTwoTradeDate)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
openLowerStocks := make([]model.LimitOpenCompareStock, 0)
|
||||
otherStocks := make([]model.LimitOpenCompareStock, 0)
|
||||
firstToSecondBoardCount := 0
|
||||
firstSecondBeforeElevenCount := 0
|
||||
for _, stock := range stocks {
|
||||
if stock.IsFirstToSecondBoard {
|
||||
stock.HighlightLabel = "首板进二板"
|
||||
firstToSecondBoardCount++
|
||||
}
|
||||
isOpenLower := previousTradeDate != "" && stock.HasOpen && stock.HasPreviousClose && stock.Open < stock.PreviousClose
|
||||
if isOpenLower && stock.IsFirstToSecondBoard && isBeforeEleven(stock.AkFirstLimitTime) {
|
||||
stock.IsFirstSecondBeforeEleven = true
|
||||
stock.HighlightLabel = "首二一一"
|
||||
firstSecondBeforeElevenCount++
|
||||
}
|
||||
if isOpenLower {
|
||||
openLowerStocks = append(openLowerStocks, stock)
|
||||
continue
|
||||
}
|
||||
otherStocks = append(otherStocks, stock)
|
||||
}
|
||||
|
||||
resp.Summary = model.LimitOpenCompareSummary{
|
||||
LimitCount: len(stocks),
|
||||
OpenLowerPreviousCloseCount: len(openLowerStocks),
|
||||
OthersCount: len(otherStocks),
|
||||
FirstToSecondBoardCount: firstToSecondBoardCount,
|
||||
FirstSecondBeforeElevenCount: firstSecondBeforeElevenCount,
|
||||
}
|
||||
resp.Groups = buildLimitOpenCompareGroups(openLowerStocks, otherStocks)
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func isBeforeEleven(limitTime *string) bool {
|
||||
if limitTime == nil || *limitTime == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
timeText := strings.TrimSpace(*limitTime)
|
||||
hour := 0
|
||||
minute := 0
|
||||
second := 0
|
||||
if strings.Contains(timeText, ":") {
|
||||
if n, _ := fmt.Sscanf(timeText, "%d:%d:%d", &hour, &minute, &second); n < 2 {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
if len(timeText) < 4 {
|
||||
return false
|
||||
}
|
||||
if len(timeText) == 4 {
|
||||
timeText += "00"
|
||||
}
|
||||
if len(timeText) != 6 {
|
||||
return false
|
||||
}
|
||||
var err error
|
||||
hour, err = strconv.Atoi(timeText[0:2])
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
minute, err = strconv.Atoi(timeText[2:4])
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
second, err = strconv.Atoi(timeText[4:6])
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if hour < 0 || hour > 23 || minute < 0 || minute > 59 || second < 0 || second > 59 {
|
||||
return false
|
||||
}
|
||||
|
||||
return hour < 11
|
||||
}
|
||||
|
||||
func (s *LimitBoardService) buildRecentMaxBoardStats(tradeDates []string, dateIndex int) ([]model.LimitBoardDailyMax, error) {
|
||||
startIndex := 0
|
||||
if dateIndex >= 29 {
|
||||
@@ -199,6 +308,58 @@ func (s *LimitBoardService) loadCurrentLimitStocks(tradeDate string) ([]model.Li
|
||||
return stocks, err
|
||||
}
|
||||
|
||||
func (s *LimitBoardService) loadLimitOpenCompareStocks(tradeDate, previousTradeDate, previousTwoTradeDate string) ([]model.LimitOpenCompareStock, error) {
|
||||
var stocks []model.LimitOpenCompareStock
|
||||
query := `SELECT
|
||||
l.symbol,
|
||||
l.ts_code,
|
||||
l.name,
|
||||
COALESCE(l.market, '') AS market,
|
||||
DATE_FORMAT(l.trade_date, '%Y-%m-%d') AS trade_date,
|
||||
d.open IS NOT NULL AS has_open,
|
||||
COALESCE(d.open, 0) AS open,
|
||||
COALESCE(d.close, l.close, 0) AS close,
|
||||
? AS previous_trade_date,
|
||||
? AS previous_two_trade_date,
|
||||
pd.close IS NOT NULL AS has_previous_close,
|
||||
COALESCE(pd.close, 0) AS previous_close,
|
||||
(? <> '' AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM stock_limit_data ppl
|
||||
WHERE ppl.ts_code = l.ts_code AND ppl.trade_date = ? AND ppl.status = 1
|
||||
)) AS is_first_to_second_board,
|
||||
COALESCE(l.limit_price, 0) AS limit_price,
|
||||
COALESCE(d.pct_chg, 0) AS pct_chg,
|
||||
l.ak_amount,
|
||||
l.ak_float_market_value,
|
||||
l.ak_total_market_value,
|
||||
l.ak_turnover_rate,
|
||||
l.ak_seal_amount,
|
||||
l.ak_first_limit_time,
|
||||
l.ak_last_limit_time,
|
||||
l.ak_break_limit_count,
|
||||
l.ak_limit_up_stat,
|
||||
l.ak_limit_up_days,
|
||||
l.ak_industry,
|
||||
l.vol
|
||||
FROM stock_limit_data l
|
||||
LEFT JOIN stock_daily d
|
||||
ON d.ts_code = l.ts_code AND d.trade_date = l.trade_date
|
||||
LEFT JOIN stock_daily pd
|
||||
ON pd.ts_code = l.ts_code AND pd.trade_date = ?
|
||||
INNER JOIN stock_limit_data pl
|
||||
ON pl.ts_code = l.ts_code AND pl.trade_date = ? AND pl.status = 1
|
||||
WHERE l.trade_date = ? AND l.status = 1
|
||||
ORDER BY d.pct_chg DESC, l.ts_code ASC`
|
||||
|
||||
if previousTradeDate == "" {
|
||||
return stocks, nil
|
||||
}
|
||||
|
||||
err := s.DB.Raw(query, previousTradeDate, previousTwoTradeDate, previousTwoTradeDate, previousTwoTradeDate, previousTradeDate, previousTradeDate, tradeDate).Scan(&stocks).Error
|
||||
return stocks, err
|
||||
}
|
||||
|
||||
func (s *LimitBoardService) loadLimitHistory(stocks []model.LimitBoardStock, tradeDate string) (map[string]map[string]struct{}, error) {
|
||||
codes := make([]string, 0, len(stocks))
|
||||
for _, stock := range stocks {
|
||||
@@ -281,3 +442,39 @@ func sortLimitBoardGroups(groupMap map[int][]model.LimitBoardStock) []model.Limi
|
||||
|
||||
return groups
|
||||
}
|
||||
|
||||
func buildLimitOpenCompareGroups(openLowerStocks, otherStocks []model.LimitOpenCompareStock) []model.LimitOpenCompareGroup {
|
||||
if openLowerStocks == nil {
|
||||
openLowerStocks = []model.LimitOpenCompareStock{}
|
||||
}
|
||||
if otherStocks == nil {
|
||||
otherStocks = []model.LimitOpenCompareStock{}
|
||||
}
|
||||
|
||||
sortLimitOpenCompareStocks(openLowerStocks)
|
||||
sortLimitOpenCompareStocks(otherStocks)
|
||||
|
||||
return []model.LimitOpenCompareGroup{
|
||||
{
|
||||
Key: "open_lower_previous_close",
|
||||
Label: "开盘低于前收",
|
||||
Count: len(openLowerStocks),
|
||||
Stocks: openLowerStocks,
|
||||
},
|
||||
{
|
||||
Key: "others",
|
||||
Label: "其他涨停股",
|
||||
Count: len(otherStocks),
|
||||
Stocks: otherStocks,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func sortLimitOpenCompareStocks(stocks []model.LimitOpenCompareStock) {
|
||||
sort.Slice(stocks, func(i, j int) bool {
|
||||
if stocks[i].PctChg == stocks[j].PctChg {
|
||||
return stocks[i].TsCode < stocks[j].TsCode
|
||||
}
|
||||
return stocks[i].PctChg > stocks[j].PctChg
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user