This commit addresses the issue where switching to English still showed Chinese text in many UI elements.
Changes made:
- Added 40+ missing translation keys to translations.ts for both English and Chinese
- Updated App.tsx to use t() function for all hardcoded text (logout button, loading message)
- Updated AITradersPage.tsx extensively:
- Replaced all alert/confirm messages with translation keys
- Updated status labels (inUse, enabled, configured)
- Updated all modal components (SignalSource, ModelConfig, ExchangeConfig)
- Added language prop to all modal components
- Replaced all Chinese UI text with translation function calls
The implementation now properly supports language switching between English and Chinese throughout the entire application.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- add logo
- Replaced emoji placeholders with Lucide icons in AITradersPage, CompetitionPage, EquityChart, Header, LoginPage, and RegisterPage for improved visual consistency.
- Updated button styles to include icons for actions like adding models and exchanges.
- Enhanced error and empty state displays with relevant icons to provide better user feedback.
- Add specific field validation for Aster exchange (asterUser, asterSigner, asterPrivateKey)
- Add specific field validation for Hyperliquid exchange (apiKey, hyperliquidWalletAddr)
- Keep existing validation for Binance (apiKey, secretKey)
- Remove debug console logs
- Fix issue where Aster exchange was not appearing in trader creation dropdown
This ensures all three supported exchanges can be properly selected when creating a new AI trader.
Problem:
- Leaderboard used ai_model-based colors (qwen=purple, other=blue)
- Performance Comparison used index-based colors (10 color pool)
- This caused color mismatch between the two components
- Same trader showed different colors in different sections
Solution:
- Create shared color utility (utils/traderColors.ts)
- Define single color pool with 10 distinct colors
- Implement unified getTraderColor function based on trader index
- Update both ComparisonChart and CompetitionPage to use shared utility
Changes:
- New file: web/src/utils/traderColors.ts (shared color logic)
- Updated: ComparisonChart.tsx (use shared utility)
- Updated: CompetitionPage.tsx (use shared utility in Leaderboard
and Head-to-Head sections)
Now traders consistently display the same color across all UI sections.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Problem:
- Multiple traders using the same AI model had duplicate colors
- Only 2 colors were available (blue for deepseek, purple for qwen)
- Made it difficult to distinguish between traders
Solution:
- Expand color pool from 2 to 10 distinct colors
- Change color assignment from ai_model-based to index-based
- Each trader now gets a unique color based on their position
- Colors cycle if there are more than 10 traders
Color pool includes: blue, purple, emerald, orange, pink, amber,
sky, violet, green, rose
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Frontend changes:
- Update TradeOutcome interface with new fields:
- quantity: Position size
- leverage: Leverage multiplier
- position_value: Total position value
- margin_used: Margin required
- Add position details display in trade cards:
- Quantity (with 4 decimal precision)
- Leverage (shown as "50x")
- Position Value (shown as "$10000.00")
- Margin Used (shown as "$200.00")
Visual design:
- 2x2 grid layout for position details
- Color coding: Leverage in gold, Margin in purple
- Conditional rendering with fallback "-" for missing data
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Previously, ComparisonChart was hardcoded to only fetch equity history
data for the first 2 traders, causing the 3rd and subsequent traders'
data to not be displayed on the chart.
Changes:
- Replaced multiple individual useSWR calls with single consolidated call
- Use Promise.all() to fetch all traders' equity data concurrently
- Generate dynamic cache key based on all trader IDs
- Maintain backward compatibility with existing component structure
- Update useMemo dependencies to properly track data changes
This fix allows the comparison chart to properly display any number of
competing traders, not just 2.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Root cause:
ComparisonChart was calling useSWR hooks dynamically inside a .map() loop,
which violates React's Rules of Hooks. When the traders array length changed
(e.g., from 0 to 2, or during initial load), the number of hook calls would
change between renders, triggering React Error #310.
Previous code:
```tsx
const traderHistories = traders.map((trader) => {
return useSWR(`equity-history-${trader.trader_id}`, ...); // ❌ Dynamic hooks
});
```
The eslint-disable comment on line 24 was masking this critical issue.
Fix:
- Always call exactly 2 useSWR hooks (trader1, trader2) unconditionally
- Pass null as the key when trader doesn't exist (SWR handles this gracefully)
- Build traderHistories array from these fixed hooks
- Ensures same number of hooks called on every render
This follows React's Rules of Hooks:
✅ Only call hooks at the top level
✅ Don't call hooks inside loops, conditions, or nested functions
✅ Call hooks in the same order every render
Fixes: React Error #310 (Rendered more hooks than during previous render)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Root cause analysis:
The previous fix (0cb1f37) only addressed App.tsx Debug Info section,
but missed CompetitionPage.tsx which also directly accesses trader data
fields without null safety checks.
When competition data is loading or incomplete, trader objects may exist
but contain undefined fields (total_pnl, total_equity, etc.), causing:
"TypeError: Cannot read properties of undefined (reading 'total_pnl')"
Fixed locations in CompetitionPage.tsx:
1. Line 76-77: Leader display in header (total_pnl, total_pnl_pct)
2. Line 142: Leaderboard total_equity display
3. Line 151-157: Leaderboard P&L section (total_pnl checks and displays)
4. Line 229-230: Head-to-Head comparison (total_pnl display)
Changes applied:
- Replace direct property access with optional chaining (?.)
- Use nullish coalescing (?? 0) for numeric comparisons
- Add fallback values ('0.00') for undefined fields
- Ensure consistent null safety across all trader data displays
This completes the null safety coverage for the entire frontend.
Fixes: TypeError in CompetitionPage at index-R21Yay1P.js:116:51447
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>