mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-14 00:07:01 +08:00
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:
@@ -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{
|
||||
|
||||
@@ -112,7 +112,8 @@ func parseTradeCommand(text string) *TradeAction {
|
||||
return nil
|
||||
}
|
||||
symbol = words[1]
|
||||
if !strings.HasSuffix(symbol, "USDT") {
|
||||
// Only append USDT for crypto symbols, not stock tickers
|
||||
if !isStockSymbol(symbol) && !strings.HasSuffix(symbol, "USDT") {
|
||||
symbol += "USDT"
|
||||
}
|
||||
|
||||
@@ -226,7 +227,10 @@ func formatTradeConfirmation(trade *TradeAction, lang string) string {
|
||||
"close_short": "平空 (Close Short)",
|
||||
}
|
||||
|
||||
symbol := strings.TrimSuffix(trade.Symbol, "USDT")
|
||||
symbol := trade.Symbol
|
||||
if strings.HasSuffix(symbol, "USDT") {
|
||||
symbol = strings.TrimSuffix(symbol, "USDT")
|
||||
}
|
||||
actionName := actionNames[trade.Action]
|
||||
if actionName == "" {
|
||||
actionName = trade.Action
|
||||
@@ -308,7 +312,10 @@ func (a *Agent) handleTradeConfirmation(ctx context.Context, userID int64, text,
|
||||
}
|
||||
|
||||
trade.Status = "executed"
|
||||
symbol := strings.TrimSuffix(trade.Symbol, "USDT")
|
||||
symbol := trade.Symbol
|
||||
if strings.HasSuffix(symbol, "USDT") {
|
||||
symbol = strings.TrimSuffix(symbol, "USDT")
|
||||
}
|
||||
actionEmoji := "📈"
|
||||
if strings.Contains(trade.Action, "short") {
|
||||
actionEmoji = "📉"
|
||||
|
||||
Reference in New Issue
Block a user