1
This commit is contained in:
parent
13f2845201
commit
ceaceb29c6
@ -63,12 +63,25 @@ def _safe_float(value: Any, default: float = 0.0) -> float:
|
||||
return default
|
||||
|
||||
|
||||
def _normalize_contract_symbol(symbol: Any) -> str:
|
||||
text = str(symbol or "").strip().upper()
|
||||
if not text:
|
||||
return "-"
|
||||
if text.endswith("USDTUSDT"):
|
||||
return text[:-4]
|
||||
if text.endswith("/USDT:USDT"):
|
||||
return f"{text.split('/')[0]}USDT"
|
||||
if text.endswith("USDT"):
|
||||
return text
|
||||
if "/" in text:
|
||||
return f"{text.split('/')[0]}USDT"
|
||||
return f"{text}USDT"
|
||||
|
||||
|
||||
def _normalize_platform_position(platform: str, position: Dict[str, Any]) -> Dict[str, Any]:
|
||||
side_raw = str(position.get("side") or "").lower()
|
||||
side = "long" if side_raw in {"buy", "long"} else "short"
|
||||
symbol = position.get("symbol") or position.get("coin") or "-"
|
||||
if isinstance(symbol, str) and symbol.endswith("USDTUSDT"):
|
||||
symbol = symbol.replace("USDTUSDT", "USDT")
|
||||
symbol = _normalize_contract_symbol(position.get("symbol") or position.get("coin") or "-")
|
||||
|
||||
entry_price = _safe_float(position.get("entry_price") or position.get("filled_price"))
|
||||
mark_price = _safe_float(position.get("mark_price") or position.get("current_price"))
|
||||
@ -105,9 +118,7 @@ def _normalize_platform_position(platform: str, position: Dict[str, Any]) -> Dic
|
||||
def _normalize_platform_order(platform: str, order: Dict[str, Any]) -> Dict[str, Any]:
|
||||
side_raw = str(order.get("side") or "").lower()
|
||||
side = "long" if side_raw in {"buy", "long", "b"} else "short"
|
||||
symbol = order.get("symbol") or order.get("coin") or "-"
|
||||
if isinstance(symbol, str) and symbol.endswith("USDTUSDT"):
|
||||
symbol = symbol.replace("USDTUSDT", "USDT")
|
||||
symbol = _normalize_contract_symbol(order.get("symbol") or order.get("coin") or "-")
|
||||
|
||||
price = _safe_float(order.get("price") or order.get("entry_price"))
|
||||
size = abs(_safe_float(order.get("size") or order.get("quantity")))
|
||||
|
||||
@ -3580,7 +3580,7 @@ class CryptoAgent:
|
||||
for order in all_orders:
|
||||
pending_orders.append({
|
||||
'order_id': order.get('order_id'),
|
||||
'symbol': f"{order['symbol']}USDT",
|
||||
'symbol': order.get('symbol'),
|
||||
'side': order.get('side', ''),
|
||||
'entry_price': order.get('price'),
|
||||
'quantity': order.get('size'),
|
||||
|
||||
@ -544,7 +544,7 @@ class BitgetLiveTradingService:
|
||||
|
||||
result.append({
|
||||
"order_id": str(order.get('id', '')),
|
||||
"symbol": coin,
|
||||
"symbol": f"{coin}USDT",
|
||||
"side": order.get('side', ''),
|
||||
"size": size_in_coins,
|
||||
"price": display_price,
|
||||
|
||||
@ -283,6 +283,55 @@
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.toolbar-group {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.filter-chip {
|
||||
appearance: none;
|
||||
border: 1px solid rgba(126, 200, 255, 0.16);
|
||||
background: rgba(255,255,255,0.04);
|
||||
color: var(--muted);
|
||||
border-radius: 999px;
|
||||
padding: 8px 14px;
|
||||
cursor: pointer;
|
||||
font-family: "IBM Plex Mono", monospace;
|
||||
font-size: 12px;
|
||||
transition: all 0.18s ease;
|
||||
}
|
||||
|
||||
.filter-chip.active {
|
||||
color: var(--text);
|
||||
border-color: rgba(126, 200, 255, 0.34);
|
||||
background: rgba(126, 200, 255, 0.14);
|
||||
box-shadow: inset 0 0 0 1px rgba(126, 200, 255, 0.08);
|
||||
}
|
||||
|
||||
.position-card.platform-paper {
|
||||
border-color: rgba(126, 200, 255, 0.22);
|
||||
box-shadow: inset 0 0 0 1px rgba(126, 200, 255, 0.06);
|
||||
}
|
||||
|
||||
.position-card.platform-bitget {
|
||||
border-color: rgba(156, 255, 87, 0.18);
|
||||
box-shadow: inset 0 0 0 1px rgba(156, 255, 87, 0.06);
|
||||
}
|
||||
|
||||
.platform-pill.paper {
|
||||
border-color: rgba(126, 200, 255, 0.32);
|
||||
color: var(--cold);
|
||||
background: rgba(126, 200, 255, 0.10);
|
||||
}
|
||||
|
||||
.platform-pill.bitget {
|
||||
border-color: rgba(156, 255, 87, 0.28);
|
||||
color: var(--accent);
|
||||
background: rgba(156, 255, 87, 0.10);
|
||||
}
|
||||
|
||||
.hero {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1.4fr) minmax(360px, 0.9fr);
|
||||
@ -2769,6 +2818,8 @@
|
||||
let cachedConsoleData = null;
|
||||
let revealSensitiveData = false;
|
||||
let consoleAuthenticated = false;
|
||||
let positionsPlatformFilter = 'all';
|
||||
let ordersPlatformFilter = 'all';
|
||||
const SENSITIVE_VISIBILITY_KEY = 'console_sensitive_visible_v2';
|
||||
const HUB_PREFERENCE_KEY = 'console_hub_active_v1';
|
||||
|
||||
@ -2847,6 +2898,17 @@
|
||||
return Object.values(platformHalts || {}).filter((item) => item && item.halted).length;
|
||||
}
|
||||
|
||||
function normalizePlatformKey(value) {
|
||||
return String(value || '').trim().toLowerCase();
|
||||
}
|
||||
|
||||
function platformDisplayName(value) {
|
||||
const key = normalizePlatformKey(value);
|
||||
if (key === 'paper') return 'PAPER';
|
||||
if (key === 'bitget') return 'BITGET';
|
||||
return String(value || '-').toUpperCase();
|
||||
}
|
||||
|
||||
function setFeedback(message, isError = false) {
|
||||
const el = document.getElementById('feedback');
|
||||
if (!message) {
|
||||
@ -3968,21 +4030,39 @@
|
||||
const toolbar = document.getElementById('positionsToolbar');
|
||||
const container = document.getElementById('positionsTable');
|
||||
const total = positions || [];
|
||||
const platformCounts = ['paper', 'bitget'].map((platform) => {
|
||||
const count = total.filter((item) => item.platform === platform).length;
|
||||
return `<span class="toolbar-chip">${platform}: ${count}</span>`;
|
||||
}).join('');
|
||||
toolbar.innerHTML = `${platformCounts}<span class="toolbar-chip">total: ${total.length}</span>`;
|
||||
const paperCount = total.filter((item) => normalizePlatformKey(item.platform) === 'paper').length;
|
||||
const bitgetCount = total.filter((item) => normalizePlatformKey(item.platform) === 'bitget').length;
|
||||
const filtered = total.filter((item) => positionsPlatformFilter === 'all' || normalizePlatformKey(item.platform) === positionsPlatformFilter);
|
||||
|
||||
if (!total.length) {
|
||||
toolbar.innerHTML = `
|
||||
<div class="toolbar-group">
|
||||
<span class="toolbar-chip">paper: ${paperCount}</span>
|
||||
<span class="toolbar-chip">bitget: ${bitgetCount}</span>
|
||||
<span class="toolbar-chip">total: ${total.length}</span>
|
||||
</div>
|
||||
<div class="toolbar-group">
|
||||
<button class="filter-chip ${positionsPlatformFilter === 'all' ? 'active' : ''}" data-position-filter="all">全部</button>
|
||||
<button class="filter-chip ${positionsPlatformFilter === 'paper' ? 'active' : ''}" data-position-filter="paper">模拟盘</button>
|
||||
<button class="filter-chip ${positionsPlatformFilter === 'bitget' ? 'active' : ''}" data-position-filter="bitget">Bitget</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
toolbar.querySelectorAll('[data-position-filter]').forEach((button) => {
|
||||
button.addEventListener('click', () => {
|
||||
positionsPlatformFilter = button.getAttribute('data-position-filter') || 'all';
|
||||
renderUnifiedPositions(total);
|
||||
});
|
||||
});
|
||||
|
||||
if (!filtered.length) {
|
||||
container.innerHTML = compactEmpty('当前没有跨平台持仓', '没有活动持仓时,这里会保持紧凑,不再占用大块留白。');
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = `
|
||||
<div class="position-card-grid">
|
||||
${total.map((item) => `
|
||||
<article class="position-card ${item.side === 'long' ? 'long' : 'short'}">
|
||||
${filtered.map((item) => `
|
||||
<article class="position-card platform-${normalizePlatformKey(item.platform)} ${item.side === 'long' ? 'long' : 'short'}">
|
||||
<div class="position-card-head">
|
||||
<div>
|
||||
<div class="position-card-symbol">${item.symbol || '-'}</div>
|
||||
@ -3994,7 +4074,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="position-card-tags">
|
||||
<span class="platform-pill">${item.platform}</span>
|
||||
<span class="platform-pill ${normalizePlatformKey(item.platform)}">${platformDisplayName(item.platform)}</span>
|
||||
<span class="side-pill ${item.side === 'long' ? 'long' : 'short'}">${item.side === 'long' ? 'long' : 'short'}</span>
|
||||
${item.setup_type ? `<span class="event-inline-badge">${item.setup_type}</span>` : ''}
|
||||
</div>
|
||||
@ -4028,21 +4108,40 @@
|
||||
const total = orders || [];
|
||||
const entryCount = total.filter((item) => item.category === 'entry').length;
|
||||
const protectionCount = total.filter((item) => item.category === 'tp_sl').length;
|
||||
const paperCount = total.filter((item) => normalizePlatformKey(item.platform) === 'paper').length;
|
||||
const bitgetCount = total.filter((item) => normalizePlatformKey(item.platform) === 'bitget').length;
|
||||
const filtered = total.filter((item) => ordersPlatformFilter === 'all' || normalizePlatformKey(item.platform) === ordersPlatformFilter);
|
||||
toolbar.innerHTML = `
|
||||
<span class="toolbar-chip">entry: ${entryCount}</span>
|
||||
<span class="toolbar-chip">tp/sl: ${protectionCount}</span>
|
||||
<span class="toolbar-chip">total: ${total.length}</span>
|
||||
<div class="toolbar-group">
|
||||
<span class="toolbar-chip">entry: ${entryCount}</span>
|
||||
<span class="toolbar-chip">tp/sl: ${protectionCount}</span>
|
||||
<span class="toolbar-chip">paper: ${paperCount}</span>
|
||||
<span class="toolbar-chip">bitget: ${bitgetCount}</span>
|
||||
<span class="toolbar-chip">total: ${total.length}</span>
|
||||
</div>
|
||||
<div class="toolbar-group">
|
||||
<button class="filter-chip ${ordersPlatformFilter === 'all' ? 'active' : ''}" data-order-filter="all">全部</button>
|
||||
<button class="filter-chip ${ordersPlatformFilter === 'paper' ? 'active' : ''}" data-order-filter="paper">模拟盘</button>
|
||||
<button class="filter-chip ${ordersPlatformFilter === 'bitget' ? 'active' : ''}" data-order-filter="bitget">Bitget</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
if (!total.length) {
|
||||
toolbar.querySelectorAll('[data-order-filter]').forEach((button) => {
|
||||
button.addEventListener('click', () => {
|
||||
ordersPlatformFilter = button.getAttribute('data-order-filter') || 'all';
|
||||
renderUnifiedOrders(total);
|
||||
});
|
||||
});
|
||||
|
||||
if (!filtered.length) {
|
||||
container.innerHTML = compactEmpty('当前没有跨平台挂单', '没有入场单或保护单时,这里会保持紧凑展示。');
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = `
|
||||
<div class="position-card-grid">
|
||||
${total.map((item) => `
|
||||
<article class="position-card ${item.side === 'long' ? 'long' : 'short'}">
|
||||
${filtered.map((item) => `
|
||||
<article class="position-card platform-${normalizePlatformKey(item.platform)} ${item.side === 'long' ? 'long' : 'short'}">
|
||||
<div class="position-card-head">
|
||||
<div>
|
||||
<div class="position-card-symbol">${item.symbol || '-'}</div>
|
||||
@ -4054,7 +4153,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="position-card-tags">
|
||||
<span class="platform-pill">${item.platform}</span>
|
||||
<span class="platform-pill ${normalizePlatformKey(item.platform)}">${platformDisplayName(item.platform)}</span>
|
||||
<span class="side-pill ${item.side === 'long' ? 'long' : 'short'}">${item.side === 'long' ? 'long' : 'short'}</span>
|
||||
${item.signal_grade ? `<span class="event-inline-badge">${item.signal_grade}</span>` : ''}
|
||||
${item.signal_type ? `<span class="event-inline-badge">${item.signal_type}</span>` : ''}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user