mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-14 08:16:56 +08:00
fix: isStockSymbol misclassifies crypto symbols (BTC/ETH/SOL) as stock tickers
Critical bug: isStockSymbol('BTC') returned true because 'BTC' is 3
uppercase letters and the suffix check only catches 'BTCUSDT'-style pairs.
This caused crypto trade commands to be routed to Alpaca (stock trader)
instead of crypto exchanges.
Fix: add knownCryptoSymbols map with 60+ common crypto base symbols.
Check this map first before the heuristic letter-count check.
Also includes:
- Unit tests for isStockSymbol (crypto vs stock classification)
- Alpaca support in handleSyncBalance/handleClosePosition API handlers
- Cancel orphaned SL/TP orders before manual position close
- Clear peak PnL cache on position close (prevent stale data)
- Lighter FormatQuantity uses actual market precision instead of hardcoded 4
This commit is contained in:
@@ -336,6 +336,9 @@ func (at *AutoTrader) executeCloseLongWithRecord(decision *kernel.Decision, acti
|
||||
// Record order to database and poll for confirmation
|
||||
at.recordAndConfirmOrder(order, decision.Symbol, "close_long", quantity, marketData.CurrentPrice, 0, entryPrice)
|
||||
|
||||
// Clear peak PnL cache for this position (prevent stale data if same symbol is reopened)
|
||||
at.ClearPeakPnLCache(decision.Symbol, "long")
|
||||
|
||||
logger.Infof(" ✓ Position closed successfully")
|
||||
return nil
|
||||
}
|
||||
@@ -406,6 +409,9 @@ func (at *AutoTrader) executeCloseShortWithRecord(decision *kernel.Decision, act
|
||||
// Record order to database and poll for confirmation
|
||||
at.recordAndConfirmOrder(order, decision.Symbol, "close_short", quantity, marketData.CurrentPrice, 0, entryPrice)
|
||||
|
||||
// Clear peak PnL cache for this position (prevent stale data if same symbol is reopened)
|
||||
at.ClearPeakPnLCache(decision.Symbol, "short")
|
||||
|
||||
logger.Infof(" ✓ Position closed successfully")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -351,9 +351,14 @@ func (t *LighterTraderV2) GetMarketPrice(symbol string) (float64, error) {
|
||||
|
||||
// FormatQuantity Format quantity to correct precision (implements Trader interface)
|
||||
func (t *LighterTraderV2) FormatQuantity(symbol string, quantity float64) (string, error) {
|
||||
// TODO: Get symbol precision from API
|
||||
// Using default precision for now
|
||||
return fmt.Sprintf("%.4f", quantity), nil
|
||||
marketInfo, err := t.getMarketInfo(symbol)
|
||||
if err != nil {
|
||||
// Fallback to 4 decimal places if market info unavailable
|
||||
logger.Infof("⚠️ FormatQuantity: failed to get market info for %s, using default precision: %v", symbol, err)
|
||||
return fmt.Sprintf("%.4f", quantity), nil
|
||||
}
|
||||
format := fmt.Sprintf("%%.%df", marketInfo.SizeDecimals)
|
||||
return fmt.Sprintf(format, quantity), nil
|
||||
}
|
||||
|
||||
// GetOrderBook Get order book (implements GridTrader interface)
|
||||
|
||||
Reference in New Issue
Block a user