fix: Alpaca integration bugs — field mapping, market hours, stock symbol handling

- Fix critical bug: Alpaca GetBalance returns wrong field names (total_equity
  vs totalEquity) — auto_trader was getting 0 equity, breaking all decisions
- Fix critical bug: Alpaca GetPositions missing positionAmt/unRealizedProfit
  fields — positions invisible to trading AI
- Fix CancelAllOrders: was nuking ALL orders globally, now filters by symbol
- Implement GetClosedPnL: was returning nil, now returns filled sell orders
- Add IsMarketOpen: checks Alpaca clock endpoint for market hours
- Add market hours check in trading loop: skip cycles when US market closed
  (saves LLM tokens and prevents failed orders)
- Fix parseTradeCommand: 'BUY AAPL 10' no longer becomes 'AAPLUSDT'
- Fix toolGetMarketPrice: route stock symbols to Alpaca, crypto to others
- Add exchange field to toolGetPositions output for multi-exchange clarity
This commit is contained in:
shinchan-zhai
2026-03-23 19:05:25 +08:00
parent d0aebe9f18
commit bbaa109223
4 changed files with 138 additions and 20 deletions

View File

@@ -6,6 +6,7 @@ import (
"nofx/kernel"
"nofx/logger"
"nofx/store"
"nofx/trader/alpaca"
"nofx/wallet"
"strings"
"time"
@@ -33,6 +34,19 @@ func (at *AutoTrader) runCycle() error {
at.checkClaw402Balance()
}
// Check market hours for stock exchanges (Alpaca)
if at.exchange == "alpaca" {
if alpacaTrader, ok := at.trader.(*alpaca.AlpacaTrader); ok {
isOpen, status, err := alpacaTrader.IsMarketOpen()
if err != nil {
logger.Warnf("⚠️ [%s] Failed to check market clock: %v", at.name, err)
} else if !isOpen {
logger.Infof("🔒 [%s] US stock market %s — skipping trading cycle #%d", at.name, status, at.callCount)
return nil
}
}
}
// Create decision record
record := &store.DecisionRecord{
ExecutionLog: []string{},