Merge remote-tracking branch 'origin/main' into feat/real-pnl-statistics

This commit is contained in:
codyhhchen
2026-04-30 23:32:53 +08:00
53 changed files with 1891 additions and 431 deletions
@@ -518,7 +518,7 @@ const AddModal: React.FC<AddModalProps> = ({
value={parseFloat(leaderAssetInfo.total)}
precision={4}
valueStyle={{ color: '#52c41a', fontWeight: 'bold', fontSize: '16px' }}
suffix="USDC"
prefix="$"
formatter={(value) => formatUSDC(value?.toString() || '0')}
/>
</Col>
@@ -528,7 +528,7 @@ const AddModal: React.FC<AddModalProps> = ({
value={parseFloat(leaderAssetInfo.available)}
precision={4}
valueStyle={{ color: '#1890ff', fontSize: '14px' }}
suffix="USDC"
prefix="$"
formatter={(value) => formatUSDC(value?.toString() || '0')}
/>
</Col>
@@ -538,7 +538,7 @@ const AddModal: React.FC<AddModalProps> = ({
value={parseFloat(leaderAssetInfo.position)}
precision={4}
valueStyle={{ color: '#722ed1', fontSize: '14px' }}
suffix="USDC"
prefix="$"
formatter={(value) => formatUSDC(value?.toString() || '0')}
/>
</Col>
@@ -606,7 +606,7 @@ const AddModal: React.FC<AddModalProps> = ({
{copyMode === 'FIXED' && (
<Form.Item
label={t('copyTradingAdd.fixedAmount') || '固定跟单金额 (USDC)'}
label={t('copyTradingAdd.fixedAmount') || '固定跟单金额 ($)'}
name="fixedAmount"
rules={[
{ required: true, message: t('copyTradingAdd.fixedAmountRequired') || '请输入固定跟单金额' },
@@ -645,7 +645,7 @@ const AddModal: React.FC<AddModalProps> = ({
{copyMode === 'RATIO' && (
<>
<Form.Item
label={t('copyTradingAdd.maxOrderSize') || '单笔订单最大金额 (USDC)'}
label={t('copyTradingAdd.maxOrderSize') || '单笔订单最大金额 ($)'}
name="maxOrderSize"
tooltip={t('copyTradingAdd.maxOrderSizeTooltip') || '比例模式下,限制单笔跟单订单的最大金额上限'}
>
@@ -665,7 +665,7 @@ const AddModal: React.FC<AddModalProps> = ({
</Form.Item>
<Form.Item
label={t('copyTradingAdd.minOrderSize') || '单笔订单最小金额 (USDC)'}
label={t('copyTradingAdd.minOrderSize') || '单笔订单最小金额 ($)'}
name="minOrderSize"
tooltip={t('copyTradingAdd.minOrderSizeTooltip') || '比例模式下,限制单笔跟单订单的最小金额下限,必须 >= 1'}
rules={[
@@ -700,7 +700,7 @@ const AddModal: React.FC<AddModalProps> = ({
)}
<Form.Item
label={t('copyTradingAdd.maxDailyLoss') || '每日最大亏损限制 (USDC)'}
label={t('copyTradingAdd.maxDailyLoss') || '每日最大亏损限制 ($)'}
name="maxDailyLoss"
tooltip={t('copyTradingAdd.maxDailyLossTooltip') || '限制每日最大亏损金额,用于风险控制'}
>
@@ -709,7 +709,7 @@ const AddModal: React.FC<AddModalProps> = ({
step={0.0001}
precision={4}
style={{ width: '100%' }}
placeholder={t('copyTradingAdd.maxDailyLossPlaceholder') || '默认 10000 USDC(可选)'}
placeholder={t('copyTradingAdd.maxDailyLossPlaceholder') || '默认 10000 $(可选)'}
formatter={(value) => {
if (!value && value !== 0) return ''
const num = parseFloat(value.toString())
@@ -767,7 +767,7 @@ const AddModal: React.FC<AddModalProps> = ({
</Form.Item>
<Form.Item
label={t('copyTradingAdd.minOrderDepth') || '最小订单深度 (USDC)'}
label={t('copyTradingAdd.minOrderDepth') || '最小订单深度 ($)'}
name="minOrderDepth"
tooltip={t('copyTradingAdd.minOrderDepthTooltip') || '检查订单簿的总订单金额(买盘+卖盘),确保市场有足够的流动性。不填写则不启用此过滤'}
>
@@ -853,7 +853,7 @@ const AddModal: React.FC<AddModalProps> = ({
<Divider>{t('copyTradingAdd.positionLimitFilter') || '最大仓位限制'}</Divider>
<Form.Item
label={t('copyTradingAdd.maxPositionValue') || '最大仓位金额 (USDC)'}
label={t('copyTradingAdd.maxPositionValue') || '最大仓位金额 ($)'}
name="maxPositionValue"
tooltip={t('copyTradingAdd.maxPositionValueTooltip') || '限制单个市场的最大仓位金额。如果该市场的当前仓位金额 + 跟单金额超过此限制,则不会下单。不填写则不启用此限制'}
>
@@ -1082,7 +1082,7 @@ const AddModal: React.FC<AddModalProps> = ({
<span>
{record.copyMode === 'RATIO'
? `${t('copyTradingAdd.ratioMode') || '比例'} ${record.copyRatio}x`
: `${t('copyTradingAdd.fixedAmountMode') || '固定'} ${formatUSDC(record.fixedAmount || '0')} USDC`
: `${t('copyTradingAdd.fixedAmountMode') || '固定'} $${formatUSDC(record.fixedAmount || '0')}`
}
</span>
)
@@ -261,7 +261,7 @@ const BuyOrdersTab: React.FC<BuyOrdersTabProps> = ({ copyTradingId, active = fal
const amount = (parseFloat(record.quantity) * parseFloat(record.price)).toString()
return (
<span style={{ fontSize: isMobile ? 12 : 14 }}>
{isMobile ? formatUSDC(amount) : `${formatUSDC(amount)} USDC`}
{isMobile ? formatUSDC(amount) : `$${formatUSDC(amount)}`}
</span>
)
}
@@ -384,7 +384,7 @@ const BuyOrdersTab: React.FC<BuyOrdersTabProps> = ({ copyTradingId, active = fal
</div>
<div style={{ display: 'flex', gap: '16px', flexWrap: 'wrap', fontSize: isMobile ? '12px' : '13px', color: '#666' }}>
<span>{t('copyTradingOrders.orderCount') || '订单数'}: {group.stats.count}</span>
<span>{t('copyTradingOrders.totalAmount') || '总金额'}: {formatUSDC(group.stats.totalAmount)} USDC</span>
<span>{t('copyTradingOrders.totalAmount') || '总金额'}: ${formatUSDC(group.stats.totalAmount)}</span>
<span>
{t('copyTradingOrders.statusBreakdown') || '状态'}:
{group.stats.fullyMatchedCount > 0 && ` ${t('copyTradingOrders.allFullySold') || '全部卖出'} ${group.stats.fullyMatchedCount}`}
@@ -460,7 +460,7 @@ const BuyOrdersTab: React.FC<BuyOrdersTabProps> = ({ copyTradingId, active = fal
<div style={{ fontSize: '12px', color: '#666' }}>
<div>{t('copyTradingOrders.quantity') || '数量'}: {formatUSDC(order.quantity)} | {t('copyTradingOrders.price') || '价格'}: {formatUSDC(order.price)}</div>
<div>{t('copyTradingOrders.amount') || '金额'}: {formatUSDC(amount)} USDC</div>
<div>{t('copyTradingOrders.amount') || '金额'}: ${formatUSDC(amount)}</div>
<div>{t('copyTradingOrders.matched') || '已匹配'}: {formatUSDC(order.matchedQuantity)} | {t('copyTradingOrders.remaining') || '剩余'}: {formatUSDC(order.remainingQuantity)}</div>
<div style={{ color: '#999', marginTop: '4px' }}>{formattedDate}</div>
</div>
@@ -557,7 +557,7 @@ const BuyOrdersTab: React.FC<BuyOrdersTabProps> = ({ copyTradingId, active = fal
{t('copyTradingOrders.quantity') || '数量'}: {formatUSDC(order.quantity)} | {t('copyTradingOrders.price') || '价格'}: {formatUSDC(order.price)}
</div>
<div style={{ fontSize: '14px', fontWeight: '500', marginTop: '4px' }}>
{t('copyTradingOrders.amount') || '金额'}: {formatUSDC(amount)} USDC
{t('copyTradingOrders.amount') || '金额'}: ${formatUSDC(amount)}
</div>
</div>
@@ -356,7 +356,7 @@ const EditModal: React.FC<EditModalProps> = ({
value={parseFloat(leaderAssetInfo.total)}
precision={4}
valueStyle={{ color: '#52c41a', fontWeight: 'bold', fontSize: '16px' }}
suffix="USDC"
prefix="$"
formatter={(value) => formatUSDC(value?.toString() || '0')}
/>
</Col>
@@ -366,7 +366,7 @@ const EditModal: React.FC<EditModalProps> = ({
value={parseFloat(leaderAssetInfo.available)}
precision={4}
valueStyle={{ color: '#1890ff', fontSize: '14px' }}
suffix="USDC"
prefix="$"
formatter={(value) => formatUSDC(value?.toString() || '0')}
/>
</Col>
@@ -376,7 +376,7 @@ const EditModal: React.FC<EditModalProps> = ({
value={parseFloat(leaderAssetInfo.position)}
precision={4}
valueStyle={{ color: '#722ed1', fontSize: '14px' }}
suffix="USDC"
prefix="$"
formatter={(value) => formatUSDC(value?.toString() || '0')}
/>
</Col>
@@ -456,7 +456,7 @@ const EditModal: React.FC<EditModalProps> = ({
{copyMode === 'FIXED' && (
<Form.Item
label={t('copyTradingEdit.fixedAmount') || '固定跟单金额 (USDC)'}
label={t('copyTradingEdit.fixedAmount') || '固定跟单金额 ($)'}
name="fixedAmount"
rules={[
{ required: true, message: t('copyTradingEdit.fixedAmountRequired') || '请输入固定跟单金额' },
@@ -495,7 +495,7 @@ const EditModal: React.FC<EditModalProps> = ({
{copyMode === 'RATIO' && (
<>
<Form.Item
label={t('copyTradingEdit.maxOrderSize') || '单笔订单最大金额 (USDC)'}
label={t('copyTradingEdit.maxOrderSize') || '单笔订单最大金额 ($)'}
name="maxOrderSize"
tooltip={t('copyTradingEdit.maxOrderSizeTooltip') || '比例模式下,限制单笔跟单订单的最大金额上限'}
>
@@ -515,7 +515,7 @@ const EditModal: React.FC<EditModalProps> = ({
</Form.Item>
<Form.Item
label={t('copyTradingEdit.minOrderSize') || '单笔订单最小金额 (USDC)'}
label={t('copyTradingEdit.minOrderSize') || '单笔订单最小金额 ($)'}
name="minOrderSize"
tooltip={t('copyTradingEdit.minOrderSizeTooltip') || '比例模式下,限制单笔跟单订单的最小金额下限,必须 >= 1'}
rules={[
@@ -550,7 +550,7 @@ const EditModal: React.FC<EditModalProps> = ({
)}
<Form.Item
label={t('copyTradingEdit.maxDailyLoss') || '每日最大亏损限制 (USDC)'}
label={t('copyTradingEdit.maxDailyLoss') || '每日最大亏损限制 ($)'}
name="maxDailyLoss"
tooltip={t('copyTradingEdit.maxDailyLossTooltip') || '限制每日最大亏损金额,用于风险控制'}
>
@@ -559,7 +559,7 @@ const EditModal: React.FC<EditModalProps> = ({
step={0.0001}
precision={4}
style={{ width: '100%' }}
placeholder={t('copyTradingEdit.maxDailyLossPlaceholder') || '默认 10000 USDC(可选)'}
placeholder={t('copyTradingEdit.maxDailyLossPlaceholder') || '默认 10000 $(可选)'}
formatter={(value) => {
if (!value && value !== 0) return ''
const num = parseFloat(value.toString())
@@ -617,7 +617,7 @@ const EditModal: React.FC<EditModalProps> = ({
</Form.Item>
<Form.Item
label={t('copyTradingEdit.minOrderDepth') || '最小订单深度 (USDC)'}
label={t('copyTradingEdit.minOrderDepth') || '最小订单深度 ($)'}
name="minOrderDepth"
tooltip={t('copyTradingEdit.minOrderDepthTooltip') || '检查订单簿的总订单金额(买盘+卖盘),确保市场有足够的流动性。不填写则不启用此过滤'}
>
@@ -703,7 +703,7 @@ const EditModal: React.FC<EditModalProps> = ({
<Divider>{t('copyTradingEdit.positionLimitFilter') || '最大仓位限制'}</Divider>
<Form.Item
label={t('copyTradingEdit.maxPositionValue') || '最大仓位金额 (USDC)'}
label={t('copyTradingEdit.maxPositionValue') || '最大仓位金额 ($)'}
name="maxPositionValue"
tooltip={t('copyTradingEdit.maxPositionValueTooltip') || '限制单个市场的最大仓位金额。如果该市场的当前仓位金额 + 跟单金额超过此限制,则不会下单。不填写则不启用此限制'}
>
@@ -228,7 +228,7 @@ const MatchedOrdersTab: React.FC<MatchedOrdersTabProps> = ({ copyTradingId, acti
fontWeight: 500,
fontSize: isMobile ? 12 : 14
}}>
{isMobile ? formatUSDC(value) : `${formatUSDC(value)} USDC`}
{isMobile ? formatUSDC(value) : `$${formatUSDC(value)}`}
</span>
)
},
@@ -408,7 +408,7 @@ const MatchedOrdersTab: React.FC<MatchedOrdersTabProps> = ({ copyTradingId, acti
fontWeight: 'bold',
color: getPnlColor(order.realizedPnl)
}}>
{formatUSDC(order.realizedPnl)} USDC
${formatUSDC(order.realizedPnl)}
</div>
</div>
@@ -258,7 +258,7 @@ const SellOrdersTab: React.FC<SellOrdersTabProps> = ({ copyTradingId, active = f
const amount = (parseFloat(record.quantity) * parseFloat(record.price)).toString()
return (
<span style={{ fontSize: isMobile ? 12 : 14 }}>
{isMobile ? formatUSDC(amount) : `${formatUSDC(amount)} USDC`}
{isMobile ? formatUSDC(amount) : `$${formatUSDC(amount)}`}
</span>
)
}
@@ -274,7 +274,7 @@ const SellOrdersTab: React.FC<SellOrdersTabProps> = ({ copyTradingId, active = f
fontWeight: 500,
fontSize: isMobile ? 12 : 14
}}>
{isMobile ? formatUSDC(value) : `${formatUSDC(value)} USDC`}
{isMobile ? formatUSDC(value) : `$${formatUSDC(value)}`}
</span>
)
},
@@ -362,10 +362,10 @@ const SellOrdersTab: React.FC<SellOrdersTabProps> = ({ copyTradingId, active = f
</div>
<div style={{ display: 'flex', gap: '16px', flexWrap: 'wrap', fontSize: isMobile ? '12px' : '13px', color: '#666' }}>
<span>{t('copyTradingOrders.orderCount') || '订单数'}: {group.stats.count}</span>
<span>{t('copyTradingOrders.totalAmount') || '总金额'}: {formatUSDC(group.stats.totalAmount)} USDC</span>
<span>{t('copyTradingOrders.totalAmount') || '总金额'}: ${formatUSDC(group.stats.totalAmount)}</span>
{group.stats.totalPnl && (
<span style={{ color: pnlColor, fontWeight: 500 }}>
{t('copyTradingOrders.totalPnl') || '总盈亏'}: {formatUSDC(group.stats.totalPnl)} USDC
{t('copyTradingOrders.totalPnl') || '总盈亏'}: ${formatUSDC(group.stats.totalPnl)}
</span>
)}
</div>
@@ -434,9 +434,9 @@ const SellOrdersTab: React.FC<SellOrdersTabProps> = ({ copyTradingId, active = f
<div style={{ fontSize: '12px', color: '#666' }}>
<div>{t('copyTradingOrders.quantity') || '数量'}: {formatUSDC(order.quantity)} | {t('copyTradingOrders.price') || '价格'}: {formatUSDC(order.price)}</div>
<div>{t('copyTradingOrders.amount') || '金额'}: {formatUSDC(amount)} USDC</div>
<div>{t('copyTradingOrders.amount') || '金额'}: ${formatUSDC(amount)}</div>
<div style={{ color: getPnlColor(order.realizedPnl), fontWeight: 500 }}>
{t('copyTradingOrders.realizedPnl') || '已实现盈亏'}: {formatUSDC(order.realizedPnl)} USDC
{t('copyTradingOrders.realizedPnl') || '已实现盈亏'}: ${formatUSDC(order.realizedPnl)}
</div>
<div style={{ color: '#999', marginTop: '4px' }}>{formattedDate}</div>
</div>
@@ -530,7 +530,7 @@ const SellOrdersTab: React.FC<SellOrdersTabProps> = ({ copyTradingId, active = f
{t('copyTradingOrders.quantity') || '数量'}: {formatUSDC(order.quantity)} | {t('copyTradingOrders.price') || '价格'}: {formatUSDC(order.price)}
</div>
<div style={{ fontSize: '14px', fontWeight: '500', marginTop: '4px' }}>
{t('copyTradingOrders.amount') || '金额'}: {formatUSDC(amount)} USDC
{t('copyTradingOrders.amount') || '金额'}: ${formatUSDC(amount)}
</div>
</div>
@@ -541,7 +541,7 @@ const SellOrdersTab: React.FC<SellOrdersTabProps> = ({ copyTradingId, active = f
fontWeight: 'bold',
color: getPnlColor(order.realizedPnl)
}}>
{formatUSDC(order.realizedPnl)} USDC
${formatUSDC(order.realizedPnl)}
</div>
</div>
@@ -104,7 +104,7 @@ const StatisticsModal: React.FC<StatisticsModalProps> = ({
</div>
<div style={{ fontSize: '16px', fontWeight: '500', color: '#333', flex: '1', textAlign: 'right', display: 'flex', alignItems: 'center', justifyContent: 'flex-end', gap: '4px' }}>
<ArrowUpOutlined style={{ color: '#1890ff', fontSize: '14px' }} />
<span style={{ fontSize: 'clamp(12px, 4vw, 16px)' }}>{formatUSDC(statistics.totalBuyAmount)} USDC</span>
<span style={{ fontSize: 'clamp(12px, 4vw, 16px)' }}>${formatUSDC(statistics.totalBuyAmount)}</span>
</div>
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '12px', borderBottom: '1px solid #f0f0f0' }}>
@@ -113,7 +113,7 @@ const StatisticsModal: React.FC<StatisticsModalProps> = ({
</div>
<div style={{ fontSize: '16px', fontWeight: '500', color: '#333', flex: '1', textAlign: 'right', display: 'flex', alignItems: 'center', justifyContent: 'flex-end', gap: '4px' }}>
<ArrowDownOutlined style={{ color: '#ff4d4f', fontSize: '14px' }} />
<span style={{ fontSize: 'clamp(12px, 4vw, 16px)' }}>{formatUSDC(statistics.totalSellAmount)} USDC</span>
<span style={{ fontSize: 'clamp(12px, 4vw, 16px)' }}>${formatUSDC(statistics.totalSellAmount)}</span>
</div>
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '12px', borderBottom: '1px solid #f0f0f0' }}>
@@ -138,7 +138,7 @@ const StatisticsModal: React.FC<StatisticsModalProps> = ({
</div>
<div style={{ fontSize: '16px', fontWeight: 'bold', color: getPnlColor(statistics.totalPnl), flex: '1', textAlign: 'right', display: 'flex', alignItems: 'center', justifyContent: 'flex-end', gap: '4px' }}>
{getPnlIcon(statistics.totalPnl)}
<span style={{ fontSize: 'clamp(12px, 4vw, 16px)' }}>{formatUSDC(statistics.totalPnl)} USDC</span>
<span style={{ fontSize: 'clamp(12px, 4vw, 16px)' }}>${formatUSDC(statistics.totalPnl)}</span>
</div>
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '12px', borderBottom: '1px solid #f0f0f0' }}>
@@ -147,7 +147,7 @@ const StatisticsModal: React.FC<StatisticsModalProps> = ({
</div>
<div style={{ fontSize: '16px', fontWeight: '500', color: getPnlColor(statistics.totalRealizedPnl), flex: '1', textAlign: 'right', display: 'flex', alignItems: 'center', justifyContent: 'flex-end', gap: '4px' }}>
{getPnlIcon(statistics.totalRealizedPnl)}
<span style={{ fontSize: 'clamp(12px, 4vw, 16px)' }}>{formatUSDC(statistics.totalRealizedPnl)} USDC</span>
<span style={{ fontSize: 'clamp(12px, 4vw, 16px)' }}>${formatUSDC(statistics.totalRealizedPnl)}</span>
</div>
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '12px', borderBottom: '1px solid #f0f0f0' }}>
@@ -156,7 +156,7 @@ const StatisticsModal: React.FC<StatisticsModalProps> = ({
</div>
<div style={{ fontSize: '16px', fontWeight: '500', color: getPnlColor(statistics.totalUnrealizedPnl), flex: '1', textAlign: 'right', display: 'flex', alignItems: 'center', justifyContent: 'flex-end', gap: '4px' }}>
{getPnlIcon(statistics.totalUnrealizedPnl)}
<span style={{ fontSize: 'clamp(12px, 4vw, 16px)' }}>{formatUSDC(statistics.totalUnrealizedPnl)} USDC</span>
<span style={{ fontSize: 'clamp(12px, 4vw, 16px)' }}>${formatUSDC(statistics.totalUnrealizedPnl)}</span>
</div>
</div>
</div>
@@ -181,16 +181,14 @@ const StatisticsModal: React.FC<StatisticsModalProps> = ({
<Statistic
title={t('copyTradingOrders.totalBuyAmount') || '总买入金额'}
value={formatUSDC(statistics.totalBuyAmount)}
suffix="USDC"
prefix={<ArrowUpOutlined style={{ color: '#1890ff' }} />}
prefix={<><ArrowUpOutlined style={{ color: '#1890ff' }} /> $</>}
/>
</Col>
<Col xs={24} sm={12} md={8}>
<Statistic
title={t('copyTradingOrders.totalSellAmount') || '总卖出金额'}
value={formatUSDC(statistics.totalSellAmount)}
suffix="USDC"
prefix={<ArrowDownOutlined style={{ color: '#ff4d4f' }} />}
prefix={<><ArrowDownOutlined style={{ color: '#ff4d4f' }} /> $</>}
/>
</Col>
<Col xs={24} sm={12} md={8}>
@@ -211,27 +209,24 @@ const StatisticsModal: React.FC<StatisticsModalProps> = ({
<Statistic
title={t('copyTradingOrders.totalPnl') || '总盈亏(含未实现)'}
value={formatUSDC(statistics.totalPnl)}
suffix="USDC"
valueStyle={{ color: getPnlColor(statistics.totalPnl) }}
prefix={getPnlIcon(statistics.totalPnl)}
prefix={<>{getPnlIcon(statistics.totalPnl)} $</>}
/>
</Col>
<Col xs={24} sm={12} md={8}>
<Statistic
title={t('copyTradingOrders.totalRealizedPnl') || '总已实现盈亏'}
value={formatUSDC(statistics.totalRealizedPnl)}
suffix="USDC"
valueStyle={{ color: getPnlColor(statistics.totalRealizedPnl) }}
prefix={getPnlIcon(statistics.totalRealizedPnl)}
prefix={<>{getPnlIcon(statistics.totalRealizedPnl)} $</>}
/>
</Col>
<Col xs={24} sm={12} md={8}>
<Statistic
title={t('copyTradingOrders.totalUnrealizedPnl') || '总未实现盈亏'}
value={formatUSDC(statistics.totalUnrealizedPnl)}
suffix="USDC"
valueStyle={{ color: getPnlColor(statistics.totalUnrealizedPnl) }}
prefix={getPnlIcon(statistics.totalUnrealizedPnl)}
prefix={<>{getPnlIcon(statistics.totalUnrealizedPnl)} $</>}
/>
</Col>
</Row>