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:
shinchan-zhai
2026-03-23 20:18:24 +08:00
parent 7b1cff23bc
commit 06824915a4
5 changed files with 127 additions and 4 deletions

View File

@@ -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
}