diff --git a/trader/aster_trader.go b/trader/aster_trader.go
index d9ba82a6..15128e13 100644
--- a/trader/aster_trader.go
+++ b/trader/aster_trader.go
@@ -438,13 +438,23 @@ func (t *AsterTrader) GetBalance() (map[string]interface{}, error) {
return nil, err
}
+ // 🔍 调试:打印原始API响应
+ log.Printf("🔍 Aster API原始响应: %s", string(body))
+
// 查找USDT余额
totalBalance := 0.0
availableBalance := 0.0
crossUnPnl := 0.0
for _, bal := range balances {
+ // 🔍 调试:打印每条余额记录
+ log.Printf("🔍 余额记录: %+v", bal)
+
if asset, ok := bal["asset"].(string); ok && asset == "USDT" {
+ // 🔍 调试:打印USDT余额详情
+ log.Printf("🔍 USDT余额详情: balance=%v, availableBalance=%v, crossUnPnl=%v",
+ bal["balance"], bal["availableBalance"], bal["crossUnPnl"])
+
if wb, ok := bal["balance"].(string); ok {
totalBalance, _ = strconv.ParseFloat(wb, 64)
}
@@ -458,11 +468,25 @@ func (t *AsterTrader) GetBalance() (map[string]interface{}, error) {
}
}
+ // ✅ Aster API完全兼容Binance API格式
+ // balance字段 = wallet balance(不包含未实现盈亏)
+ // crossUnPnl = unrealized profit(未实现盈亏)
+ // crossWalletBalance = balance + crossUnPnl(全仓钱包余额,包含盈亏)
+ //
+ // 参考Binance官方文档:
+ // - Account Information V2: marginBalance = walletBalance + unrealizedProfit
+ // - Balance V3: crossWalletBalance = balance + crossUnPnl
+
+ log.Printf("✓ Aster API返回: 钱包余额=%.2f, 未实现盈亏=%.2f, 可用余额=%.2f",
+ totalBalance,
+ crossUnPnl,
+ availableBalance)
+
// 返回与Binance相同的字段名,确保AutoTrader能正确解析
return map[string]interface{}{
- "totalWalletBalance": totalBalance,
+ "totalWalletBalance": totalBalance, // 钱包余额(不含未实现盈亏)
"availableBalance": availableBalance,
- "totalUnrealizedProfit": crossUnPnl,
+ "totalUnrealizedProfit": crossUnPnl, // 未实现盈亏
}, nil
}
diff --git a/web/src/components/AITradersPage.tsx b/web/src/components/AITradersPage.tsx
index e1c73699..a19e7097 100644
--- a/web/src/components/AITradersPage.tsx
+++ b/web/src/components/AITradersPage.tsx
@@ -23,6 +23,7 @@ import {
Users,
AlertTriangle,
BookOpen,
+ HelpCircle,
} from 'lucide-react'
// 获取友好的AI模型名称
@@ -1064,6 +1065,51 @@ export function AITradersPage({ onTraderSelect }: AITradersPageProps) {
)
}
+// Tooltip Helper Component
+function Tooltip({
+ content,
+ children,
+}: {
+ content: string
+ children: React.ReactNode
+}) {
+ const [show, setShow] = useState(false)
+
+ return (
+
+
setShow(true)}
+ onMouseLeave={() => setShow(false)}
+ onClick={() => setShow(!show)}
+ >
+ {children}
+
+ {show && (
+
+ )}
+
+ )
+}
+
// Signal Source Configuration Modal Component
function SignalSourceModal({
coinPoolUrl,
@@ -1772,10 +1818,16 @@ function ExchangeConfigModal({
<>
+ {selectedExchange.id === 'aster' && (
+
{t('asterUsdtWarning', language)}
+ )}
{t('exchangeConfigWarning1', language)}
{t('exchangeConfigWarning2', language)}
{t('exchangeConfigWarning3', language)}
diff --git a/web/src/components/TraderConfigModal.tsx b/web/src/components/TraderConfigModal.tsx
index f96c9070..e0c7c0bf 100644
--- a/web/src/components/TraderConfigModal.tsx
+++ b/web/src/components/TraderConfigModal.tsx
@@ -68,6 +68,8 @@ export function TraderConfigModal({
const [selectedCoins, setSelectedCoins] = useState
([])
const [showCoinSelector, setShowCoinSelector] = useState(false)
const [promptTemplates, setPromptTemplates] = useState<{ name: string }[]>([])
+ const [isFetchingBalance, setIsFetchingBalance] = useState(false)
+ const [balanceFetchError, setBalanceFetchError] = useState('')
useEffect(() => {
if (traderData) {
@@ -182,6 +184,45 @@ export function TraderConfigModal({
})
}
+ const handleFetchCurrentBalance = async () => {
+ if (!isEditMode || !traderData?.trader_id) {
+ setBalanceFetchError('只有在编辑模式下才能获取当前余额');
+ return;
+ }
+
+ setIsFetchingBalance(true);
+ setBalanceFetchError('');
+
+ try {
+ 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('获取账户余额失败');
+ }
+
+ const data = await response.json();
+
+ // total_equity = 当前账户净值(包含未实现盈亏)
+ // 这应该作为新的初始余额
+ const currentBalance = data.total_equity || data.balance || 0;
+
+ setFormData(prev => ({ ...prev, initial_balance: currentBalance }));
+
+ // 显示成功提示
+ console.log('已获取当前余额:', currentBalance);
+ } catch (error) {
+ console.error('获取余额失败:', error);
+ setBalanceFetchError('获取余额失败,请检查网络连接');
+ } finally {
+ setIsFetchingBalance(false);
+ }
+ };
+
const handleSave = async () => {
if (!onSave) return
@@ -346,9 +387,22 @@ export function TraderConfigModal({
-
+
+
+ {isEditMode && (
+
+ )}
+
+ {!isEditMode && (
+
+
+ 请输入您交易所账户的当前实际余额。如果输入不准确,P&L统计将会错误。
+
+ )}
+ {isEditMode && (
+
+ 点击"获取当前余额"按钮可自动获取您交易所账户的当前净值
+
+ )}
+ {balanceFetchError && (
+
{balanceFetchError}
+ )}
diff --git a/web/src/i18n/translations.ts b/web/src/i18n/translations.ts
index ae5c8cca..a48b96b1 100644
--- a/web/src/i18n/translations.ts
+++ b/web/src/i18n/translations.ts
@@ -197,6 +197,14 @@ export const translations = {
'Hyperliquid uses private key for trading authentication',
hyperliquidWalletAddressDesc:
'Wallet address corresponding to the private key',
+ asterUserDesc:
+ 'Main wallet address - The EVM wallet address you use to log in to Aster',
+ asterSignerDesc:
+ 'API wallet address - Generate from https://www.asterdex.com/en/api-wallet',
+ asterPrivateKeyDesc:
+ 'API wallet private key - Get from https://www.asterdex.com/en/api-wallet (only used locally for signing, never transmitted)',
+ asterUsdtWarning:
+ 'Important: Aster only tracks USDT balance. Please ensure you use USDT as margin currency to avoid P&L calculation errors caused by price fluctuations of other assets (BNB, ETH, etc.)',
testnetDescription:
'Enable to connect to exchange test environment for simulated trading',
securityWarning: 'Security Warning',
@@ -658,7 +666,15 @@ export const translations = {
enterPassphrase: '输入Passphrase (OKX必填)',
hyperliquidPrivateKeyDesc: 'Hyperliquid 使用私钥进行交易认证',
hyperliquidWalletAddressDesc: '与私钥对应的钱包地址',
- testnetDescription: '启用后将连接到交易所测试环境,用于模拟交易',
+ asterUserDesc:
+ '主钱包地址 - 您用于登录 Aster 的 EVM 钱包地址',
+ asterSignerDesc:
+ 'API 钱包地址 - 从 https://www.asterdex.com/zh-CN/api-wallet 生成',
+ asterPrivateKeyDesc:
+ 'API 钱包私钥 - 从 https://www.asterdex.com/zh-CN/api-wallet 获取(仅在本地用于签名,不会被传输)',
+ asterUsdtWarning:
+ '重要提示:Aster 仅统计 USDT 余额。请确保您使用 USDT 作为保证金币种,避免其他资产(BNB、ETH等)的价格波动导致盈亏统计错误',
+ testnetDescription: '启用后将连接到交易所测试环境,用于模拟交易',
securityWarning: '安全提示',
saveConfiguration: '保存配置',