适配mysql
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"level_go/internal/dbcompat"
|
||||
"level_go/internal/model"
|
||||
)
|
||||
|
||||
@@ -104,17 +105,18 @@ func (s *LimitBoardService) ListLimitBreakNextPerformanceStocks(req model.LimitB
|
||||
//
|
||||
// 口径:前一交易日涨停、前两交易日未涨停、当前交易日 final_status = 2。
|
||||
func (s *LimitBoardService) loadLimitBreakNextPerformanceRows(startDate, endDate string) ([]limitBreakNextPerformanceRow, error) {
|
||||
seeds, err := dbcompat.LoadSSEOpenCalendarSeeds(s.DB, startDate, endDate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(seeds) == 0 {
|
||||
return []limitBreakNextPerformanceRow{}, nil
|
||||
}
|
||||
calendarTable, calendarArgs := dbcompat.CalendarSeedTable(seeds)
|
||||
|
||||
query := `
|
||||
WITH open_calendar AS (
|
||||
SELECT
|
||||
cal_date AS trade_date,
|
||||
LAG(cal_date, 1) OVER (ORDER BY cal_date) AS previous_trade_date,
|
||||
LAG(cal_date, 2) OVER (ORDER BY cal_date) AS previous_two_trade_date,
|
||||
LEAD(cal_date, 1) OVER (ORDER BY cal_date) AS next_trade_date
|
||||
FROM trade_calendar
|
||||
WHERE exchange = 'SSE' AND is_open = 1
|
||||
),
|
||||
candidate AS (
|
||||
SELECT *
|
||||
FROM (
|
||||
SELECT
|
||||
DATE_FORMAT(c.trade_date, '%Y-%m-%d') AS trade_date,
|
||||
DATE_FORMAT(c.previous_trade_date, '%Y-%m-%d') AS previous_trade_date,
|
||||
@@ -141,34 +143,31 @@ candidate AS (
|
||||
nd.high AS next_high,
|
||||
nd.low AS next_low,
|
||||
nd.close AS next_close
|
||||
FROM open_calendar c
|
||||
FROM (` + calendarTable + `) c
|
||||
INNER JOIN stock_limit_combined_data l
|
||||
ON l.trade_date = c.trade_date AND l.final_status = 2
|
||||
INNER JOIN stock_limit_combined_data pl
|
||||
ON pl.ts_code = l.ts_code AND pl.trade_date = c.previous_trade_date AND pl.final_status = 1
|
||||
ON ` + dbcompat.TsCodeEqual("pl.ts_code", "l.ts_code") + ` AND pl.trade_date = c.previous_trade_date AND pl.final_status = 1
|
||||
LEFT JOIN stock_limit_combined_data ppl
|
||||
ON ppl.ts_code = l.ts_code AND ppl.trade_date = c.previous_two_trade_date AND ppl.final_status = 1
|
||||
ON ` + dbcompat.TsCodeEqual("ppl.ts_code", "l.ts_code") + ` AND ppl.trade_date = c.previous_two_trade_date AND ppl.final_status = 1
|
||||
LEFT JOIN stock_daily d
|
||||
ON d.ts_code = l.ts_code AND d.trade_date = c.trade_date
|
||||
ON ` + dbcompat.TsCodeEqual("d.ts_code", "l.ts_code") + ` AND d.trade_date = c.trade_date
|
||||
LEFT JOIN stock_daily pd
|
||||
ON pd.ts_code = l.ts_code AND pd.trade_date = c.previous_trade_date
|
||||
ON ` + dbcompat.TsCodeEqual("pd.ts_code", "l.ts_code") + ` AND pd.trade_date = c.previous_trade_date
|
||||
LEFT JOIN stock_daily nd
|
||||
ON nd.ts_code = l.ts_code AND nd.trade_date = c.next_trade_date
|
||||
ON ` + dbcompat.TsCodeEqual("nd.ts_code", "l.ts_code") + ` AND nd.trade_date = c.next_trade_date
|
||||
LEFT JOIN stock_basic sb
|
||||
ON sb.ts_code = l.ts_code COLLATE utf8mb4_unicode_ci
|
||||
WHERE c.trade_date BETWEEN ? AND ?
|
||||
AND c.previous_trade_date IS NOT NULL
|
||||
ON ` + dbcompat.TsCodeEqualUnicode("sb.ts_code", "l.ts_code") + `
|
||||
WHERE c.previous_trade_date IS NOT NULL
|
||||
AND c.previous_two_trade_date IS NOT NULL
|
||||
AND ppl.ts_code IS NULL
|
||||
)
|
||||
SELECT *
|
||||
FROM candidate
|
||||
) candidate
|
||||
WHERE previous_close IS NOT NULL
|
||||
AND t_close IS NOT NULL
|
||||
ORDER BY trade_date ASC, ts_code ASC`
|
||||
|
||||
var rows []limitBreakNextPerformanceRow
|
||||
err := s.DB.Raw(query, startDate, endDate).Scan(&rows).Error
|
||||
err = s.DB.Raw(query, calendarArgs...).Scan(&rows).Error
|
||||
return rows, err
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"level_go/internal/dbcompat"
|
||||
"level_go/internal/model"
|
||||
)
|
||||
|
||||
@@ -146,7 +147,7 @@ func (s *LimitBoardService) loadLimitOpenCompareStocks(tradeDate, previousTradeD
|
||||
(? <> '' AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM stock_limit_combined_data ppl
|
||||
WHERE ppl.ts_code = l.ts_code AND ppl.trade_date = ? AND ppl.final_status = 1
|
||||
WHERE ` + dbcompat.TsCodeEqual("ppl.ts_code", "l.ts_code") + ` AND ppl.trade_date = ? AND ppl.final_status = 1
|
||||
)) AS is_first_to_second_board,
|
||||
COALESCE(l.calc_limit_price, 0) AS limit_price,
|
||||
COALESCE(l.tushare_pct_chg, d.pct_chg, 0) AS pct_chg,
|
||||
@@ -164,11 +165,11 @@ func (s *LimitBoardService) loadLimitOpenCompareStocks(tradeDate, previousTradeD
|
||||
l.calc_vol AS vol
|
||||
FROM stock_limit_combined_data l
|
||||
LEFT JOIN stock_daily d
|
||||
ON l.ts_code = d.ts_code AND d.trade_date = l.trade_date
|
||||
ON ` + dbcompat.TsCodeEqual("l.ts_code", "d.ts_code") + ` AND d.trade_date = l.trade_date
|
||||
LEFT JOIN stock_daily pd
|
||||
ON l.ts_code = pd.ts_code AND pd.trade_date = ?
|
||||
ON ` + dbcompat.TsCodeEqual("l.ts_code", "pd.ts_code") + ` AND pd.trade_date = ?
|
||||
INNER JOIN stock_limit_combined_data pl
|
||||
ON pl.ts_code = l.ts_code AND pl.trade_date = ? AND pl.final_status = 1
|
||||
ON ` + dbcompat.TsCodeEqual("pl.ts_code", "l.ts_code") + ` AND pl.trade_date = ? AND pl.final_status = 1
|
||||
WHERE l.trade_date = ? AND l.final_status = 1
|
||||
ORDER BY d.pct_chg DESC, l.ts_code ASC`
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package service
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"level_go/internal/dbcompat"
|
||||
"level_go/internal/model"
|
||||
)
|
||||
|
||||
@@ -93,11 +94,11 @@ func (s *LimitBoardService) loadLimitOpenThresholdStocks(tradeDate, previousTrad
|
||||
l.calc_vol AS vol
|
||||
FROM stock_limit_combined_data l
|
||||
LEFT JOIN stock_daily d
|
||||
ON l.ts_code = d.ts_code AND d.trade_date = l.trade_date
|
||||
ON ` + dbcompat.TsCodeEqual("l.ts_code", "d.ts_code") + ` AND d.trade_date = l.trade_date
|
||||
LEFT JOIN stock_daily pd
|
||||
ON l.ts_code = pd.ts_code AND pd.trade_date = ?
|
||||
ON ` + dbcompat.TsCodeEqual("l.ts_code", "pd.ts_code") + ` AND pd.trade_date = ?
|
||||
INNER JOIN stock_limit_combined_data pl
|
||||
ON pl.ts_code = l.ts_code AND pl.trade_date = ? AND pl.final_status = 1
|
||||
ON ` + dbcompat.TsCodeEqual("pl.ts_code", "l.ts_code") + ` AND pl.trade_date = ? AND pl.final_status = 1
|
||||
WHERE l.trade_date = ? AND l.final_status = 1
|
||||
ORDER BY d.pct_chg DESC, l.ts_code ASC`
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package service
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"level_go/internal/dbcompat"
|
||||
"level_go/internal/model"
|
||||
)
|
||||
|
||||
@@ -146,7 +147,7 @@ func (s *LimitBoardService) loadCurrentLimitStocks(tradeDate string) ([]model.Li
|
||||
l.calc_vol AS vol
|
||||
FROM stock_limit_combined_data l
|
||||
LEFT JOIN stock_daily d
|
||||
ON l.ts_code = d.ts_code AND d.trade_date = l.trade_date
|
||||
ON ` + dbcompat.TsCodeEqual("l.ts_code", "d.ts_code") + ` AND d.trade_date = l.trade_date
|
||||
WHERE l.trade_date = ? AND l.final_status = 1
|
||||
ORDER BY d.pct_chg DESC, l.ts_code ASC`
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package service
|
||||
import (
|
||||
"math"
|
||||
|
||||
"level_go/internal/dbcompat"
|
||||
"level_go/internal/model"
|
||||
)
|
||||
|
||||
@@ -23,6 +24,8 @@ type secondCalRow struct {
|
||||
TClose *float64 `gorm:"column:t_close"` // T 日收盘价。
|
||||
TPctChg *float64 `gorm:"column:t_pct_chg"` // T 日收盘涨跌幅。
|
||||
Status string `gorm:"column:status"` // T 日二板状态。
|
||||
FirstLimitTime *string `gorm:"column:first_limit_time"` // T 日首次涨停时间。
|
||||
OpenTimes *int `gorm:"column:open_times"` // T 日开板次数。
|
||||
NextHigh *float64 `gorm:"column:next_high"` // T+1 日最高价。
|
||||
NextClose *float64 `gorm:"column:next_close"` // T+1 日收盘价。
|
||||
}
|
||||
@@ -85,29 +88,19 @@ func (s *LimitBoardService) GetSecondCal(req model.SecondCalRequest) (model.Seco
|
||||
|
||||
// loadSecondCalDays 查询日期范围内的开市交易日和相邻交易日。
|
||||
func (s *LimitBoardService) loadSecondCalDays(startDate, endDate string) ([]secondCalDaySeed, map[string]int, error) {
|
||||
query := `
|
||||
WITH open_calendar AS (
|
||||
SELECT
|
||||
cal_date AS trade_date,
|
||||
LAG(cal_date, 1) OVER (ORDER BY cal_date) AS previous_trade_date,
|
||||
LAG(cal_date, 2) OVER (ORDER BY cal_date) AS previous_two_trade_date,
|
||||
LEAD(cal_date, 1) OVER (ORDER BY cal_date) AS next_trade_date
|
||||
FROM trade_calendar
|
||||
WHERE exchange = 'SSE' AND is_open = 1
|
||||
)
|
||||
SELECT
|
||||
DATE_FORMAT(trade_date, '%Y-%m-%d') AS trade_date,
|
||||
COALESCE(DATE_FORMAT(previous_trade_date, '%Y-%m-%d'), '') AS previous_trade_date,
|
||||
COALESCE(DATE_FORMAT(previous_two_trade_date, '%Y-%m-%d'), '') AS previous_two_trade_date,
|
||||
COALESCE(DATE_FORMAT(next_trade_date, '%Y-%m-%d'), '') AS next_trade_date
|
||||
FROM open_calendar
|
||||
WHERE trade_date BETWEEN ? AND ?
|
||||
ORDER BY trade_date ASC`
|
||||
|
||||
var days []secondCalDaySeed
|
||||
if err := s.DB.Raw(query, startDate, endDate).Scan(&days).Error; err != nil {
|
||||
seeds, err := dbcompat.LoadSSEOpenCalendarSeeds(s.DB, startDate, endDate)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
days := make([]secondCalDaySeed, 0, len(seeds))
|
||||
for _, seed := range seeds {
|
||||
days = append(days, secondCalDaySeed{
|
||||
TradeDate: seed.TradeDate,
|
||||
PreviousTradeDate: seed.PreviousTradeDate,
|
||||
PreviousTwoTradeDate: seed.PreviousTwoTradeDate,
|
||||
NextTradeDate: seed.NextTradeDate,
|
||||
})
|
||||
}
|
||||
|
||||
// 构建交易日到响应数组下标的映射,后续聚合明细时可以 O(1) 定位。
|
||||
dayIndex := make(map[string]int, len(days))
|
||||
@@ -119,17 +112,41 @@ ORDER BY trade_date ASC`
|
||||
|
||||
// loadSecondCalRows 查询 T-1 涨停、T-2 未涨停、T 日再次触及涨停价的二板股票。
|
||||
func (s *LimitBoardService) loadSecondCalRows(startDate, endDate string) ([]secondCalRow, error) {
|
||||
seeds, err := dbcompat.LoadSSEOpenCalendarSeeds(s.DB, startDate, endDate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(seeds) == 0 {
|
||||
return []secondCalRow{}, nil
|
||||
}
|
||||
calendarTable, calendarArgs := dbcompat.CalendarSeedTable(seeds)
|
||||
stockDailyTsCodeCollation, err := dbcompat.ColumnCollation(s.DB, "stock_daily", "ts_code")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
query := `
|
||||
WITH open_calendar AS (
|
||||
SELECT
|
||||
cal_date AS trade_date,
|
||||
LAG(cal_date, 1) OVER (ORDER BY cal_date) AS previous_trade_date,
|
||||
LAG(cal_date, 2) OVER (ORDER BY cal_date) AS previous_two_trade_date,
|
||||
LEAD(cal_date, 1) OVER (ORDER BY cal_date) AS next_trade_date
|
||||
FROM trade_calendar
|
||||
WHERE exchange = 'SSE' AND is_open = 1
|
||||
),
|
||||
candidate AS (
|
||||
SELECT
|
||||
DATE_FORMAT(trade_date, '%Y-%m-%d') AS trade_date,
|
||||
DATE_FORMAT(previous_trade_date, '%Y-%m-%d') AS previous_trade_date,
|
||||
DATE_FORMAT(previous_two_trade_date, '%Y-%m-%d') AS previous_two_trade_date,
|
||||
COALESCE(DATE_FORMAT(next_trade_date, '%Y-%m-%d'), '') AS next_trade_date,
|
||||
COALESCE(symbol, '') AS symbol,
|
||||
ts_code,
|
||||
name,
|
||||
market,
|
||||
industry,
|
||||
previous_close,
|
||||
limit_price,
|
||||
t_high,
|
||||
t_close,
|
||||
t_pct_chg,
|
||||
status,
|
||||
first_limit_time,
|
||||
open_times,
|
||||
next_high,
|
||||
next_close
|
||||
FROM (
|
||||
SELECT
|
||||
c.trade_date,
|
||||
c.previous_trade_date,
|
||||
@@ -159,45 +176,41 @@ candidate AS (
|
||||
WHEN d.close < d.high THEN 'break'
|
||||
ELSE 'unknown'
|
||||
END AS status,
|
||||
CASE
|
||||
WHEN ABS(d.close - d.high) < 0.0001
|
||||
THEN NULLIF(NULLIF(TRIM(tlu.first_time), ''), 'None')
|
||||
WHEN d.close < d.high
|
||||
THEN NULLIF(NULLIF(TRIM(tlz.first_time), ''), 'None')
|
||||
ELSE NULL
|
||||
END AS first_limit_time,
|
||||
CASE
|
||||
WHEN ABS(d.close - d.high) < 0.0001 THEN tlu.open_times
|
||||
WHEN d.close < d.high THEN tlz.open_times
|
||||
ELSE NULL
|
||||
END AS open_times,
|
||||
nd.high AS next_high,
|
||||
nd.close AS next_close
|
||||
FROM open_calendar c
|
||||
FROM (` + calendarTable + `) c
|
||||
INNER JOIN limit_list_d pl
|
||||
ON pl.trade_date = c.previous_trade_date AND pl.` + "`limit`" + ` = 'U'
|
||||
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'
|
||||
ON ` + dbcompat.TsCodeEqual("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 COLLATE utf8mb4_0900_ai_ci AND d.trade_date = c.trade_date
|
||||
ON ` + dbcompat.TsCodeEqualRightCollation("d.ts_code", "pl.ts_code", stockDailyTsCodeCollation) + ` AND d.trade_date = c.trade_date
|
||||
LEFT JOIN stock_daily nd
|
||||
ON nd.ts_code = pl.ts_code COLLATE utf8mb4_0900_ai_ci AND nd.trade_date = c.next_trade_date
|
||||
ON ` + dbcompat.TsCodeEqualRightCollation("nd.ts_code", "pl.ts_code", stockDailyTsCodeCollation) + ` AND nd.trade_date = c.next_trade_date
|
||||
LEFT JOIN limit_list_d tlu
|
||||
ON ` + dbcompat.TsCodeEqual("tlu.ts_code", "pl.ts_code") + ` AND tlu.trade_date = c.trade_date AND tlu.` + "`limit`" + ` = 'U'
|
||||
LEFT JOIN limit_list_d tlz
|
||||
ON ` + dbcompat.TsCodeEqual("tlz.ts_code", "pl.ts_code") + ` AND tlz.trade_date = c.trade_date AND tlz.` + "`limit`" + ` = 'Z'
|
||||
LEFT JOIN stock_basic sb
|
||||
ON sb.ts_code = pl.ts_code COLLATE utf8mb4_unicode_ci
|
||||
WHERE c.trade_date BETWEEN ? AND ?
|
||||
AND c.previous_trade_date IS NOT NULL
|
||||
ON ` + dbcompat.TsCodeEqual("sb.ts_code", "pl.ts_code") + `
|
||||
WHERE c.previous_trade_date IS NOT NULL
|
||||
AND c.previous_two_trade_date IS NOT NULL
|
||||
AND ppl.ts_code IS NULL
|
||||
AND d.high IS NOT NULL
|
||||
AND d.close IS NOT NULL
|
||||
)
|
||||
SELECT
|
||||
DATE_FORMAT(trade_date, '%Y-%m-%d') AS trade_date,
|
||||
DATE_FORMAT(previous_trade_date, '%Y-%m-%d') AS previous_trade_date,
|
||||
DATE_FORMAT(previous_two_trade_date, '%Y-%m-%d') AS previous_two_trade_date,
|
||||
COALESCE(DATE_FORMAT(next_trade_date, '%Y-%m-%d'), '') AS next_trade_date,
|
||||
COALESCE(symbol, '') AS symbol,
|
||||
ts_code,
|
||||
name,
|
||||
market,
|
||||
industry,
|
||||
previous_close,
|
||||
limit_price,
|
||||
t_high,
|
||||
t_close,
|
||||
t_pct_chg,
|
||||
status,
|
||||
next_high,
|
||||
next_close
|
||||
FROM candidate
|
||||
) candidate
|
||||
WHERE previous_close IS NOT NULL
|
||||
AND limit_price IS NOT NULL
|
||||
AND limit_price > 0
|
||||
@@ -206,7 +219,7 @@ WHERE previous_close IS NOT NULL
|
||||
ORDER BY trade_date ASC, ts_code ASC`
|
||||
|
||||
var rows []secondCalRow
|
||||
err := s.DB.Raw(query, startDate, endDate).Scan(&rows).Error
|
||||
err = s.DB.Raw(query, calendarArgs...).Scan(&rows).Error
|
||||
return rows, err
|
||||
}
|
||||
|
||||
@@ -228,9 +241,13 @@ func buildSecondCalStock(row secondCalRow) model.SecondCalStock {
|
||||
TClose: row.TClose,
|
||||
TPctChg: row.TPctChg,
|
||||
Status: row.Status,
|
||||
OpenTimes: row.OpenTimes,
|
||||
NextHigh: row.NextHigh,
|
||||
NextClose: row.NextClose,
|
||||
}
|
||||
if row.FirstLimitTime != nil {
|
||||
item.FirstLimitTime = formatLimitTime(*row.FirstLimitTime)
|
||||
}
|
||||
|
||||
if row.THigh != nil && *row.THigh > 0 && row.NextHigh != nil {
|
||||
// T+1 盘中盈利统一按 T+1 最高价是否高于 T 日最高价判断。
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"sort"
|
||||
|
||||
"gorm.io/gorm"
|
||||
"level_go/internal/dbcompat"
|
||||
"level_go/internal/model"
|
||||
)
|
||||
|
||||
@@ -45,7 +46,7 @@ func (s *StockService) AnalyzePerformance(startDate, endDate string) ([]model.An
|
||||
|
||||
// 查询 startDate 当日涨停股,并优先使用涨停合并表中的计算最高价。
|
||||
query := `SELECT l.ts_code, l.name, d.open, COALESCE(l.calc_high, d.high, 0) AS high FROM stock_limit_combined_data l
|
||||
LEFT JOIN stock_daily d ON l.ts_code = d.ts_code AND l.trade_date = d.trade_date
|
||||
LEFT JOIN stock_daily d ON ` + dbcompat.TsCodeEqual("l.ts_code", "d.ts_code") + ` AND l.trade_date = d.trade_date
|
||||
WHERE l.trade_date = ? AND l.final_status = 1`
|
||||
|
||||
if err := s.DB.Raw(query, startDate).Scan(&limits).Error; err != nil {
|
||||
|
||||
Reference in New Issue
Block a user