import React, { useState, useEffect } from 'react'; import useSWR from 'swr'; import { api } from '../lib/api'; import type { TraderInfo, CreateTraderRequest, AIModel, Exchange } from '../types'; import { useLanguage } from '../contexts/LanguageContext'; import { t } from '../i18n/translations'; export function AITradersPage() { const { language } = useLanguage(); const [showCreateModal, setShowCreateModal] = useState(false); const [showModelModal, setShowModelModal] = useState(false); const [showExchangeModal, setShowExchangeModal] = useState(false); const [editingModel, setEditingModel] = useState(null); const [editingExchange, setEditingExchange] = useState(null); const [allModels, setAllModels] = useState([]); const [allExchanges, setAllExchanges] = useState([]); const { data: traders, mutate: mutateTraders } = useSWR( 'traders', api.getTraders, { refreshInterval: 5000 } ); // 加载AI模型和交易所配置 useEffect(() => { const loadConfigs = async () => { try { const [modelConfigs, exchangeConfigs] = await Promise.all([ api.getModelConfigs(), api.getExchangeConfigs() ]); setAllModels(modelConfigs); setAllExchanges(exchangeConfigs); } catch (error) { console.error('Failed to load configs:', error); } }; loadConfigs(); }, []); // 只显示已配置的模型和交易所 const configuredModels = allModels.filter(m => m.enabled && m.apiKey); const configuredExchanges = allExchanges.filter(e => e.enabled && e.apiKey && (e.id === 'hyperliquid' || e.secretKey)); // 检查模型是否正在被运行中的交易员使用 const isModelInUse = (modelId: string) => { return traders?.some(t => t.ai_model === modelId && t.is_running) || false; }; // 检查交易所是否正在被运行中的交易员使用 const isExchangeInUse = (exchangeId: string) => { return traders?.some(t => t.exchange_id === exchangeId && t.is_running) || false; }; const handleCreateTrader = async (modelId: string, exchangeId: string, name: string, initialBalance: number) => { try { const model = allModels.find(m => m.id === modelId); const exchange = allExchanges.find(e => e.id === exchangeId); if (!model?.enabled) { alert(t('modelNotConfigured', language)); return; } if (!exchange?.enabled) { alert(t('exchangeNotConfigured', language)); return; } const request: CreateTraderRequest = { name, ai_model_id: modelId, exchange_id: exchangeId, initial_balance: initialBalance }; await api.createTrader(request); setShowCreateModal(false); mutateTraders(); } catch (error) { console.error('Failed to create trader:', error); alert('创建交易员失败'); } }; const handleDeleteTrader = async (traderId: string) => { if (!confirm(t('confirmDeleteTrader', language))) return; try { await api.deleteTrader(traderId); mutateTraders(); } catch (error) { console.error('Failed to delete trader:', error); alert('删除交易员失败'); } }; const handleToggleTrader = async (traderId: string, running: boolean) => { try { if (running) { await api.stopTrader(traderId); } else { await api.startTrader(traderId); } mutateTraders(); } catch (error) { console.error('Failed to toggle trader:', error); alert('操作失败'); } }; const handleModelClick = (modelId: string) => { if (!isModelInUse(modelId)) { setEditingModel(modelId); setShowModelModal(true); } }; const handleExchangeClick = (exchangeId: string) => { if (!isExchangeInUse(exchangeId)) { setEditingExchange(exchangeId); setShowExchangeModal(true); } }; const handleDeleteModelConfig = async (modelId: string) => { if (!confirm('确定要删除此AI模型配置吗?')) return; try { const updatedModels = allModels.map(m => m.id === modelId ? { ...m, apiKey: '', enabled: false } : m ); const request = { models: Object.fromEntries( updatedModels.map(model => [ model.id, { enabled: model.enabled, api_key: model.apiKey || '' } ]) ) }; await api.updateModelConfigs(request); setAllModels(updatedModels); setShowModelModal(false); setEditingModel(null); } catch (error) { console.error('Failed to delete model config:', error); alert('删除配置失败'); } }; const handleSaveModelConfig = async (modelId: string, apiKey: string) => { try { const updatedModels = allModels.map(m => m.id === modelId ? { ...m, apiKey, enabled: true } : m ); const request = { models: Object.fromEntries( updatedModels.map(model => [ model.id, { enabled: model.enabled, api_key: model.apiKey || '' } ]) ) }; await api.updateModelConfigs(request); setAllModels(updatedModels); setShowModelModal(false); setEditingModel(null); } catch (error) { console.error('Failed to save model config:', error); alert('保存配置失败'); } }; const handleDeleteExchangeConfig = async (exchangeId: string) => { if (!confirm('确定要删除此交易所配置吗?')) return; try { const updatedExchanges = allExchanges.map(e => e.id === exchangeId ? { ...e, apiKey: '', secretKey: '', enabled: false } : e ); const request = { exchanges: Object.fromEntries( updatedExchanges.map(exchange => [ exchange.id, { enabled: exchange.enabled, api_key: exchange.apiKey || '', secret_key: exchange.secretKey || '', testnet: exchange.testnet || false } ]) ) }; await api.updateExchangeConfigs(request); setAllExchanges(updatedExchanges); setShowExchangeModal(false); setEditingExchange(null); } catch (error) { console.error('Failed to delete exchange config:', error); alert('删除交易所配置失败'); } }; const handleSaveExchangeConfig = async (exchangeId: string, apiKey: string, secretKey?: string, testnet?: boolean) => { try { const updatedExchanges = allExchanges.map(e => e.id === exchangeId ? { ...e, apiKey, secretKey, testnet, enabled: true } : e ); const request = { exchanges: Object.fromEntries( updatedExchanges.map(exchange => [ exchange.id, { enabled: exchange.enabled, api_key: exchange.apiKey || '', secret_key: exchange.secretKey || '', testnet: exchange.testnet || false } ]) ) }; await api.updateExchangeConfigs(request); setAllExchanges(updatedExchanges); setShowExchangeModal(false); setEditingExchange(null); } catch (error) { console.error('Failed to save exchange config:', error); alert('保存交易所配置失败'); } }; const handleAddModel = () => { setEditingModel(null); setShowModelModal(true); }; const handleAddExchange = () => { setEditingExchange(null); setShowExchangeModal(true); }; return (
{/* Header */}
🤖

{t('aiTraders', language)} {traders?.length || 0} {t('active', language)}

{t('manageAITraders', language)}

{/* Configuration Status */}
{/* AI Models */}

🧠 {t('aiModels', language)}

{configuredModels.map(model => { const inUse = isModelInUse(model.id); return (
handleModelClick(model.id)} >
{model.name[0]}
{model.name}
{t('configured', language)}
); })} {configuredModels.length === 0 && (
🧠
暂无已配置的AI模型
)}
{/* Exchanges */}

🏦 {t('exchanges', language)}

{configuredExchanges.map(exchange => { const inUse = isExchangeInUse(exchange.id); return (
handleExchangeClick(exchange.id)} >
{exchange.name[0]}
{exchange.name}
{exchange.type.toUpperCase()} • {t('configured', language)}
); })} {configuredExchanges.length === 0 && (
🏦
暂无已配置的交易所
)}
{/* Traders List */}

👥 {t('currentTraders', language)}

{traders && traders.length > 0 ? (
{traders.map(trader => (
🤖
{trader.trader_name}
{trader.ai_model.toUpperCase()} Model • {trader.exchange_id?.toUpperCase()}
{/* Status */}
{t('status', language)}
{trader.is_running ? t('running', language) : t('stopped', language)}
{/* Actions */}
))}
) : (
🤖
{t('noTraders', language)}
{t('createFirstTrader', language)}
{(configuredModels.length === 0 || configuredExchanges.length === 0) && (
{configuredModels.length === 0 && configuredExchanges.length === 0 ? t('configureModelsAndExchangesFirst', language) : configuredModels.length === 0 ? t('configureModelsFirst', language) : t('configureExchangesFirst', language) }
)}
)}
{/* Create Trader Modal */} {showCreateModal && ( setShowCreateModal(false)} language={language} /> )} {/* Model Configuration Modal */} {showModelModal && ( { setShowModelModal(false); setEditingModel(null); }} language={language} /> )} {/* Exchange Configuration Modal */} {showExchangeModal && ( { setShowExchangeModal(false); setEditingExchange(null); }} language={language} /> )}
); } // Create Trader Modal Component function CreateTraderModal({ enabledModels, enabledExchanges, onCreate, onClose, language }: { enabledModels: AIModel[]; enabledExchanges: Exchange[]; onCreate: (modelId: string, exchangeId: string, name: string, initialBalance: number) => void; onClose: () => void; language: any; }) { // 默认选择DeepSeek模型,如果没有启用则选择第一个 const defaultModel = enabledModels.find(m => m.id === 'deepseek') || enabledModels[0]; // 默认选择Binance交易所,如果没有启用则选择第一个 const defaultExchange = enabledExchanges.find(e => e.id === 'binance') || enabledExchanges[0]; const [selectedModel, setSelectedModel] = useState(defaultModel?.id || ''); const [selectedExchange, setSelectedExchange] = useState(defaultExchange?.id || ''); const [traderName, setTraderName] = useState(''); const [initialBalance, setInitialBalance] = useState(1000); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); if (!selectedModel || !selectedExchange || !traderName.trim()) return; onCreate(selectedModel, selectedExchange, traderName.trim(), initialBalance); }; return (

{t('createNewTrader', language)}

setTraderName(e.target.value)} placeholder={t('enterTraderName', language)} className="w-full px-3 py-2 rounded" style={{ background: '#0B0E11', border: '1px solid #2B3139', color: '#EAECEF' }} required />
setInitialBalance(Number(e.target.value))} min="100" max="100000" className="w-full px-3 py-2 rounded" style={{ background: '#0B0E11', border: '1px solid #2B3139', color: '#EAECEF' }} required />
); } // Model Configuration Modal Component function ModelConfigModal({ allModels, editingModelId, onSave, onDelete, onClose, language }: { allModels: AIModel[]; editingModelId: string | null; onSave: (modelId: string, apiKey: string) => void; onDelete: (modelId: string) => void; onClose: () => void; language: any; }) { const [selectedModelId, setSelectedModelId] = useState(editingModelId || ''); const [apiKey, setApiKey] = useState(''); // 获取当前编辑的模型信息 const selectedModel = allModels.find(m => m.id === selectedModelId); // 如果是编辑现有模型,初始化API Key useEffect(() => { if (editingModelId && selectedModel) { setApiKey(selectedModel.apiKey || ''); } }, [editingModelId, selectedModel]); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); if (!selectedModelId || !apiKey.trim()) return; onSave(selectedModelId, apiKey.trim()); }; // 可选择的模型列表(排除已配置的,除非是当前编辑的) const availableModels = allModels.filter(m => !m.enabled || !m.apiKey || m.id === editingModelId ); return (

{editingModelId ? '编辑AI模型' : '添加AI模型'}

{!editingModelId && (
)} {selectedModel && (
{selectedModel.name[0]}
{selectedModel.name}
{selectedModel.provider}
setApiKey(e.target.value)} placeholder={`请输入 ${selectedModel.name} API Key`} className="w-full px-3 py-2 rounded" style={{ background: '#1E2329', border: '1px solid #2B3139', color: '#EAECEF' }} required />
)}
{editingModelId && ( )}
); } // Exchange Configuration Modal Component function ExchangeConfigModal({ allExchanges, editingExchangeId, onSave, onDelete, onClose, language }: { allExchanges: Exchange[]; editingExchangeId: string | null; onSave: (exchangeId: string, apiKey: string, secretKey?: string, testnet?: boolean) => void; onDelete: (exchangeId: string) => void; onClose: () => void; language: any; }) { const [selectedExchangeId, setSelectedExchangeId] = useState(editingExchangeId || ''); const [apiKey, setApiKey] = useState(''); const [secretKey, setSecretKey] = useState(''); const [testnet, setTestnet] = useState(false); // 获取当前编辑的交易所信息 const selectedExchange = allExchanges.find(e => e.id === selectedExchangeId); // 如果是编辑现有交易所,初始化表单数据 useEffect(() => { if (editingExchangeId && selectedExchange) { setApiKey(selectedExchange.apiKey || ''); setSecretKey(selectedExchange.secretKey || ''); setTestnet(selectedExchange.testnet || false); } }, [editingExchangeId, selectedExchange]); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); if (!selectedExchangeId || !apiKey.trim()) return; if (selectedExchange?.id !== 'hyperliquid' && !secretKey.trim()) return; onSave(selectedExchangeId, apiKey.trim(), secretKey.trim(), testnet); }; // 可选择的交易所列表(排除已配置的,除非是当前编辑的) const availableExchanges = allExchanges.filter(e => !e.enabled || !e.apiKey || e.id === editingExchangeId ); return (

{editingExchangeId ? '编辑交易所' : '添加交易所'}

{!editingExchangeId && (
)} {selectedExchange && (
{selectedExchange.name[0]}
{selectedExchange.name}
{selectedExchange.type.toUpperCase()}
setApiKey(e.target.value)} placeholder={selectedExchange.id === 'hyperliquid' ? '请输入以太坊私钥' : `请输入 ${selectedExchange.name} API Key`} className="w-full px-3 py-2 rounded" style={{ background: '#1E2329', border: '1px solid #2B3139', color: '#EAECEF' }} required />
{selectedExchange.id !== 'hyperliquid' && (
setSecretKey(e.target.value)} placeholder={`请输入 ${selectedExchange.name} Secret Key`} className="w-full px-3 py-2 rounded" style={{ background: '#1E2329', border: '1px solid #2B3139', color: '#EAECEF' }} required />
)} {selectedExchange.type === 'dex' && (
setTestnet(e.target.checked)} className="w-4 h-4" />
)}
)}
{editingExchangeId && ( )}
); }