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

@@ -274,6 +274,7 @@ func (a *Agent) toolGetPositions() string {
}
positions = append(positions, map[string]any{
"trader": tid,
"exchange": t.GetExchange(),
"symbol": p["symbol"],
"side": p["side"],
"size": size,
@@ -339,11 +340,20 @@ func (a *Agent) toolGetMarketPrice(argsJSON string) string {
return `{"error": "no trader manager configured"}`
}
wantStock := isStockSymbol(sym)
for _, t := range a.traderManager.GetAllTraders() {
underlying := t.GetUnderlyingTrader()
if underlying == nil {
continue
}
// Route to correct exchange type (stock vs crypto)
isAlpaca := t.GetExchange() == "alpaca"
if wantStock && !isAlpaca {
continue
}
if !wantStock && isAlpaca {
continue
}
price, err := underlying.GetMarketPrice(sym)
if err == nil && price > 0 {
result, _ := json.Marshal(map[string]any{