feat(agent): add market hours check for stock trades

- execute_trade: warn user when US market is closed (order queued for next open)
- get_market_price: include market_open/market_status for stock quotes
- Uses Alpaca's /v2/clock endpoint via IsMarketOpen() interface
- Prevents surprise queued orders during off-hours
This commit is contained in:
shinchan-zhai
2026-03-23 20:49:59 +08:00
parent 0e338558d4
commit cd6fe62e16
4 changed files with 57 additions and 10 deletions

View File

@@ -322,6 +322,9 @@ func (at *AutoTrader) executeCloseLongWithRecord(decision *kernel.Decision, acti
logger.Infof(" 🗑️ Cancelled stop/TP orders for %s", decision.Symbol)
}
// Record quantity in action record (was missing — close decisions showed 0 quantity in history)
actionRecord.Quantity = quantity
// Close position
order, err := at.trader.CloseLong(decision.Symbol, 0) // 0 = close all
if err != nil {
@@ -387,6 +390,9 @@ func (at *AutoTrader) executeCloseShortWithRecord(decision *kernel.Decision, act
logger.Infof(" 📊 Using exchange position data: qty=%.8f, entry=%.2f", quantity, entryPrice)
}
// Record quantity in action record (was missing — close decisions showed 0 quantity in history)
actionRecord.Quantity = quantity
// Cancel existing stop-loss and take-profit orders BEFORE closing position
// Critical: orphaned SL/TP orders could trigger after position is closed and create unintended positions
if err := at.trader.CancelStopOrders(decision.Symbol); err != nil {

View File

@@ -276,7 +276,7 @@ func (t *HyperliquidTrader) GetMarketPrice(symbol string) (float64, error) {
if err == nil {
return priceFloat, nil
}
return 0, fmt.Errorf("price format error: %v", err)
return 0, fmt.Errorf("price format error: %w", err)
}
return 0, fmt.Errorf("price not found for %s", symbol)
@@ -335,7 +335,7 @@ func (t *HyperliquidTrader) getXyzMarketPrice(coin string) (float64, error) {
if err == nil {
return priceFloat, nil
}
return 0, fmt.Errorf("price format error: %v", err)
return 0, fmt.Errorf("price format error: %w", err)
}
return 0, fmt.Errorf("xyz dex price not found for %s (lookup key: %s)", coin, lookupKey)