mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-16 09:11:03 +08:00
feat: add exchange_id field to trader_positions table
- Add exchange_id column to track which exchange the position is from - Update all SELECT/INSERT queries to include exchange_id - Set exchange_id when creating position record in AutoTrader - Add migration to add column to existing tables
This commit is contained in:
@@ -11,6 +11,7 @@ import (
|
|||||||
type TraderPosition struct {
|
type TraderPosition struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
TraderID string `json:"trader_id"`
|
TraderID string `json:"trader_id"`
|
||||||
|
ExchangeID string `json:"exchange_id"` // 交易所ID: binance/bybit/hyperliquid/aster/lighter
|
||||||
Symbol string `json:"symbol"`
|
Symbol string `json:"symbol"`
|
||||||
Side string `json:"side"` // LONG/SHORT
|
Side string `json:"side"` // LONG/SHORT
|
||||||
Quantity float64 `json:"quantity"` // 开仓数量
|
Quantity float64 `json:"quantity"` // 开仓数量
|
||||||
@@ -45,6 +46,7 @@ func (s *PositionStore) InitTables() error {
|
|||||||
CREATE TABLE IF NOT EXISTS trader_positions (
|
CREATE TABLE IF NOT EXISTS trader_positions (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
trader_id TEXT NOT NULL,
|
trader_id TEXT NOT NULL,
|
||||||
|
exchange_id TEXT NOT NULL DEFAULT '',
|
||||||
symbol TEXT NOT NULL,
|
symbol TEXT NOT NULL,
|
||||||
side TEXT NOT NULL,
|
side TEXT NOT NULL,
|
||||||
quantity REAL NOT NULL,
|
quantity REAL NOT NULL,
|
||||||
@@ -70,6 +72,7 @@ func (s *PositionStore) InitTables() error {
|
|||||||
// 创建索引
|
// 创建索引
|
||||||
indices := []string{
|
indices := []string{
|
||||||
`CREATE INDEX IF NOT EXISTS idx_positions_trader ON trader_positions(trader_id)`,
|
`CREATE INDEX IF NOT EXISTS idx_positions_trader ON trader_positions(trader_id)`,
|
||||||
|
`CREATE INDEX IF NOT EXISTS idx_positions_exchange ON trader_positions(exchange_id)`,
|
||||||
`CREATE INDEX IF NOT EXISTS idx_positions_status ON trader_positions(trader_id, status)`,
|
`CREATE INDEX IF NOT EXISTS idx_positions_status ON trader_positions(trader_id, status)`,
|
||||||
`CREATE INDEX IF NOT EXISTS idx_positions_symbol ON trader_positions(trader_id, symbol, side, status)`,
|
`CREATE INDEX IF NOT EXISTS idx_positions_symbol ON trader_positions(trader_id, symbol, side, status)`,
|
||||||
`CREATE INDEX IF NOT EXISTS idx_positions_entry ON trader_positions(trader_id, entry_time DESC)`,
|
`CREATE INDEX IF NOT EXISTS idx_positions_entry ON trader_positions(trader_id, entry_time DESC)`,
|
||||||
@@ -81,6 +84,9 @@ func (s *PositionStore) InitTables() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 迁移:为现有表添加 exchange_id 列(如果不存在)
|
||||||
|
s.db.Exec(`ALTER TABLE trader_positions ADD COLUMN exchange_id TEXT NOT NULL DEFAULT ''`)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,11 +99,11 @@ func (s *PositionStore) Create(pos *TraderPosition) error {
|
|||||||
|
|
||||||
result, err := s.db.Exec(`
|
result, err := s.db.Exec(`
|
||||||
INSERT INTO trader_positions (
|
INSERT INTO trader_positions (
|
||||||
trader_id, symbol, side, quantity, entry_price, entry_order_id,
|
trader_id, exchange_id, symbol, side, quantity, entry_price, entry_order_id,
|
||||||
entry_time, leverage, status, created_at, updated_at
|
entry_time, leverage, status, created_at, updated_at
|
||||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
`,
|
`,
|
||||||
pos.TraderID, pos.Symbol, pos.Side, pos.Quantity, pos.EntryPrice,
|
pos.TraderID, pos.ExchangeID, pos.Symbol, pos.Side, pos.Quantity, pos.EntryPrice,
|
||||||
pos.EntryOrderID, pos.EntryTime.Format(time.RFC3339), pos.Leverage,
|
pos.EntryOrderID, pos.EntryTime.Format(time.RFC3339), pos.Leverage,
|
||||||
pos.Status, now.Format(time.RFC3339), now.Format(time.RFC3339),
|
pos.Status, now.Format(time.RFC3339), now.Format(time.RFC3339),
|
||||||
)
|
)
|
||||||
@@ -132,7 +138,7 @@ func (s *PositionStore) ClosePosition(id int64, exitPrice float64, exitOrderID s
|
|||||||
// GetOpenPositions 获取所有未平仓位
|
// GetOpenPositions 获取所有未平仓位
|
||||||
func (s *PositionStore) GetOpenPositions(traderID string) ([]*TraderPosition, error) {
|
func (s *PositionStore) GetOpenPositions(traderID string) ([]*TraderPosition, error) {
|
||||||
rows, err := s.db.Query(`
|
rows, err := s.db.Query(`
|
||||||
SELECT id, trader_id, symbol, side, quantity, entry_price, entry_order_id,
|
SELECT id, trader_id, exchange_id, symbol, side, quantity, entry_price, entry_order_id,
|
||||||
entry_time, exit_price, exit_order_id, exit_time, realized_pnl, fee,
|
entry_time, exit_price, exit_order_id, exit_time, realized_pnl, fee,
|
||||||
leverage, status, close_reason, created_at, updated_at
|
leverage, status, close_reason, created_at, updated_at
|
||||||
FROM trader_positions
|
FROM trader_positions
|
||||||
@@ -153,14 +159,14 @@ func (s *PositionStore) GetOpenPositionBySymbol(traderID, symbol, side string) (
|
|||||||
var entryTime, exitTime, createdAt, updatedAt sql.NullString
|
var entryTime, exitTime, createdAt, updatedAt sql.NullString
|
||||||
|
|
||||||
err := s.db.QueryRow(`
|
err := s.db.QueryRow(`
|
||||||
SELECT id, trader_id, symbol, side, quantity, entry_price, entry_order_id,
|
SELECT id, trader_id, exchange_id, symbol, side, quantity, entry_price, entry_order_id,
|
||||||
entry_time, exit_price, exit_order_id, exit_time, realized_pnl, fee,
|
entry_time, exit_price, exit_order_id, exit_time, realized_pnl, fee,
|
||||||
leverage, status, close_reason, created_at, updated_at
|
leverage, status, close_reason, created_at, updated_at
|
||||||
FROM trader_positions
|
FROM trader_positions
|
||||||
WHERE trader_id = ? AND symbol = ? AND side = ? AND status = 'OPEN'
|
WHERE trader_id = ? AND symbol = ? AND side = ? AND status = 'OPEN'
|
||||||
ORDER BY entry_time DESC LIMIT 1
|
ORDER BY entry_time DESC LIMIT 1
|
||||||
`, traderID, symbol, side).Scan(
|
`, traderID, symbol, side).Scan(
|
||||||
&pos.ID, &pos.TraderID, &pos.Symbol, &pos.Side, &pos.Quantity,
|
&pos.ID, &pos.TraderID, &pos.ExchangeID, &pos.Symbol, &pos.Side, &pos.Quantity,
|
||||||
&pos.EntryPrice, &pos.EntryOrderID, &entryTime, &pos.ExitPrice,
|
&pos.EntryPrice, &pos.EntryOrderID, &entryTime, &pos.ExitPrice,
|
||||||
&pos.ExitOrderID, &exitTime, &pos.RealizedPnL, &pos.Fee,
|
&pos.ExitOrderID, &exitTime, &pos.RealizedPnL, &pos.Fee,
|
||||||
&pos.Leverage, &pos.Status, &pos.CloseReason, &createdAt, &updatedAt,
|
&pos.Leverage, &pos.Status, &pos.CloseReason, &createdAt, &updatedAt,
|
||||||
@@ -179,7 +185,7 @@ func (s *PositionStore) GetOpenPositionBySymbol(traderID, symbol, side string) (
|
|||||||
// GetClosedPositions 获取已平仓位(历史记录)
|
// GetClosedPositions 获取已平仓位(历史记录)
|
||||||
func (s *PositionStore) GetClosedPositions(traderID string, limit int) ([]*TraderPosition, error) {
|
func (s *PositionStore) GetClosedPositions(traderID string, limit int) ([]*TraderPosition, error) {
|
||||||
rows, err := s.db.Query(`
|
rows, err := s.db.Query(`
|
||||||
SELECT id, trader_id, symbol, side, quantity, entry_price, entry_order_id,
|
SELECT id, trader_id, exchange_id, symbol, side, quantity, entry_price, entry_order_id,
|
||||||
entry_time, exit_price, exit_order_id, exit_time, realized_pnl, fee,
|
entry_time, exit_price, exit_order_id, exit_time, realized_pnl, fee,
|
||||||
leverage, status, close_reason, created_at, updated_at
|
leverage, status, close_reason, created_at, updated_at
|
||||||
FROM trader_positions
|
FROM trader_positions
|
||||||
@@ -198,7 +204,7 @@ func (s *PositionStore) GetClosedPositions(traderID string, limit int) ([]*Trade
|
|||||||
// GetAllOpenPositions 获取所有trader的未平仓位(用于全局同步)
|
// GetAllOpenPositions 获取所有trader的未平仓位(用于全局同步)
|
||||||
func (s *PositionStore) GetAllOpenPositions() ([]*TraderPosition, error) {
|
func (s *PositionStore) GetAllOpenPositions() ([]*TraderPosition, error) {
|
||||||
rows, err := s.db.Query(`
|
rows, err := s.db.Query(`
|
||||||
SELECT id, trader_id, symbol, side, quantity, entry_price, entry_order_id,
|
SELECT id, trader_id, exchange_id, symbol, side, quantity, entry_price, entry_order_id,
|
||||||
entry_time, exit_price, exit_order_id, exit_time, realized_pnl, fee,
|
entry_time, exit_price, exit_order_id, exit_time, realized_pnl, fee,
|
||||||
leverage, status, close_reason, created_at, updated_at
|
leverage, status, close_reason, created_at, updated_at
|
||||||
FROM trader_positions
|
FROM trader_positions
|
||||||
@@ -439,7 +445,7 @@ func (s *PositionStore) scanPositions(rows *sql.Rows) ([]*TraderPosition, error)
|
|||||||
var entryTime, exitTime, createdAt, updatedAt sql.NullString
|
var entryTime, exitTime, createdAt, updatedAt sql.NullString
|
||||||
|
|
||||||
err := rows.Scan(
|
err := rows.Scan(
|
||||||
&pos.ID, &pos.TraderID, &pos.Symbol, &pos.Side, &pos.Quantity,
|
&pos.ID, &pos.TraderID, &pos.ExchangeID, &pos.Symbol, &pos.Side, &pos.Quantity,
|
||||||
&pos.EntryPrice, &pos.EntryOrderID, &entryTime, &pos.ExitPrice,
|
&pos.EntryPrice, &pos.EntryOrderID, &entryTime, &pos.ExitPrice,
|
||||||
&pos.ExitOrderID, &exitTime, &pos.RealizedPnL, &pos.Fee,
|
&pos.ExitOrderID, &exitTime, &pos.RealizedPnL, &pos.Fee,
|
||||||
&pos.Leverage, &pos.Status, &pos.CloseReason, &createdAt, &updatedAt,
|
&pos.Leverage, &pos.Status, &pos.CloseReason, &createdAt, &updatedAt,
|
||||||
|
|||||||
@@ -1548,6 +1548,7 @@ func (at *AutoTrader) recordPositionChange(orderID, symbol, side, action string,
|
|||||||
// 开仓:创建新的仓位记录
|
// 开仓:创建新的仓位记录
|
||||||
pos := &store.TraderPosition{
|
pos := &store.TraderPosition{
|
||||||
TraderID: at.id,
|
TraderID: at.id,
|
||||||
|
ExchangeID: at.exchange, // 记录具体的交易所ID
|
||||||
Symbol: symbol,
|
Symbol: symbol,
|
||||||
Side: side, // LONG or SHORT
|
Side: side, // LONG or SHORT
|
||||||
Quantity: quantity,
|
Quantity: quantity,
|
||||||
|
|||||||
Reference in New Issue
Block a user