mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-07 21:12:00 +08:00
fix: cancel orphaned stop/TP orders on position close + guard zero SL/TP prices
Critical bugs fixed: - executeCloseLong/CloseShort: cancel stop-loss and take-profit orders BEFORE closing position to prevent orphaned orders from triggering and creating unintended positions - emergencyClosePosition: same fix for drawdown monitor's emergency close path - Skip SetStopLoss/SetTakeProfit when AI returns price=0 (prevents exchange API errors) Also includes: - Add agent.Stop() to graceful shutdown sequence in main.go - Remove unused variable suppression in Hyperliquid trader
This commit is contained in:
4
main.go
4
main.go
@@ -192,6 +192,10 @@ func main() {
|
||||
}
|
||||
logger.Info("✅ HTTP server stopped")
|
||||
|
||||
// Stop NOFXi agent (sentinel, brain, scheduler, cleanup goroutines)
|
||||
nofxiAgent.Stop()
|
||||
logger.Info("✅ NOFXi agent stopped")
|
||||
|
||||
// Stop all traders
|
||||
traderManager.StopAll()
|
||||
logger.Info("✅ System shut down safely")
|
||||
|
||||
@@ -134,12 +134,16 @@ func (at *AutoTrader) executeOpenLongWithRecord(decision *kernel.Decision, actio
|
||||
posKey := decision.Symbol + "_long"
|
||||
at.positionFirstSeenTime[posKey] = time.Now().UnixMilli()
|
||||
|
||||
// Set stop loss and take profit
|
||||
if err := at.trader.SetStopLoss(decision.Symbol, "LONG", quantity, decision.StopLoss); err != nil {
|
||||
logger.Infof(" ⚠ Failed to set stop loss: %v", err)
|
||||
// Set stop loss and take profit (skip if AI didn't specify a price)
|
||||
if decision.StopLoss > 0 {
|
||||
if err := at.trader.SetStopLoss(decision.Symbol, "LONG", quantity, decision.StopLoss); err != nil {
|
||||
logger.Infof(" ⚠ Failed to set stop loss: %v", err)
|
||||
}
|
||||
}
|
||||
if err := at.trader.SetTakeProfit(decision.Symbol, "LONG", quantity, decision.TakeProfit); err != nil {
|
||||
logger.Infof(" ⚠ Failed to set take profit: %v", err)
|
||||
if decision.TakeProfit > 0 {
|
||||
if err := at.trader.SetTakeProfit(decision.Symbol, "LONG", quantity, decision.TakeProfit); err != nil {
|
||||
logger.Infof(" ⚠ Failed to set take profit: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -252,11 +256,15 @@ func (at *AutoTrader) executeOpenShortWithRecord(decision *kernel.Decision, acti
|
||||
at.positionFirstSeenTime[posKey] = time.Now().UnixMilli()
|
||||
|
||||
// Set stop loss and take profit
|
||||
if err := at.trader.SetStopLoss(decision.Symbol, "SHORT", quantity, decision.StopLoss); err != nil {
|
||||
logger.Infof(" ⚠ Failed to set stop loss: %v", err)
|
||||
if decision.StopLoss > 0 {
|
||||
if err := at.trader.SetStopLoss(decision.Symbol, "SHORT", quantity, decision.StopLoss); err != nil {
|
||||
logger.Infof(" ⚠ Failed to set stop loss: %v", err)
|
||||
}
|
||||
}
|
||||
if err := at.trader.SetTakeProfit(decision.Symbol, "SHORT", quantity, decision.TakeProfit); err != nil {
|
||||
logger.Infof(" ⚠ Failed to set take profit: %v", err)
|
||||
if decision.TakeProfit > 0 {
|
||||
if err := at.trader.SetTakeProfit(decision.Symbol, "SHORT", quantity, decision.TakeProfit); err != nil {
|
||||
logger.Infof(" ⚠ Failed to set take profit: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -306,6 +314,14 @@ func (at *AutoTrader) executeCloseLongWithRecord(decision *kernel.Decision, acti
|
||||
logger.Infof(" 📊 Using exchange position data: qty=%.8f, entry=%.2f", quantity, entryPrice)
|
||||
}
|
||||
|
||||
// Cancel existing stop-loss and take-profit orders BEFORE closing position
|
||||
// Critical: orphaned SL/TP orders could trigger after position is closed and create unintended positions
|
||||
if err := at.trader.CancelStopOrders(decision.Symbol); err != nil {
|
||||
logger.Warnf(" ⚠️ Failed to cancel stop orders for %s: %v (proceeding with close)", decision.Symbol, err)
|
||||
} else {
|
||||
logger.Infof(" 🗑️ Cancelled stop/TP orders for %s", decision.Symbol)
|
||||
}
|
||||
|
||||
// Close position
|
||||
order, err := at.trader.CloseLong(decision.Symbol, 0) // 0 = close all
|
||||
if err != nil {
|
||||
@@ -368,6 +384,14 @@ func (at *AutoTrader) executeCloseShortWithRecord(decision *kernel.Decision, act
|
||||
logger.Infof(" 📊 Using exchange position data: qty=%.8f, entry=%.2f", quantity, entryPrice)
|
||||
}
|
||||
|
||||
// Cancel existing stop-loss and take-profit orders BEFORE closing position
|
||||
// Critical: orphaned SL/TP orders could trigger after position is closed and create unintended positions
|
||||
if err := at.trader.CancelStopOrders(decision.Symbol); err != nil {
|
||||
logger.Warnf(" ⚠️ Failed to cancel stop orders for %s: %v (proceeding with close)", decision.Symbol, err)
|
||||
} else {
|
||||
logger.Infof(" 🗑️ Cancelled stop/TP orders for %s", decision.Symbol)
|
||||
}
|
||||
|
||||
// Close position
|
||||
order, err := at.trader.CloseShort(decision.Symbol, 0) // 0 = close all
|
||||
if err != nil {
|
||||
|
||||
@@ -112,6 +112,12 @@ func (at *AutoTrader) checkPositionDrawdown() {
|
||||
|
||||
// emergencyClosePosition emergency close position function
|
||||
func (at *AutoTrader) emergencyClosePosition(symbol, side string) error {
|
||||
// Cancel existing stop-loss and take-profit orders BEFORE closing position
|
||||
// Critical: orphaned SL/TP orders could trigger after position is closed and create unintended positions
|
||||
if err := at.trader.CancelStopOrders(symbol); err != nil {
|
||||
logger.Warnf(" ⚠️ Emergency close: failed to cancel stop orders for %s: %v", symbol, err)
|
||||
}
|
||||
|
||||
switch side {
|
||||
case "long":
|
||||
order, err := at.trader.CloseLong(symbol, 0) // 0 = close all
|
||||
|
||||
@@ -132,9 +132,6 @@ func (t *HyperliquidTrader) GetBalance() (map[string]interface{}, error) {
|
||||
spotUSDCBalance, availableBalance)
|
||||
}
|
||||
|
||||
// Suppress unused variable warning
|
||||
_ = totalUnrealizedPnlAll
|
||||
|
||||
result["totalWalletBalance"] = totalWalletBalance // Total assets (Perp + Spot + xyz) - unrealized
|
||||
result["totalEquity"] = totalEquityCalculated // Total equity = Perp AV + Spot + xyz AV
|
||||
result["availableBalance"] = availableBalance // Available balance (Perp + Spot if unified)
|
||||
|
||||
Reference in New Issue
Block a user