From 81e3d3cdb4f5a970950444a46702d980a38a42f0 Mon Sep 17 00:00:00 2001 From: CoderMageFox Date: Wed, 5 Nov 2025 12:37:04 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8DInitialBalance?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E9=94=99=E8=AF=AF=E5=AF=BC=E8=87=B4=E7=9A=84?= =?UTF-8?q?P&L=E7=BB=9F=E8=AE=A1=E4=B8=8D=E5=87=86=E7=A1=AE=E9=97=AE?= =?UTF-8?q?=E9=A2=98=20=E7=94=A8=E6=88=B7=E5=9C=A8=E4=BD=BF=E7=94=A8Aster?= =?UTF-8?q?=E4=BA=A4=E6=98=93=E5=91=98=E6=97=B6=E5=8F=91=E7=8E=B0=EF=BC=8C?= =?UTF-8?q?=E5=8D=B3=E4=BD=BF=E6=B2=A1=E6=9C=89=E5=BC=80=E5=A7=8B=E4=BA=A4?= =?UTF-8?q?=E6=98=93=EF=BC=8CP&L=E7=BB=9F=E8=AE=A1=E4=B9=9F=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E4=BA=8612.5=20USDT=20(83.33%)=E7=9A=84=E7=9B=88?= =?UTF-8?q?=E4=BA=8F=E3=80=82=E7=BB=8F=E8=BF=87=E8=B0=83=E6=9F=A5=E5=8F=91?= =?UTF-8?q?=E7=8E=B0=EF=BC=9A=20**=E6=A0=B9=E6=9C=AC=E5=8E=9F=E5=9B=A0**?= =?UTF-8?q?=EF=BC=9A=20-=20=E5=AE=9E=E9=99=85Aster=E8=B4=A6=E6=88=B7?= =?UTF-8?q?=E4=BD=99=E9=A2=9D=EF=BC=9A27.5=20USDT=20-=20Web=E7=95=8C?= =?UTF-8?q?=E9=9D=A2=E9=85=8D=E7=BD=AE=E7=9A=84InitialBalance=EF=BC=9A15?= =?UTF-8?q?=20USDT=20=E2=9D=8C=20-=20=E9=94=99=E8=AF=AF=E7=9A=84P&L?= =?UTF-8?q?=E8=AE=A1=E7=AE=97=EF=BC=9A27.5=20-=2015=20=3D=2012.5=20USDT=20?= =?UTF-8?q?(83.33%)=20**=E9=97=AE=E9=A2=98=E6=A0=B9=E6=BA=90**=EF=BC=9A=20?= =?UTF-8?q?1.=20Web=E7=95=8C=E9=9D=A2=E5=88=9B=E5=BB=BA=E4=BA=A4=E6=98=93?= =?UTF-8?q?=E5=91=98=E6=97=B6=E9=BB=98=E8=AE=A4initial=5Fbalance=E4=B8=BA1?= =?UTF-8?q?000=20USDT=202.=20=E7=94=A8=E6=88=B7=E6=89=8B=E5=8A=A8=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E6=97=B6=E5=AE=B9=E6=98=93=E8=BE=93=E5=85=A5=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E7=9A=84=E5=80=BC=203.=20=E7=BC=BA=E5=B0=91=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E8=8E=B7=E5=8F=96=E5=AE=9E=E9=99=85=E4=BD=99=E9=A2=9D?= =?UTF-8?q?=E7=9A=84=E5=8A=9F=E8=83=BD=204.=20=E7=BC=BA=E5=B0=91=E6=98=8E?= =?UTF-8?q?=E7=A1=AE=E7=9A=84=E8=AD=A6=E5=91=8A=E6=8F=90=E7=A4=BA=20**?= =?UTF-8?q?=E6=96=87=E4=BB=B6**:=20`trader/aster=5Ftrader.go`=20-=20?= =?UTF-8?q?=E2=9C=85=20=E9=AA=8C=E8=AF=81Aster=20API=E5=AE=8C=E5=85=A8?= =?UTF-8?q?=E5=85=BC=E5=AE=B9Binance=E6=A0=BC=E5=BC=8F=20-=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E8=AF=A6=E7=BB=86=E7=9A=84=E6=B3=A8=E9=87=8A=E8=AF=B4?= =?UTF-8?q?=E6=98=8E=E5=AD=97=E6=AE=B5=E5=90=AB=E4=B9=89=20-=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E8=B0=83=E8=AF=95=E6=97=A5=E5=BF=97=E4=BB=A5=E4=BE=BF?= =?UTF-8?q?=E6=8E=92=E6=9F=A5=E9=97=AE=E9=A2=98=20-=20=E7=A1=AE=E8=AE=A4ba?= =?UTF-8?q?lance=E5=AD=97=E6=AE=B5=E4=B8=8D=E5=8C=85=E5=90=AB=E6=9C=AA?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E7=9B=88=E4=BA=8F=EF=BC=88=E4=B8=8EBinance?= =?UTF-8?q?=E4=B8=80=E8=87=B4=EF=BC=89=20**=E5=85=B3=E9=94=AE=E7=A1=AE?= =?UTF-8?q?=E8=AE=A4**=EF=BC=9A=20```go=20//=20=E2=9C=85=20Aster=20API?= =?UTF-8?q?=E5=AE=8C=E5=85=A8=E5=85=BC=E5=AE=B9Binance=20API=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=20//=20balance=E5=AD=97=E6=AE=B5=20=3D=20wallet=20bal?= =?UTF-8?q?ance=EF=BC=88=E4=B8=8D=E5=8C=85=E5=90=AB=E6=9C=AA=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=E7=9B=88=E4=BA=8F=EF=BC=89=20//=20crossUnPnl=20=3D=20?= =?UTF-8?q?unrealized=20profit=EF=BC=88=E6=9C=AA=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E7=9B=88=E4=BA=8F=EF=BC=89=20//=20crossWalletBalance=20=3D=20b?= =?UTF-8?q?alance=20+=20crossUnPnl=EF=BC=88=E5=85=A8=E4=BB=93=E9=92=B1?= =?UTF-8?q?=E5=8C=85=E4=BD=99=E9=A2=9D=EF=BC=8C=E5=8C=85=E5=90=AB=E7=9B=88?= =?UTF-8?q?=E4=BA=8F=EF=BC=89=20```=20**=E6=96=87=E4=BB=B6**:=20`web/src/c?= =?UTF-8?q?omponents/TraderConfigModal.tsx`=20**=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=8A=9F=E8=83=BD**=EF=BC=9A=201.=20**=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F**=EF=BC=9A=E6=B7=BB=E5=8A=A0"=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E5=BD=93=E5=89=8D=E4=BD=99=E9=A2=9D"=E6=8C=89?= =?UTF-8?q?=E9=92=AE=20=20=20=20-=20=E4=B8=80=E9=94=AE=E4=BB=8E=E4=BA=A4?= =?UTF-8?q?=E6=98=93=E6=89=80API=E8=8E=B7=E5=8F=96=E5=BD=93=E5=89=8D?= =?UTF-8?q?=E8=B4=A6=E6=88=B7=E5=87=80=E5=80=BC=20=20=20=20-=20=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E5=A1=AB=E5=85=85=E5=88=B0InitialBalance=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=20=20=20=20-=20=E6=98=BE=E7=A4=BA=E5=8A=A0=E8=BD=BD?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E5=92=8C=E9=94=99=E8=AF=AF=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=202.=20**=E5=88=9B=E5=BB=BA=E6=A8=A1=E5=BC=8F**=EF=BC=9A?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=AD=A6=E5=91=8A=E6=8F=90=E7=A4=BA=20=20=20?= =?UTF-8?q?=20-=20=E2=9A=A0=EF=B8=8F=20=E6=8F=90=E9=86=92=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E5=BF=85=E9=A1=BB=E8=BE=93=E5=85=A5=E4=BA=A4=E6=98=93?= =?UTF-8?q?=E6=89=80=E7=9A=84=E5=BD=93=E5=89=8D=E5=AE=9E=E9=99=85=E4=BD=99?= =?UTF-8?q?=E9=A2=9D=20=20=20=20-=20=E8=AD=A6=E5=91=8A=EF=BC=9A=E5=A6=82?= =?UTF-8?q?=E6=9E=9C=E8=BE=93=E5=85=A5=E4=B8=8D=E5=87=86=E7=A1=AE=EF=BC=8C?= =?UTF-8?q?P&L=E7=BB=9F=E8=AE=A1=E5=B0=86=E4=BC=9A=E9=94=99=E8=AF=AF=203.?= =?UTF-8?q?=20**=E6=94=B9=E8=BF=9B=E8=BE=93=E5=85=A5=E4=BD=93=E9=AA=8C**?= =?UTF-8?q?=EF=BC=9A=20=20=20=20-=20=E6=94=AF=E6=8C=81=E5=B0=8F=E6=95=B0?= =?UTF-8?q?=E8=BE=93=E5=85=A5=EF=BC=88step=3D"0.01"=EF=BC=89=20=20=20=20-?= =?UTF-8?q?=20=E5=BF=85=E5=A1=AB=E5=AD=97=E6=AE=B5=E6=A0=87=E8=AE=B0?= =?UTF-8?q?=EF=BC=88=E5=88=9B=E5=BB=BA=E6=A8=A1=E5=BC=8F=EF=BC=89=20=20=20?= =?UTF-8?q?=20-=20=E5=AE=9E=E6=97=B6=E9=94=99=E8=AF=AF=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=20**=E4=BB=A3=E7=A0=81=E5=AE=9E=E7=8E=B0**=EF=BC=9A=20```types?= =?UTF-8?q?cript=20const=20handleFetchCurrentBalance=20=3D=20async=20()=20?= =?UTF-8?q?=3D>=20{=20=20=20const=20response=20=3D=20await=20fetch(`/api/a?= =?UTF-8?q?ccount=3Ftrader=5Fid=3D${traderData.trader=5Fid}`);=20=20=20con?= =?UTF-8?q?st=20data=20=3D=20await=20response.json();=20=20=20const=20curr?= =?UTF-8?q?entBalance=20=3D=20data.total=5Fequity;=20//=20=E5=BD=93?= =?UTF-8?q?=E5=89=8D=E5=87=80=E5=80=BC=20=20=20setFormData(prev=20=3D>=20(?= =?UTF-8?q?{=20...prev,=20initial=5Fbalance:=20currentBalance=20}));=20};?= =?UTF-8?q?=20```=20=E9=80=9A=E8=BF=87=E6=9F=A5=E9=98=85Binance=E5=AE=98?= =?UTF-8?q?=E6=96=B9=E6=96=87=E6=A1=A3=E7=A1=AE=E8=AE=A4=EF=BC=9A=20|=20?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=20|=20Binance=20|=20Aster=20(=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E5=90=8E)=20|=20|------|---------|----------------|?= =?UTF-8?q?=20|=20**=E4=BD=99=E9=A2=9D=E5=AD=97=E6=AE=B5**=20|=20balance?= =?UTF-8?q?=20=3D=20=E9=92=B1=E5=8C=85=E4=BD=99=E9=A2=9D=EF=BC=88=E4=B8=8D?= =?UTF-8?q?=E5=90=AB=E7=9B=88=E4=BA=8F=EF=BC=89=20|=20=E2=9C=85=20?= =?UTF-8?q?=E7=9B=B8=E5=90=8C=20|=20|=20**=E7=9B=88=E4=BA=8F=E5=AD=97?= =?UTF-8?q?=E6=AE=B5**=20|=20crossUnPnl=20=3D=20=E6=9C=AA=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=E7=9B=88=E4=BA=8F=20|=20=E2=9C=85=20=E7=9B=B8?= =?UTF-8?q?=E5=90=8C=20|=20|=20**=E6=80=BB=E6=9D=83=E7=9B=8A**=20|=20balan?= =?UTF-8?q?ce=20+=20crossUnPnl=20|=20=E2=9C=85=20=E7=9B=B8=E5=90=8C=20|=20?= =?UTF-8?q?|=20**P&L=E8=AE=A1=E7=AE=97**=20|=20totalEquity=20-=20initialBa?= =?UTF-8?q?lance=20|=20=E2=9C=85=20=E7=9B=B8=E5=90=8C=20|=201.=20=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E4=BA=A4=E6=98=93=E5=91=98=E9=85=8D=E7=BD=AE=202.=20?= =?UTF-8?q?=E7=82=B9=E5=87=BB"=E8=8E=B7=E5=8F=96=E5=BD=93=E5=89=8D?= =?UTF-8?q?=E4=BD=99=E9=A2=9D"=E6=8C=89=E9=92=AE=203.=20=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=A1=AB=E5=85=85=E6=AD=A3=E7=A1=AE=E7=9A=84?= =?UTF-8?q?InitialBalance=204.=20=E4=BF=9D=E5=AD=98=E9=85=8D=E7=BD=AE=201.?= =?UTF-8?q?=20=E6=9F=A5=E7=9C=8B=E4=BA=A4=E6=98=93=E6=89=80=E8=B4=A6?= =?UTF-8?q?=E6=88=B7=E7=9A=84=E5=AE=9E=E9=99=85=E4=BD=99=E9=A2=9D=202.=20?= =?UTF-8?q?=E5=87=86=E7=A1=AE=E8=BE=93=E5=85=A5=E5=88=B0InitialBalance?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=203.=20=E6=B3=A8=E6=84=8F=E6=9F=A5=E7=9C=8B?= =?UTF-8?q?=E8=AD=A6=E5=91=8A=E6=8F=90=E7=A4=BA=204.=20=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E5=88=9B=E5=BB=BA=20-=20[x]=20=E7=A1=AE=E8=AE=A4Aster=20API?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E6=A0=BC=E5=BC=8F=E4=B8=8EBinance=E4=B8=80?= =?UTF-8?q?=E8=87=B4=20-=20[x]=20=E9=AA=8C=E8=AF=81"=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E5=BD=93=E5=89=8D=E4=BD=99=E9=A2=9D"=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E6=AD=A3=E5=B8=B8=E5=B7=A5=E4=BD=9C=20-=20[x]=20=E7=A1=AE?= =?UTF-8?q?=E8=AE=A4P&L=E8=AE=A1=E7=AE=97=E5=85=AC=E5=BC=8F=E6=AD=A3?= =?UTF-8?q?=E7=A1=AE=20-=20[x]=20=E5=89=8D=E7=AB=AF=E6=9E=84=E5=BB=BA?= =?UTF-8?q?=E6=88=90=E5=8A=9F=20-=20[x]=20=E8=AD=A6=E5=91=8A=E6=8F=90?= =?UTF-8?q?=E7=A4=BA=E6=AD=A3=E5=B8=B8=E6=98=BE=E7=A4=BA=20-=20**=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D**:=20=E8=A7=A3=E5=86=B3InitialBalance=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E9=94=99=E8=AF=AF=E5=AF=BC=E8=87=B4=E7=9A=84P&L?= =?UTF-8?q?=E7=BB=9F=E8=AE=A1=E4=B8=8D=E5=87=86=E7=A1=AE=E9=97=AE=E9=A2=98?= =?UTF-8?q?=20-=20**=E6=94=B9=E8=BF=9B**:=20=E6=8F=90=E5=8D=87=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E4=BD=93=E9=AA=8C=EF=BC=8C=E5=87=8F=E5=B0=91=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E9=94=99=E8=AF=AF=20-=20**=E5=85=BC=E5=AE=B9**:=20?= =?UTF-8?q?=E5=AE=8C=E5=85=A8=E5=90=91=E5=90=8E=E5=85=BC=E5=AE=B9=EF=BC=8C?= =?UTF-8?q?=E4=B8=8D=E5=BD=B1=E5=93=8D=E7=8E=B0=E6=9C=89=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=20Co-Authored-By:=20tinkle-community=20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- trader/aster_trader.go | 28 ++++++++- web/src/components/TraderConfigModal.tsx | 76 ++++++++++++++++++++++-- 2 files changed, 98 insertions(+), 6 deletions(-) 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/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}

+ )}