diff --git a/web/package-lock.json b/web/package-lock.json index a117b2cb..e50b08cc 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -84,7 +84,6 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, - "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -1549,7 +1548,6 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.26.tgz", "integrity": "sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA==", "devOptional": true, - "peer": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -1600,7 +1598,6 @@ "integrity": "sha512-6m1I5RmHBGTnUGS113G04DMu3CpSdxCAU/UvtjNWL4Nuf3MW9tQhiJqRlHzChIkhy6kZSAQmc+I1bcGjE3yNKg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.46.3", "@typescript-eslint/types": "8.46.3", @@ -1839,7 +1836,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2214,7 +2210,6 @@ "url": "https://github.com/sponsors/ai" } ], - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.19", "caniuse-lite": "^1.0.30001751", @@ -3107,7 +3102,6 @@ "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -3168,7 +3162,6 @@ "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "dev": true, "license": "MIT", - "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -4553,7 +4546,6 @@ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "dev": true, - "peer": true, "bin": { "jiti": "bin/jiti.js" } @@ -5408,7 +5400,6 @@ "url": "https://github.com/sponsors/ai" } ], - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -5562,7 +5553,6 @@ "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "dev": true, "license": "MIT", - "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -5635,7 +5625,6 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -5647,7 +5636,6 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", - "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -6611,7 +6599,6 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, - "peer": true, "engines": { "node": ">=12" }, @@ -6752,7 +6739,6 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -6860,7 +6846,6 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", "dev": true, - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", @@ -6952,7 +6937,6 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, - "peer": true, "engines": { "node": ">=12" }, @@ -7203,7 +7187,6 @@ "integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==", "dev": true, "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/web/src/App.tsx b/web/src/App.tsx index b57081c5..a7e6d82b 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -1039,12 +1039,17 @@ function DecisionCard({ 保证金率: {decision.account_state.margin_used_pct.toFixed(1)}% 持仓: {decision.account_state.position_count} - - {t('candidateCoins', language)}: {decision.candidate_coins?.length || 0} + + {t('candidateCoins', language)}:{' '} + {decision.candidate_coins?.length || 0} )} @@ -1056,12 +1061,14 @@ function DecisionCard({ style={{ background: 'rgba(246, 70, 93, 0.1)', border: '1px solid rgba(246, 70, 93, 0.3)', - color: '#F6465D' + color: '#F6465D', }} >
-
⚠️ {t('candidateCoinsZeroWarning', language)}
+
+ ⚠️ {t('candidateCoinsZeroWarning', language)} +
{t('possibleReasons', language)}
    diff --git a/web/src/components/EquityChart.tsx b/web/src/components/EquityChart.tsx index 46ce49b0..5b520feb 100644 --- a/web/src/components/EquityChart.tsx +++ b/web/src/components/EquityChart.tsx @@ -113,9 +113,12 @@ export function EquityChart({ traderId }: EquityChartProps) { : validHistory // 计算初始余额(优先从 account 获取配置的初始余额,备选从历史数据反推) - const initialBalance = account?.initial_balance // 从交易员配置读取真实初始余额 - || (validHistory[0] ? validHistory[0].total_equity - validHistory[0].pnl : undefined) // 备选:淨值 - 盈亏 - || 1000; // 默认值(与创建交易员时的默认配置一致) + const initialBalance = + account?.initial_balance || // 从交易员配置读取真实初始余额 + (validHistory[0] + ? validHistory[0].total_equity - validHistory[0].pnl + : undefined) || // 备选:淨值 - 盈亏 + 1000 // 默认值(与创建交易员时的默认配置一致) // 转换数据格式 const chartData = displayHistory.map((point) => { diff --git a/web/src/components/TraderConfigModal.tsx b/web/src/components/TraderConfigModal.tsx index c8c75a38..b5f48cf6 100644 --- a/web/src/components/TraderConfigModal.tsx +++ b/web/src/components/TraderConfigModal.tsx @@ -102,7 +102,7 @@ export function TraderConfigModal({ } // 确保旧数据也有默认的 system_prompt_template if (traderData && traderData.system_prompt_template === undefined) { - setFormData(prev => ({ + setFormData((prev) => ({ ...prev, system_prompt_template: 'default', })) @@ -186,42 +186,45 @@ export function TraderConfigModal({ const handleFetchCurrentBalance = async () => { if (!isEditMode || !traderData?.trader_id) { - setBalanceFetchError('只有在编辑模式下才能获取当前余额'); - return; + setBalanceFetchError('只有在编辑模式下才能获取当前余额') + return } - setIsFetchingBalance(true); - setBalanceFetchError(''); + setIsFetchingBalance(true) + setBalanceFetchError('') try { - const token = localStorage.getItem('token'); - const response = await fetch(`/api/account?trader_id=${traderData.trader_id}`, { - headers: { - 'Authorization': `Bearer ${token}` + const token = localStorage.getItem('token') + const response = await fetch( + `/api/account?trader_id=${traderData.trader_id}`, + { + headers: { + Authorization: `Bearer ${token}`, + }, } - }); + ) if (!response.ok) { - throw new Error('获取账户余额失败'); + throw new Error('获取账户余额失败') } - const data = await response.json(); + const data = await response.json() // total_equity = 当前账户净值(包含未实现盈亏) // 这应该作为新的初始余额 - const currentBalance = data.total_equity || data.balance || 0; + const currentBalance = data.total_equity || data.balance || 0 - setFormData(prev => ({ ...prev, initial_balance: currentBalance })); + setFormData((prev) => ({ ...prev, initial_balance: currentBalance })) // 显示成功提示 - console.log('已获取当前余额:', currentBalance); + console.log('已获取当前余额:', currentBalance) } catch (error) { - console.error('获取余额失败:', error); - setBalanceFetchError('获取余额失败,请检查网络连接'); + console.error('获取余额失败:', error) + setBalanceFetchError('获取余额失败,请检查网络连接') } finally { - setIsFetchingBalance(false); + setIsFetchingBalance(false) } - }; + } const handleSave = async () => { if (!onSave) return @@ -390,7 +393,9 @@ export function TraderConfigModal({
    {isEditMode && (
diff --git a/web/src/i18n/translations.ts b/web/src/i18n/translations.ts index bbdd405e..6916544a 100644 --- a/web/src/i18n/translations.ts +++ b/web/src/i18n/translations.ts @@ -483,15 +483,19 @@ export const translations = { candidateCoins: 'Candidate Coins', candidateCoinsZeroWarning: 'Candidate Coins Count is 0', possibleReasons: 'Possible Reasons:', - coinPoolApiNotConfigured: 'Coin pool API not configured or inaccessible (check signal source settings)', + coinPoolApiNotConfigured: + 'Coin pool API not configured or inaccessible (check signal source settings)', apiConnectionTimeout: 'API connection timeout or returned empty data', - noCustomCoinsAndApiFailed: 'No custom coins configured and API fetch failed', + noCustomCoinsAndApiFailed: + 'No custom coins configured and API fetch failed', solutions: 'Solutions:', setCustomCoinsInConfig: 'Set custom coin list in trader configuration', orConfigureCorrectApiUrl: 'Or configure correct coin pool API address', - orDisableCoinPoolOptions: 'Or disable "Use Coin Pool" and "Use OI Top" options', + orDisableCoinPoolOptions: + 'Or disable "Use Coin Pool" and "Use OI Top" options', signalSourceNotConfigured: 'Signal Source Not Configured', - signalSourceWarningMessage: 'You have traders that enabled "Use Coin Pool" or "Use OI Top", but signal source API address is not configured yet. This will cause candidate coins count to be 0, and traders cannot work properly.', + signalSourceWarningMessage: + 'You have traders that enabled "Use Coin Pool" or "Use OI Top", but signal source API address is not configured yet. This will cause candidate coins count to be 0, and traders cannot work properly.', configureSignalSourceNow: 'Configure Signal Source Now', }, zh: { @@ -948,7 +952,8 @@ export const translations = { orConfigureCorrectApiUrl: '或者配置正确的币种池API地址', orDisableCoinPoolOptions: '或者禁用"使用币种池"和"使用OI Top"选项', signalSourceNotConfigured: '信号源未配置', - signalSourceWarningMessage: '您有交易员启用了"使用币种池"或"使用OI Top",但尚未配置信号源API地址。这将导致候选币种数量为0,交易员无法正常工作。', + signalSourceWarningMessage: + '您有交易员启用了"使用币种池"或"使用OI Top",但尚未配置信号源API地址。这将导致候选币种数量为0,交易员无法正常工作。', configureSignalSourceNow: '立即配置信号源', }, } diff --git a/web/src/lib/api.ts b/web/src/lib/api.ts index 04592e95..1257af2e 100644 --- a/web/src/lib/api.ts +++ b/web/src/lib/api.ts @@ -330,13 +330,13 @@ export const api = { // 获取服务器IP(需要认证,用于白名单配置) async getServerIP(): Promise<{ - public_ip: string; - message: string; + public_ip: string + message: string }> { const res = await fetch(`${API_BASE}/server-ip`, { headers: getAuthHeaders(), - }); - if (!res.ok) throw new Error('获取服务器IP失败'); - return res.json(); + }) + if (!res.ok) throw new Error('获取服务器IP失败') + return res.json() }, -}; +}