mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-15 16:56:56 +08:00
fix(grid): improve order state sync logic
- Don't assume missing orders are filled - Compare position size to determine fill vs cancel - Properly reset cancelled orders to empty state - More accurate grid state tracking
This commit is contained in:
@@ -811,55 +811,60 @@ func (at *AutoTrader) syncGridState() {
|
|||||||
activeOrderIDs[order.OrderID] = true
|
activeOrderIDs[order.OrderID] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get current positions to verify fills
|
||||||
|
positions, err := at.trader.GetPositions()
|
||||||
|
currentPositionSize := 0.0
|
||||||
|
if err == nil {
|
||||||
|
for _, pos := range positions {
|
||||||
|
if sym, ok := pos["symbol"].(string); ok && sym == gridConfig.Symbol {
|
||||||
|
if size, ok := pos["positionAmt"].(float64); ok {
|
||||||
|
currentPositionSize = size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update levels based on order status
|
// Update levels based on order status
|
||||||
at.gridState.mu.Lock()
|
at.gridState.mu.Lock()
|
||||||
|
previousFilledCount := 0
|
||||||
|
for _, level := range at.gridState.Levels {
|
||||||
|
if level.State == "filled" {
|
||||||
|
previousFilledCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for i := range at.gridState.Levels {
|
for i := range at.gridState.Levels {
|
||||||
level := &at.gridState.Levels[i]
|
level := &at.gridState.Levels[i]
|
||||||
if level.State == "pending" && level.OrderID != "" {
|
if level.State == "pending" && level.OrderID != "" {
|
||||||
if !activeOrderIDs[level.OrderID] {
|
if !activeOrderIDs[level.OrderID] {
|
||||||
// Order no longer exists - might be filled or cancelled
|
// Order no longer exists - check if position changed to determine fill vs cancel
|
||||||
// Mark as filled (we'll need to verify with position data)
|
// This is a heuristic - ideally we'd query order history
|
||||||
level.State = "filled"
|
if math.Abs(currentPositionSize) > math.Abs(float64(previousFilledCount)*level.OrderQuantity) {
|
||||||
level.PositionEntry = level.Price
|
// Position increased, likely filled
|
||||||
at.gridState.TotalTrades++
|
level.State = "filled"
|
||||||
logger.Infof("[Grid] Level %d order filled at $%.2f", i, level.Price)
|
level.PositionEntry = level.Price
|
||||||
|
level.PositionSize = level.OrderQuantity
|
||||||
|
at.gridState.TotalTrades++
|
||||||
|
logger.Infof("[Grid] Level %d order filled at $%.2f", i, level.Price)
|
||||||
|
} else {
|
||||||
|
// Position didn't increase as expected, likely cancelled
|
||||||
|
level.State = "empty"
|
||||||
|
level.OrderID = ""
|
||||||
|
level.OrderQuantity = 0
|
||||||
|
logger.Infof("[Grid] Level %d order cancelled/expired", i)
|
||||||
|
}
|
||||||
|
delete(at.gridState.OrderBook, level.OrderID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
at.gridState.mu.Unlock()
|
at.gridState.mu.Unlock()
|
||||||
|
|
||||||
// Update position info
|
logger.Debugf("[Grid] Synced state: position=%.4f, orders=%d", currentPositionSize, len(openOrders))
|
||||||
positions, err := at.trader.GetPositions()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var totalPosition float64
|
// Check stop loss
|
||||||
for _, pos := range positions {
|
|
||||||
if sym, ok := pos["symbol"].(string); ok && sym == gridConfig.Symbol {
|
|
||||||
if size, ok := pos["positionAmt"].(float64); ok {
|
|
||||||
totalPosition = size
|
|
||||||
}
|
|
||||||
if pnl, ok := pos["unRealizedProfit"].(float64); ok {
|
|
||||||
// Update unrealized PnL for filled levels
|
|
||||||
at.gridState.mu.Lock()
|
|
||||||
for i := range at.gridState.Levels {
|
|
||||||
if at.gridState.Levels[i].State == "filled" {
|
|
||||||
// Distribute PnL (simplified - in production, track per-level)
|
|
||||||
at.gridState.Levels[i].UnrealizedPnL = pnl / float64(at.gridState.TotalTrades)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
at.gridState.mu.Unlock()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Debugf("[Grid] Synced state: position=%.4f, orders=%d", totalPosition, len(openOrders))
|
|
||||||
|
|
||||||
// CRITICAL: Check stop loss for filled levels
|
|
||||||
at.checkAndExecuteStopLoss()
|
at.checkAndExecuteStopLoss()
|
||||||
|
|
||||||
// Check grid skew and auto-adjust if needed
|
// Check grid skew
|
||||||
at.autoAdjustGrid()
|
at.autoAdjustGrid()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user