136 lines
4.2 KiB
Go
136 lines
4.2 KiB
Go
|
|
package logic
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"errors"
|
|||
|
|
"fmt"
|
|||
|
|
"log"
|
|||
|
|
|
|||
|
|
"git.apinb.com/bsm-sdk/core/utils"
|
|||
|
|
"git.apinb.com/quant/collector/internal/impl"
|
|||
|
|
"git.apinb.com/quant/collector/internal/models"
|
|||
|
|
"git.apinb.com/quant/collector/internal/types"
|
|||
|
|
"gorm.io/gorm"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// CheckAndRepairOrderBooks 检查并补全订单簿数据
|
|||
|
|
func CheckAndRepairOrderBooks(accountID string) error {
|
|||
|
|
log.Println("开始检查订单簿数据完整性...")
|
|||
|
|
err := checkAccountOrderBooks(accountID)
|
|||
|
|
if err != nil {
|
|||
|
|
return fmt.Errorf("检查账户 %s 的订单簿失败: %w", accountID, err)
|
|||
|
|
}
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// checkAccountOrderBooks 检查单个账户的订单簿数据
|
|||
|
|
func checkAccountOrderBooks(accountID string) error {
|
|||
|
|
|
|||
|
|
// 获取该账户最新的持仓日期
|
|||
|
|
var latestYmd int
|
|||
|
|
err := impl.DBService.Model(&models.CollectorPosition{}).
|
|||
|
|
Where("account_id = ?", accountID).
|
|||
|
|
Select("MAX(ymd)").
|
|||
|
|
Scan(&latestYmd).Error
|
|||
|
|
|
|||
|
|
if err != nil {
|
|||
|
|
return fmt.Errorf("查询最新持仓日期失败: %w", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if latestYmd == 0 {
|
|||
|
|
log.Printf("账户 %s 没有持仓记录", accountID)
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
log.Printf("账户 %s 最新持仓日期: %d", accountID, latestYmd)
|
|||
|
|
|
|||
|
|
// 获取该账户最新日期的持仓列表
|
|||
|
|
var latestPositions []models.CollectorPosition
|
|||
|
|
err = impl.DBService.Where("account_id = ? AND ymd = ?", accountID, latestYmd).
|
|||
|
|
Find(&latestPositions).Error
|
|||
|
|
|
|||
|
|
if err != nil {
|
|||
|
|
return fmt.Errorf("查询持仓失败: %w", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
log.Printf("账户 %s 有 %d 个持仓股票需要检查", accountID, len(latestPositions))
|
|||
|
|
|
|||
|
|
// 1. 检查股票持仓列表是否有未闭合的订单簿记录
|
|||
|
|
for _, position := range latestPositions {
|
|||
|
|
// 跳过无持仓的股票
|
|||
|
|
if position.Volume <= 0 {
|
|||
|
|
continue
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var existingOrderBooks models.OrderBook
|
|||
|
|
err := impl.DBService.Where("account_id = ? AND stock_code = ? AND is_closed = ?", accountID, position.Code, false).First(&existingOrderBooks).Error
|
|||
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|||
|
|
// 没有找到未闭合的订单簿记录,写入新的记录
|
|||
|
|
newOrderBook := models.OrderBook{
|
|||
|
|
AccountID: accountID,
|
|||
|
|
StockCode: position.Code,
|
|||
|
|
Ymd: latestYmd,
|
|||
|
|
BuyPrice: position.AvgPrice,
|
|||
|
|
BuyVolume: position.Volume,
|
|||
|
|
IsClosed: false,
|
|||
|
|
}
|
|||
|
|
if err := impl.DBService.Create(&newOrderBook).Error; err != nil {
|
|||
|
|
log.Printf("创建订单簿记录失败: %v", err)
|
|||
|
|
continue
|
|||
|
|
}
|
|||
|
|
log.Printf("新建买入订单簿: account=%s, stock=%s, volume=%d", accountID, position.Code, position.Volume)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 2. 检查所有未闭合的订单簿记录开仓成本价格与CollectorOrders对比,是否正确,不正确采用CollectorOrders中的价格更新
|
|||
|
|
var orderBooks []models.OrderBook
|
|||
|
|
err = impl.DBService.Where("account_id = ? AND is_closed = ?", accountID, false).Find(&orderBooks).Error
|
|||
|
|
if err != nil {
|
|||
|
|
return fmt.Errorf("查询未闭合的订单簿记录失败: %w", err)
|
|||
|
|
}
|
|||
|
|
for _, orderBook := range orderBooks {
|
|||
|
|
newAvgPrice, err := GetOrderAvgPrice(orderBook.StockCode, accountID, orderBook.BuyVolume)
|
|||
|
|
if err != nil {
|
|||
|
|
log.Printf("获取订单簿 %s 的开仓成本价格失败: %v", orderBook.StockCode, err)
|
|||
|
|
continue
|
|||
|
|
}
|
|||
|
|
if newAvgPrice > orderBook.BuyPrice {
|
|||
|
|
log.Printf("订单簿 %s 的开仓成本价格不一致, 更新前: %v, 更新后: %v", orderBook.StockCode, orderBook.BuyPrice, newAvgPrice)
|
|||
|
|
orderBook.BuyPrice = newAvgPrice
|
|||
|
|
if err := impl.DBService.Save(&orderBook).Error; err != nil {
|
|||
|
|
log.Printf("更新订单簿 %s 的开仓成本价格失败: %v", orderBook.StockCode, err)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
func GetOrderAvgPrice(code, account_id string, amount int) (float64, error) {
|
|||
|
|
if amount <= 0 {
|
|||
|
|
return 0, fmt.Errorf("数量必须大于0")
|
|||
|
|
}
|
|||
|
|
var orders []models.CollectorOrder
|
|||
|
|
impl.DBService.Model(&models.CollectorOrder{}).
|
|||
|
|
Where("stock_code = ? AND account_id = ? AND offset_flag = ?", code, account_id, types.FLAG_BUY).
|
|||
|
|
Order("id desc").
|
|||
|
|
Find(&orders)
|
|||
|
|
|
|||
|
|
var stepIdx = 0
|
|||
|
|
var currentAmount int
|
|||
|
|
for idx, order := range orders {
|
|||
|
|
currentAmount += order.TradedVolume
|
|||
|
|
if currentAmount == amount {
|
|||
|
|
stepIdx = idx
|
|||
|
|
break
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
var avgPrice float64
|
|||
|
|
newOrders := orders[0 : stepIdx+1]
|
|||
|
|
for _, order := range newOrders {
|
|||
|
|
avgPrice += order.TradedPrice
|
|||
|
|
}
|
|||
|
|
avgPrice = utils.FloatRound(avgPrice/float64(len(newOrders)), 2)
|
|||
|
|
|
|||
|
|
return avgPrice, nil
|
|||
|
|
}
|