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 }