Files
nofx/scripts/fix_order_data.go
T
tinkle-community 1744e7f38e feat: migrate to CoinAnk API and improve chart UI
- Chart improvements: professional styling, popular symbols quick selection, simplified B/S legend
- Data source migration: use CoinAnk API exclusively for all kline data
- Code cleanup: remove Binance WebSocket cache and related code (websocket_client.go, combined_streams.go, monitor.go)
- Log optimization: reduce hook spam, suppress 404 errors, increase P&L diff threshold
- Lighter integration: add order sync functionality, fix market order precision
- Remove ticker merge logic for simplicity
2025-12-26 00:58:12 +08:00

142 lines
3.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package main
import (
"flag"
"fmt"
"log"
"nofx/store"
"os"
"path/filepath"
"time"
)
func main() {
var dbPath string
var dryRun bool
flag.StringVar(&dbPath, "db", "./data/data.db", "数据库文件路径")
flag.BoolVar(&dryRun, "dry-run", false, "只检查不修复(预览模式)")
flag.Parse()
// 确保数据库文件存在
absPath, err := filepath.Abs(dbPath)
if err != nil {
log.Fatalf("❌ 无效的数据库路径: %v", err)
}
if _, err := os.Stat(absPath); os.IsNotExist(err) {
log.Fatalf("❌ 数据库文件不存在: %s", absPath)
}
fmt.Printf("📂 数据库路径: %s\n", absPath)
// 打开数据库
s, err := store.New(absPath)
if err != nil {
log.Fatalf("❌ 无法打开数据库: %v", err)
}
defer s.Close()
db := s.DB()
fmt.Println("\n🔍 检查需要修复的订单...")
// 1. 修复缺少 filled_at 的 FILLED 订单(使用 updated_at 或 created_at
var needFixFilledAt int
err = db.QueryRow(`
SELECT COUNT(*)
FROM trader_orders
WHERE status = 'FILLED' AND (filled_at IS NULL OR filled_at = '')
`).Scan(&needFixFilledAt)
if err != nil {
log.Fatalf("❌ 查询失败: %v", err)
}
fmt.Printf(" 📋 缺少成交时间的订单: %d 条\n", needFixFilledAt)
// 2. 修复 avg_fill_price = 0 的 FILLED 订单(使用 price 字段)
var needFixAvgPrice int
err = db.QueryRow(`
SELECT COUNT(*)
FROM trader_orders
WHERE status = 'FILLED' AND (avg_fill_price = 0 OR avg_fill_price IS NULL) AND price > 0
`).Scan(&needFixAvgPrice)
if err != nil {
log.Fatalf("❌ 查询失败: %v", err)
}
fmt.Printf(" 💰 成交价为0的订单: %d 条\n", needFixAvgPrice)
if needFixFilledAt == 0 && needFixAvgPrice == 0 {
fmt.Println("\n✅ 没有需要修复的订单!")
return
}
if dryRun {
fmt.Println("\n⚠️ 预览模式(--dry-run),不会修改数据")
fmt.Println(" 运行 'go run scripts/fix_order_data.go' 来执行实际修复")
return
}
fmt.Println("\n🔧 开始修复...")
// 修复缺少 filled_at 的订单
if needFixFilledAt > 0 {
result, err := db.Exec(`
UPDATE trader_orders
SET filled_at = COALESCE(updated_at, created_at)
WHERE status = 'FILLED' AND (filled_at IS NULL OR filled_at = '')
`)
if err != nil {
log.Fatalf("❌ 修复成交时间失败: %v", err)
}
rows, _ := result.RowsAffected()
fmt.Printf(" ✅ 修复了 %d 条订单的成交时间\n", rows)
}
// 修复 avg_fill_price = 0 的订单
if needFixAvgPrice > 0 {
result, err := db.Exec(`
UPDATE trader_orders
SET avg_fill_price = price,
filled_quantity = quantity
WHERE status = 'FILLED'
AND (avg_fill_price = 0 OR avg_fill_price IS NULL)
AND price > 0
`)
if err != nil {
log.Fatalf("❌ 修复成交价失败: %v", err)
}
rows, _ := result.RowsAffected()
fmt.Printf(" ✅ 修复了 %d 条订单的成交价\n", rows)
}
// 验证修复结果
fmt.Println("\n🔍 验证修复结果...")
time.Sleep(100 * time.Millisecond)
var stillMissingFilledAt int
db.QueryRow(`
SELECT COUNT(*)
FROM trader_orders
WHERE status = 'FILLED' AND (filled_at IS NULL OR filled_at = '')
`).Scan(&stillMissingFilledAt)
var stillMissingAvgPrice int
db.QueryRow(`
SELECT COUNT(*)
FROM trader_orders
WHERE status = 'FILLED' AND (avg_fill_price = 0 OR avg_fill_price IS NULL)
`).Scan(&stillMissingAvgPrice)
fmt.Printf(" 📋 仍缺少成交时间: %d 条\n", stillMissingFilledAt)
fmt.Printf(" 💰 仍缺少成交价: %d 条\n", stillMissingAvgPrice)
if stillMissingFilledAt == 0 && stillMissingAvgPrice == 0 {
fmt.Println("\n✅ 修复完成!所有订单数据已完整")
fmt.Println("\n💡 现在刷新图表页面,应该能看到 B/S 标记了")
} else {
fmt.Println("\n⚠️ 仍有部分订单无法修复,可能需要手动检查")
}
}