- 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
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
- Agent: add stopCh to cleanly stop chat-history-cleanup goroutine on Agent.Stop()
(previously leaked a goroutine+ticker forever on every restart)
- Agent: add looksLikeStockQuery() guard to avoid hitting Sina search API on every
single message — only calls external API when text contains stock-related content
(saves ~200ms latency + API call on crypto-only queries)
- market/historical.go: safe type assertions in kline parsing (was bare .(float64)
which panics on unexpected API responses), reuse HTTP client for connection pooling
- market/api_client.go: safe comma-ok type assertions for all kline field parsing
(11 bare assertions → all guarded)
- trader/bybit: fix unsafe type assertion in CloseShort — pos["positionAmt"].(float64)
could panic if field is nil/wrong type (critical: handles real money)
- trader/alpaca/: Full Trader interface implementation for Alpaca
- Paper/Live trading support (market orders, stop/limit)
- GetBalance, GetPositions, GetMarketPrice via Alpaca API
- Fractional share support (4 decimal places)
- Commission-free trading
- Agent trade routing: stock symbols (AAPL, TSLA) → Alpaca
- isStockSymbol() heuristic to distinguish crypto vs stock
- execute_trade tool updated for stock buy/sell semantics
- get_market_price works for both crypto and stocks
- TraderManager + API: Alpaca registered as exchange type
- Factory case in auto_trader.go
- Config mapping in trader_manager.go
- Temp trader creation in handler_trader.go for balance query
- Frontend: PositionsPanel distinguishes stock vs crypto
- US flag emoji for stock positions
- Dollar prefix for stock PnL/prices
- 'Shares' label instead of 'Qty' for stocks
- System prompts updated for stock trading capabilities
- Guard GridCount-1 division by zero in grid spacing calculation (both grid.go and grid_levels.go)
- Rate-limit /wallet/validate and /wallet/generate endpoints (prevent DoS on key generation)
- Wrap JSON.parse(localStorage) in try-catch in AuthContext (corrupted data → graceful re-login)
- Wrap handleJSONResponse JSON.parse in try-catch with descriptive error
- Add HTTP status code checks for Lighter GetActiveOrders and sendTx
- Replace deprecated strings.Title with cases.Title (golang.org/x/text)
- Reuse HTTP client in checkClaw402Health (was creating new client per call)
- Propagate request context through MCP client (Request.Ctx field)
— Client disconnects now cancel in-flight LLM API calls (both streaming and non-streaming)
— Prevents wasted LLM tokens when user navigates away mid-response
- proxyBinance: use http.NewRequestWithContext for context-aware upstream calls
— Client disconnects cancel Binance proxy requests
— Distinguishes client cancellation from upstream failures
- Fix SSE parse bug in AgentChatPage: catch block was swallowing error events
— throw new Error(data) for 'error' events was caught by the same try/catch
— Now parse JSON separately, then handle events outside try/catch
- Add io.LimitReader to Hyperliquid coins.go JSON decoder (4MB limit)
- Use safe.ReadAllLimited in batch ticker handler for consistency
- Sanitize URL validation error in handler_ai_model.go (was leaking raw error)
- Cache agent tool definitions (built once, reused per message)
- Sort trade history by exit time for consistent ordering
- Fix thinkAndActStream: emit delta event for non-tool responses (was silent)
- Add fallback to streaming on first LLM call failure
- Add batch ticker endpoint /api/agent/tickers (3 API calls → 1)
- Update MarketTicker to use batch endpoint, remove unused state
- Warn loudly when JWT_SECRET uses default value
- Fix 华为 mapping (was incorrectly mapped to Tencent)
- Replace ioutil.ReadAll with safe.ReadAllLimited in nofxos client
- Remove unused variable in hyperliquid trader_account
- Wrap CoinAnk WS readers with safe.GoNamed for panic recovery
- Use 100dvh for mobile viewport in AgentChatPage
- console.log → console.warn for auth events
- Agent gatherContext: expand from 10 hardcoded symbols to 38+ known symbols
plus dynamic XXXUSDT pattern extraction (caps at 5 to avoid slow context)
- Add get_trade_history tool: LLM can now query closed trades with PnL summary
(win rate, total PnL, recent N trades across all traders)
- Fix ticker.Stop() leak in ALL 9 exchange order_sync goroutines:
OKX, Hyperliquid, Aster, Bybit, KuCoin, Gate, Bitget, Lighter, Binance
— tickers were never stopped when traders were stopped, leaking goroutines
- agent/agent.go: toFloat() now handles json.Number and int32 types to prevent silent data loss
- api/server.go: CORS fix — echo specific origin instead of '*' when credentials are enabled (browsers reject Allow-Credentials with wildcard)
- api/strategy.go: all 4 json.Unmarshal calls now check errors and return 'config_error' field instead of silently serving zero-value configs
- store/decision.go: explicitly mark best-effort unmarshal with _ = assignment for clarity
- CancelStopOrders: only cancel orders with non-empty TriggerPrice (was canceling ALL orders including regular limit orders — safety bug)
- proxyBinance: return 502 when upstream returns non-200 instead of silently proxying error pages
- Remove redundant CORS headers in agent/web.go (already handled by gin middleware)
Applied safe.GoNamed to:
- 9 exchange order_sync goroutines (OKX, Hyperliquid, Aster, Bybit, KuCoin, Gate, Bitget, Lighter, Binance×2)
- Drawdown monitor (auto_trader_risk.go)
- Brain news scanner + market briefs (agent/brain.go)
- Sentinel scanner (agent/sentinel.go)
- Agent scheduler (agent/scheduler.go)
- x402 idle watchdog (mcp/payment/x402.go)
- MCP stream idle watchdog (mcp/client.go)
- Rate limiter cleanup (api/rate_limiter.go)
- 3 telemetry fire-and-forget sends (telemetry/experience.go)
- CoinAnk WS handler (provider/coinank/coinank_api/kline_ws.go)
- API server goroutine (main.go)
Added manual defer/recover with error reporting to:
- Telegram AI agent handler (sends error msg to user on panic)
- Trader data fetch (returns error result on panic to prevent deadlock)
Before: a panic in ANY of these 27 goroutines would crash the entire
trading process with zero diagnostics. Now all panics are caught, logged
with stack traces, and the process continues running.
Previously when the seen map exceeded 1000 entries, ALL entries were
deleted, losing dedup state and causing re-notifications. Now evicts
~half the entries, preserving recent URLs for dedup continuity.
- System prompt now has absolute rule: no tool result = no price
- Pre-market overview must call search_stock for each major stock
- Index futures explicitly marked as unsupported
- Training data prices explicitly declared outdated and forbidden
- Applied to both CN and EN prompts
- Add strict data truthfulness rules to system prompt (CN + EN)
- Positions MUST come from get_positions tool only
- Balance MUST come from get_balance tool only
- Looking up a stock price != user owns it
- Fix unused variable warnings in hyperliquid trader
- Parse extended hours fields from Sina Finance API (field 21-24)
- Display pre-market/after-hours price, change%, and time in stock quotes
- Update system prompt: stocks have real-time data via search_stock tool
- Remove incorrect 'no real-time stock data' disclaimer
- Add searchStock() using Sina's suggest API (type=11,31,41)
- Supports A-share, HK, and US markets dynamically
- No longer limited to hardcoded knownStocks map
- resolveStockCodeDynamic: tries static map first, then API fallback
- extractStockKeyword: smart keyword extraction from natural language
- New LLM tool 'search_stock': agent can proactively search stocks
- Top 3 search results auto-enriched with real-time quotes
- System prompts updated for both zh/en
- Add chatHistory store (in-memory, per user, last 20 messages)
- Agent now passes full conversation context to LLM via CallWithRequest
- Records both user messages and assistant responses
- Add /clear command to reset conversation history
- Add 'Clear' quick action button in frontend
- Supports natural multi-turn conversations (follow-up questions, context)
NOFXi can now fetch REAL stock prices for A-shares.
Data source: Sina Finance hq.sinajs.cn (free, no API key)
- Name, price, open, prev close, high, low, volume, turnover
- Change % calculated from prev close
- GBK → UTF-8 encoding handled
Stock resolution:
- Known stocks: 拓维信息→sz002261, 贵州茅台→sh600519, etc.
- Auto-detect 6-digit codes in user text
- Prefix detection: 6xx→sh, 0xx/3xx→sz
Context injection:
- Stock data auto-appended to LLM context when user mentions a stock
- AI sees REAL price, volume, change % — cannot fabricate
Tested: '拓维信息这只股,10万元,1个月交易计划'
→ Returns ¥35.57 (real price), -6.71% (real change), 53.94亿成交额
→ Strategy based on actual price levels, not hallucinated
System prompt now explicitly:
- Lists which assets have real-time data (crypto) and which don't (stocks/forex)
- FORBIDS fabricating specific prices
- Requires disclosure: 'based on historical knowledge, not live data'
- Allows strategy frameworks but not fake price levels
Tested: 拓维信息 → now says '我没有A股实时数据' upfront, gives
strategy framework without fake prices. Honesty > confidence.
SSRF protection was blocking AI API calls because Go's custom resolver
couldn't resolve external domains (DNS timeout). curl worked because it
uses the system resolver.
Fix: Agent creates MCP client with standard http.Client (no SSRF filter)
since we control the API URLs.
Tested: '帮我看看拓维信息这只股,我有10万元,帮我制定1个月交易计划'
→ Returns professional A-share analysis with entry/exit strategy in 5.8s
DELETED: agent/router.go (regex-based intent routing)
The fundamental architecture was wrong. A real AI Agent doesn't use
pattern matching to understand users. It uses AI.
New flow:
1. User says anything
2. /help and /status → instant response (no AI needed)
3. Setup keywords → onboard flow
4. EVERYTHING else → LLM with full context
The LLM receives:
- System prompt with NOFXi's capabilities and behavior rules
- Real-time market data (auto-detected from mentioned symbols)
- Live trader positions and status
- User's message
The LLM decides what to do. Not regex. Not if-else. The AI.
This is what makes it an Agent, not a chatbot.
1. Complex natural language → AI chat (not regex analyze)
'拓维信息这个股怎么样帮我写策略' now goes to AI, not broken regex
2. Agent auto-loads AI client from store on startup
- Scans AIModel configs, creates MCP client from first available
- No manual injection needed
3. Added start.sh for one-command startup (backend + frontend)
Routing logic:
- /analyze BTC (simple, ≤3 words) → structured analyze
- Complex sentences → AI chat with full context
- This is the key insight: regex can't parse natural language, AI can
- Crypto: real-time data (market.Get) + AI analysis
- Stocks/Forex: AI answers with its own knowledge (A股/港股/美股/外汇)
- No more 'coming soon' — if AI is configured, it can analyze anything
- Graceful fallback: no AI → guide user to configure
- AI prompt asks for: asset type, fundamentals, trend, key levels, risks
Core behavior change:
- Agent NO LONGER auto-prompts setup on first message
- Setup only triggers on explicit: '开始配置' / 'setup' / '绑定交易所'
- Normal questions answered normally, even without trader configured
- AI analysis works without AI model (shows raw data + guidance)
- Stock analysis shows 'coming soon' instead of error
Intent routing improved:
- '你能分析拓维信息吗' → correctly routes to analyze
- Chinese suffixes cleaned (吗/呢/这只股票)
- More natural language patterns matched
Philosophy: Agent should be helpful from minute one.
Configuration is optional, not a gate.
- Detects when user sends Chinese text, short text, or text with spaces
during key-input steps → auto-pauses setup and answers the question
- API key masking fixed (no more garbled display)
- User can resume setup with '开始配置' anytime
Key changes:
- Agent API routes (/api/agent/*) registered directly on NOFX's :8080 server
- No more separate :8900 port — everything on :8080
- AgentChatPage.tsx added to React frontend
- Agent tab (🤖 Agent) added to navigation bar, set as DEFAULT page
- Branding: NOFX → NOFXi everywhere (title, header, branding.ts, i18n)
- Default landing page is now Agent chat, not competition
This is THE change: there is no more 'NOFX' vs 'NOFXi'.
Users open localhost:8080, they see NOFXi.
Agent chat is the first thing they see.
All other pages (Traders, Dashboard, Strategy, Data) are still there.
One binary. One port. One product. NOFXi.
Users no longer need Web UI to configure NOFXi. The agent guides them
through setup via natural language:
1. First message → agent detects no traders → shows welcome
2. User says '开始配置' or 'setup'
3. Agent asks: which exchange? (1-7, name, or Chinese name)
4. Agent asks: API Key → API Secret → Passphrase (if needed)
5. Agent asks: which AI model? (DeepSeek/Qwen/GPT/Claude/Skip)
6. Agent asks: AI API Key
7. Agent creates Exchange + AIModel + Trader in NOFX store
8. Done. User can immediately start using /analyze, /positions, etc.
Features:
- Full Chinese/English bilingual flow
- Cancel anytime with '取消' or 'cancel'
- State persisted in SystemConfig (survives restarts)
- Supports all 7 exchanges + 4 AI providers
- OKX/Bitget/KuCoin auto-asks for Passphrase
- API keys stored encrypted via NOFX crypto service
Critical fixes:
1. Agent now uses NOFX's MCP client for AI calls (real models, not placeholder)
- Gets AI client from first configured trader's MCP config
- Added AutoTrader.GetMCPClient() export
2. /analyze uses REAL market data (market.Get → EMA/MACD/RSI/BB/OI/funding)
then sends to AI — no more hallucinated prices
3. AI chat enriches prompts with live market data when user mentions a coin
4. Fallback: if AI unavailable, shows raw formatted market data (still useful)
Router improvements:
- Better natural language detection for Chinese
- '该不该买' '走势' '趋势' '行情' → analyze intent
- '多少钱' '赚了' '亏了' → query intent
- Fewer messages falling through to generic chat
Web UI:
- Endpoints updated to /api/agent/* namespace
- nofxi.html served at agent root (localhost:8900)
Result: AI analysis now shows real BTC price, real RSI, real EMA — not fiction.
This is the key architectural change: NOFXi is no longer a separate
sub-project in nofxi/, but a first-class module in agent/ that sits
on top of NOFX's existing engine.
agent/ package:
- agent.go: Core orchestrator, directly uses NOFX's TraderManager,
Store, and Market packages. No wrapper/bridge needed.
- brain.go: Proactive intelligence (news scan, market briefs, signal handling)
- sentinel.go: Market anomaly detection (price breakout, volume spike, funding rate)
- scheduler.go: Daily reports, position risk checks
- router.go: Intent routing for natural language (中/英 bilingual)
- i18n.go: Full Chinese/English message catalog
- web.go: Agent REST API on :8900 (chat, klines, ticker)
main.go changes:
- Banner: NOFX → NOFXi
- Agent auto-starts with NOFX (sentinel + brain + scheduler + web)
- Zero breaking changes to existing NOFX functionality
Key difference from old nofxi/:
- Agent reads LIVE data from TraderManager (positions, balances, status)
- Uses market.Get() for full technical indicators (EMA/MACD/RSI/BB)
- No duplicate code — kernel, trader, store all used directly
- Old nofxi/ sub-project will be removed once migration is verified
Architecture:
NOFX (engine) → kernel + trader + market + store + mcp + telegram
NOFXi (brain) → agent/ package → uses all of the above