feat(crypto-tail): 尾盘策略页币安 API 状态监控与重连间隔调整
- 尾盘策略页:进入时检测币安 API/WebSocket,异常时红色强提醒 - 异常时提供「重新检测」按钮,不跳转 API 健康页、不做 60s 轮询 - 文案面向小白:无法连接币安 API、需行情数据、稍后重新检测 - 多语言:zh-CN/zh-TW/en 新增 cryptoTailStrategy.binanceApiAlert - 币安 K 线 WS 重连延迟由 10s 改为 3s Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+1
-1
@@ -130,7 +130,7 @@ class BinanceKlineService {
|
||||
private fun scheduleReconnect() {
|
||||
if (reconnectJob?.isActive == true) return
|
||||
reconnectJob = scope.launch {
|
||||
delay(10_000)
|
||||
delay(3_000)
|
||||
reconnectJob = null
|
||||
ws5m?.close(1000, "reconnect")
|
||||
ws15m?.close(1000, "reconnect")
|
||||
|
||||
@@ -1402,6 +1402,11 @@
|
||||
"rerunFailed": "Re-run failed"
|
||||
},
|
||||
"cryptoTailStrategy": {
|
||||
"binanceApiAlert": {
|
||||
"title": "Cannot connect to Binance API — strategy cannot run for now",
|
||||
"description": "Tail strategy needs Binance market data to work. The connection failed; this may be a network issue or Binance outage. Try again later by clicking the button below.",
|
||||
"recheck": "Re-check"
|
||||
},
|
||||
"list": {
|
||||
"title": "Crypto Tail Strategy",
|
||||
"walletTip": "Use a dedicated wallet for tail strategy. Do not use it for manual trading or copy trading to avoid balance/position issues.",
|
||||
|
||||
@@ -1401,6 +1401,11 @@
|
||||
"rerunFailed": "重新测试失败"
|
||||
},
|
||||
"cryptoTailStrategy": {
|
||||
"binanceApiAlert": {
|
||||
"title": "无法连接币安 API,策略暂时不能运行",
|
||||
"description": "尾盘策略需要从币安获取行情数据才能工作。当前连接失败,可能是网络问题或币安服务异常,请稍后点击下方按钮重新检测。",
|
||||
"recheck": "重新检测"
|
||||
},
|
||||
"list": {
|
||||
"title": "加密尾盘策略",
|
||||
"walletTip": "请使用单独的钱包运行尾盘策略,避免该钱包用于手动交易、跟单等其他操作,否则可能导致余额或仓位变化,造成策略执行异常。",
|
||||
|
||||
@@ -1402,6 +1402,11 @@
|
||||
"rerunFailed": "重新測試失敗"
|
||||
},
|
||||
"cryptoTailStrategy": {
|
||||
"binanceApiAlert": {
|
||||
"title": "無法連接幣安 API,策略暫時不能運行",
|
||||
"description": "尾盤策略需要從幣安取得行情資料才能運作。目前連線失敗,可能是網路問題或幣安服務異常,請稍後點擊下方按鈕重新檢測。",
|
||||
"recheck": "重新檢測"
|
||||
},
|
||||
"list": {
|
||||
"title": "加密尾盤策略",
|
||||
"walletTip": "請使用單獨的錢包運行尾盤策略,避免該錢包用於手動交易、跟單等其他操作,否則可能導致餘額或倉位變化,造成策略執行異常。",
|
||||
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
Spin,
|
||||
Tooltip
|
||||
} from 'antd'
|
||||
import { PlusOutlined, EditOutlined, UnorderedListOutlined, InfoCircleOutlined } from '@ant-design/icons'
|
||||
import { PlusOutlined, EditOutlined, UnorderedListOutlined, InfoCircleOutlined, WarningOutlined } from '@ant-design/icons'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useMediaQuery } from 'react-responsive'
|
||||
import { apiService } from '../services/api'
|
||||
@@ -47,12 +47,41 @@ const CryptoTailStrategyList: React.FC = () => {
|
||||
const [triggersLoading, setTriggersLoading] = useState(false)
|
||||
const [form] = Form.useForm()
|
||||
|
||||
/** 币安 API 健康状态:仅保留「不可用」的项,用于强提醒 */
|
||||
const [binanceUnhealthy, setBinanceUnhealthy] = useState<Array<{ name: string; message: string }>>([])
|
||||
const [binanceCheckLoading, setBinanceCheckLoading] = useState(false)
|
||||
|
||||
const BINANCE_API_NAMES = ['币安 API', '币安 WebSocket']
|
||||
|
||||
const fetchBinanceApiStatus = async () => {
|
||||
setBinanceCheckLoading(true)
|
||||
try {
|
||||
const res = await apiService.proxyConfig.checkApiHealth()
|
||||
if (res.data.code === 0 && res.data.data?.apis) {
|
||||
const unhealthy = res.data.data.apis.filter(
|
||||
(api) => BINANCE_API_NAMES.includes(api.name) && api.status !== 'success'
|
||||
)
|
||||
setBinanceUnhealthy(unhealthy.map((api) => ({ name: api.name, message: api.message })))
|
||||
} else {
|
||||
setBinanceUnhealthy([])
|
||||
}
|
||||
} catch {
|
||||
setBinanceUnhealthy([{ name: '币安 API', message: '' }, { name: '币安 WebSocket', message: '' }])
|
||||
} finally {
|
||||
setBinanceCheckLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
fetchAccounts()
|
||||
fetchSystemConfig()
|
||||
fetchMarketOptions()
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
fetchBinanceApiStatus()
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
fetchList()
|
||||
}, [filters])
|
||||
@@ -411,6 +440,37 @@ const CryptoTailStrategyList: React.FC = () => {
|
||||
return (
|
||||
<div style={{ padding: isMobile ? 12 : 24 }}>
|
||||
<h1 style={{ marginBottom: 16, fontSize: isMobile ? 20 : 24 }}>{t('cryptoTailStrategy.list.title')}</h1>
|
||||
{binanceUnhealthy.length > 0 && (
|
||||
<Alert
|
||||
type="error"
|
||||
showIcon
|
||||
icon={<WarningOutlined />}
|
||||
message={t('cryptoTailStrategy.binanceApiAlert.title')}
|
||||
description={
|
||||
<div>
|
||||
<p style={{ marginBottom: 8 }}>{t('cryptoTailStrategy.binanceApiAlert.description')}</p>
|
||||
<ul style={{ marginBottom: 8, paddingLeft: 20 }}>
|
||||
{binanceUnhealthy.map((item, i) => (
|
||||
<li key={i}>
|
||||
<strong>{item.name}</strong>
|
||||
{item.message ? `: ${item.message}` : ''}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<Button
|
||||
type="primary"
|
||||
danger
|
||||
size="small"
|
||||
loading={binanceCheckLoading}
|
||||
onClick={fetchBinanceApiStatus}
|
||||
>
|
||||
{t('cryptoTailStrategy.binanceApiAlert.recheck')}
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
style={{ marginBottom: 16 }}
|
||||
/>
|
||||
)}
|
||||
<Alert
|
||||
type="warning"
|
||||
showIcon
|
||||
|
||||
Reference in New Issue
Block a user