fix bug
This commit is contained in:
@@ -1,58 +0,0 @@
|
|||||||
package collector
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"git.apinb.com/quant/collector/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TestCalculateHash 测试Hash计算功能
|
|
||||||
func TestCalculateHash(t *testing.T) {
|
|
||||||
// 读取样本数据
|
|
||||||
data, err := os.ReadFile("../exmple/status.json")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("读取样本文件失败: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var status types.Status
|
|
||||||
if err := json.Unmarshal(data, &status); err != nil {
|
|
||||||
t.Fatalf("JSON解析失败: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
collector := NewCollector("http://localhost:5000/status")
|
|
||||||
hash, err := collector.CalculateHash(&status)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("计算Hash失败: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if hash == "" {
|
|
||||||
t.Error("Hash值不能为空")
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Logf("计算的Hash: %s", hash)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestHasChanged 测试变化检测
|
|
||||||
func TestHasChanged(t *testing.T) {
|
|
||||||
collector := NewCollector("http://localhost:5000/status")
|
|
||||||
|
|
||||||
// 第一次应该返回true
|
|
||||||
if !collector.HasChanged("hash1") {
|
|
||||||
t.Error("第一次检测应该返回true")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新hash
|
|
||||||
collector.UpdateHash("hash1")
|
|
||||||
|
|
||||||
// 相同的hash应该返回false
|
|
||||||
if collector.HasChanged("hash1") {
|
|
||||||
t.Error("相同的hash应该返回false")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 不同的hash应该返回true
|
|
||||||
if !collector.HasChanged("hash2") {
|
|
||||||
t.Error("不同的hash应该返回true")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -87,6 +87,11 @@ func (s *Storage) AutoMigrate() error {
|
|||||||
|
|
||||||
// SaveStatus 保存完整状态数据(使用事务)
|
// SaveStatus 保存完整状态数据(使用事务)
|
||||||
func (s *Storage) SaveStatus(status *types.Status, dataHash string) error {
|
func (s *Storage) SaveStatus(status *types.Status, dataHash string) error {
|
||||||
|
// 验证必要字段 - AccountID是所有Upsert的共同条件
|
||||||
|
if status.Data.Assets.AccountID == "" {
|
||||||
|
return fmt.Errorf("账户ID不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
return s.db.Transaction(func(tx *gorm.DB) error {
|
return s.db.Transaction(func(tx *gorm.DB) error {
|
||||||
// 计算Ymd (年月日数字格式,如20260407)
|
// 计算Ymd (年月日数字格式,如20260407)
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
@@ -117,6 +122,14 @@ func (s *Storage) SaveStatus(status *types.Status, dataHash string) error {
|
|||||||
if len(status.Data.Orders) > 0 {
|
if len(status.Data.Orders) > 0 {
|
||||||
orders := make([]models.CollectorOrder, 0, len(status.Data.Orders))
|
orders := make([]models.CollectorOrder, 0, len(status.Data.Orders))
|
||||||
for _, order := range status.Data.Orders {
|
for _, order := range status.Data.Orders {
|
||||||
|
// 验证Upsert必要条件: OrderID和StockCode
|
||||||
|
if order.OrderID == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if order.StockCode == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
orders = append(orders, models.CollectorOrder{
|
orders = append(orders, models.CollectorOrder{
|
||||||
OrderID: order.OrderID,
|
OrderID: order.OrderID,
|
||||||
AccountID: status.Data.Assets.AccountID,
|
AccountID: status.Data.Assets.AccountID,
|
||||||
@@ -134,15 +147,17 @@ func (s *Storage) SaveStatus(status *types.Status, dataHash string) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 使用Upsert逻辑: 以 account_id, order_id, ymd 为条件
|
// 使用Upsert逻辑: 以 account_id, order_id, ymd 为条件
|
||||||
if err := tx.Clauses(clause.OnConflict{
|
if len(orders) > 0 {
|
||||||
Columns: []clause.Column{{Name: "account_id"}, {Name: "order_id"}, {Name: "ymd"}},
|
if err := tx.Clauses(clause.OnConflict{
|
||||||
DoUpdates: clause.AssignmentColumns([]string{
|
Columns: []clause.Column{{Name: "account_id"}, {Name: "order_id"}, {Name: "ymd"}},
|
||||||
"stock_code", "price", "volume",
|
DoUpdates: clause.AssignmentColumns([]string{
|
||||||
"traded_price", "traded_volume", "order_status",
|
"stock_code", "price", "volume",
|
||||||
"order_time", "order_remark", "data_hash", "collected_at",
|
"traded_price", "traded_volume", "order_status",
|
||||||
}),
|
"order_time", "order_remark", "data_hash", "collected_at",
|
||||||
}).Create(&orders).Error; err != nil {
|
}),
|
||||||
return fmt.Errorf("保存订单失败: %w", err)
|
}).Create(&orders).Error; err != nil {
|
||||||
|
return fmt.Errorf("保存订单失败: %w", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,6 +165,11 @@ func (s *Storage) SaveStatus(status *types.Status, dataHash string) error {
|
|||||||
if len(status.Data.Positions) > 0 {
|
if len(status.Data.Positions) > 0 {
|
||||||
positions := make([]models.CollectorPosition, 0, len(status.Data.Positions))
|
positions := make([]models.CollectorPosition, 0, len(status.Data.Positions))
|
||||||
for _, pos := range status.Data.Positions {
|
for _, pos := range status.Data.Positions {
|
||||||
|
// 验证Upsert必要条件: Code
|
||||||
|
if pos.Code == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
positions = append(positions, models.CollectorPosition{
|
positions = append(positions, models.CollectorPosition{
|
||||||
AccountID: status.Data.Assets.AccountID,
|
AccountID: status.Data.Assets.AccountID,
|
||||||
Code: pos.Code,
|
Code: pos.Code,
|
||||||
@@ -169,16 +189,18 @@ func (s *Storage) SaveStatus(status *types.Status, dataHash string) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 使用Upsert逻辑: 以 account_id, code, ymd 为条件
|
// 使用Upsert逻辑: 以 account_id, code, ymd 为条件
|
||||||
if err := tx.Clauses(clause.OnConflict{
|
if len(positions) > 0 {
|
||||||
Columns: []clause.Column{{Name: "account_id"}, {Name: "code"}, {Name: "ymd"}},
|
if err := tx.Clauses(clause.OnConflict{
|
||||||
DoUpdates: clause.AssignmentColumns([]string{
|
Columns: []clause.Column{{Name: "account_id"}, {Name: "code"}, {Name: "ymd"}},
|
||||||
"volume", "can_use_volume", "frozen_volume",
|
DoUpdates: clause.AssignmentColumns([]string{
|
||||||
"avg_price", "open_price", "current_price",
|
"volume", "can_use_volume", "frozen_volume",
|
||||||
"market_value", "profit", "profit_rate",
|
"avg_price", "open_price", "current_price",
|
||||||
"min_profit_rate", "data_hash", "collected_at",
|
"market_value", "profit", "profit_rate",
|
||||||
}),
|
"min_profit_rate", "data_hash", "collected_at",
|
||||||
}).Create(&positions).Error; err != nil {
|
}),
|
||||||
return fmt.Errorf("保存持仓失败: %w", err)
|
}).Create(&positions).Error; err != nil {
|
||||||
|
return fmt.Errorf("保存持仓失败: %w", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,6 +208,11 @@ func (s *Storage) SaveStatus(status *types.Status, dataHash string) error {
|
|||||||
if len(status.Data.TickData) > 0 {
|
if len(status.Data.TickData) > 0 {
|
||||||
ticks := make([]models.CollectorTick, 0, len(status.Data.TickData))
|
ticks := make([]models.CollectorTick, 0, len(status.Data.TickData))
|
||||||
for code, tick := range status.Data.TickData {
|
for code, tick := range status.Data.TickData {
|
||||||
|
// 验证Upsert必要条件: StockCode
|
||||||
|
if code == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
ticks = append(ticks, models.CollectorTick{
|
ticks = append(ticks, models.CollectorTick{
|
||||||
StockCode: code,
|
StockCode: code,
|
||||||
Ymd: ymd,
|
Ymd: ymd,
|
||||||
@@ -209,17 +236,19 @@ func (s *Storage) SaveStatus(status *types.Status, dataHash string) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 使用Upsert逻辑: 以 stock_code, ymd 为条件
|
// 使用Upsert逻辑: 以 stock_code, ymd 为条件
|
||||||
if err := tx.Clauses(clause.OnConflict{
|
if len(ticks) > 0 {
|
||||||
Columns: []clause.Column{{Name: "stock_code"}, {Name: "ymd"}},
|
if err := tx.Clauses(clause.OnConflict{
|
||||||
DoUpdates: clause.AssignmentColumns([]string{
|
Columns: []clause.Column{{Name: "stock_code"}, {Name: "ymd"}},
|
||||||
"last_price", "open", "high", "low", "last_close",
|
DoUpdates: clause.AssignmentColumns([]string{
|
||||||
"volume", "amount", "pvolume",
|
"last_price", "open", "high", "low", "last_close",
|
||||||
"bid_prices", "bid_volumes", "ask_prices", "ask_volumes",
|
"volume", "amount", "pvolume",
|
||||||
"time", "timetag", "stock_status",
|
"bid_prices", "bid_volumes", "ask_prices", "ask_volumes",
|
||||||
"data_hash", "collected_at",
|
"time", "timetag", "stock_status",
|
||||||
}),
|
"data_hash", "collected_at",
|
||||||
}).Create(&ticks).Error; err != nil {
|
}),
|
||||||
return fmt.Errorf("保存行情数据失败: %w", err)
|
}).Create(&ticks).Error; err != nil {
|
||||||
|
return fmt.Errorf("保存行情数据失败: %w", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user