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
|
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]:
|
def _normalize_platform_position(platform: str, position: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
side_raw = str(position.get("side") or "").lower()
|
side_raw = str(position.get("side") or "").lower()
|
||||||
side = "long" if side_raw in {"buy", "long"} else "short"
|
side = "long" if side_raw in {"buy", "long"} else "short"
|
||||||
symbol = position.get("symbol") or position.get("coin") or "-"
|
symbol = _normalize_contract_symbol(position.get("symbol") or position.get("coin") or "-")
|
||||||
if isinstance(symbol, str) and symbol.endswith("USDTUSDT"):
|
|
||||||
symbol = symbol.replace("USDTUSDT", "USDT")
|
|
||||||
|
|
||||||
entry_price = _safe_float(position.get("entry_price") or position.get("filled_price"))
|
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"))
|
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]:
|
def _normalize_platform_order(platform: str, order: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
side_raw = str(order.get("side") or "").lower()
|
side_raw = str(order.get("side") or "").lower()
|
||||||
side = "long" if side_raw in {"buy", "long", "b"} else "short"
|
side = "long" if side_raw in {"buy", "long", "b"} else "short"
|
||||||
symbol = order.get("symbol") or order.get("coin") or "-"
|
symbol = _normalize_contract_symbol(order.get("symbol") or order.get("coin") or "-")
|
||||||
if isinstance(symbol, str) and symbol.endswith("USDTUSDT"):
|
|
||||||
symbol = symbol.replace("USDTUSDT", "USDT")
|
|
||||||
|
|
||||||
price = _safe_float(order.get("price") or order.get("entry_price"))
|
price = _safe_float(order.get("price") or order.get("entry_price"))
|
||||||
size = abs(_safe_float(order.get("size") or order.get("quantity")))
|
size = abs(_safe_float(order.get("size") or order.get("quantity")))
|
||||||
|
|||||||
@ -3580,7 +3580,7 @@ class CryptoAgent:
|
|||||||
for order in all_orders:
|
for order in all_orders:
|
||||||
pending_orders.append({
|
pending_orders.append({
|
||||||
'order_id': order.get('order_id'),
|
'order_id': order.get('order_id'),
|
||||||
'symbol': f"{order['symbol']}USDT",
|
'symbol': order.get('symbol'),
|
||||||
'side': order.get('side', ''),
|
'side': order.get('side', ''),
|
||||||
'entry_price': order.get('price'),
|
'entry_price': order.get('price'),
|
||||||
'quantity': order.get('size'),
|
'quantity': order.get('size'),
|
||||||
|
|||||||
@ -544,7 +544,7 @@ class BitgetLiveTradingService:
|
|||||||
|
|
||||||
result.append({
|
result.append({
|
||||||
"order_id": str(order.get('id', '')),
|
"order_id": str(order.get('id', '')),
|
||||||
"symbol": coin,
|
"symbol": f"{coin}USDT",
|
||||||
"side": order.get('side', ''),
|
"side": order.get('side', ''),
|
||||||
"size": size_in_coins,
|
"size": size_in_coins,
|
||||||
"price": display_price,
|
"price": display_price,
|
||||||
|
|||||||
@ -283,6 +283,55 @@
|
|||||||
line-height: 1.6;
|
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 {
|
.hero {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: minmax(0, 1.4fr) minmax(360px, 0.9fr);
|
grid-template-columns: minmax(0, 1.4fr) minmax(360px, 0.9fr);
|
||||||
@ -2769,6 +2818,8 @@
|
|||||||
let cachedConsoleData = null;
|
let cachedConsoleData = null;
|
||||||
let revealSensitiveData = false;
|
let revealSensitiveData = false;
|
||||||
let consoleAuthenticated = false;
|
let consoleAuthenticated = false;
|
||||||
|
let positionsPlatformFilter = 'all';
|
||||||
|
let ordersPlatformFilter = 'all';
|
||||||
const SENSITIVE_VISIBILITY_KEY = 'console_sensitive_visible_v2';
|
const SENSITIVE_VISIBILITY_KEY = 'console_sensitive_visible_v2';
|
||||||
const HUB_PREFERENCE_KEY = 'console_hub_active_v1';
|
const HUB_PREFERENCE_KEY = 'console_hub_active_v1';
|
||||||
|
|
||||||
@ -2847,6 +2898,17 @@
|
|||||||
return Object.values(platformHalts || {}).filter((item) => item && item.halted).length;
|
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) {
|
function setFeedback(message, isError = false) {
|
||||||
const el = document.getElementById('feedback');
|
const el = document.getElementById('feedback');
|
||||||
if (!message) {
|
if (!message) {
|
||||||
@ -3968,21 +4030,39 @@
|
|||||||
const toolbar = document.getElementById('positionsToolbar');
|
const toolbar = document.getElementById('positionsToolbar');
|
||||||
const container = document.getElementById('positionsTable');
|
const container = document.getElementById('positionsTable');
|
||||||
const total = positions || [];
|
const total = positions || [];
|
||||||
const platformCounts = ['paper', 'bitget'].map((platform) => {
|
const paperCount = total.filter((item) => normalizePlatformKey(item.platform) === 'paper').length;
|
||||||
const count = total.filter((item) => item.platform === platform).length;
|
const bitgetCount = total.filter((item) => normalizePlatformKey(item.platform) === 'bitget').length;
|
||||||
return `<span class="toolbar-chip">${platform}: ${count}</span>`;
|
const filtered = total.filter((item) => positionsPlatformFilter === 'all' || normalizePlatformKey(item.platform) === positionsPlatformFilter);
|
||||||
}).join('');
|
|
||||||
toolbar.innerHTML = `${platformCounts}<span class="toolbar-chip">total: ${total.length}</span>`;
|
|
||||||
|
|
||||||
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('当前没有跨平台持仓', '没有活动持仓时,这里会保持紧凑,不再占用大块留白。');
|
container.innerHTML = compactEmpty('当前没有跨平台持仓', '没有活动持仓时,这里会保持紧凑,不再占用大块留白。');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
container.innerHTML = `
|
container.innerHTML = `
|
||||||
<div class="position-card-grid">
|
<div class="position-card-grid">
|
||||||
${total.map((item) => `
|
${filtered.map((item) => `
|
||||||
<article class="position-card ${item.side === 'long' ? 'long' : 'short'}">
|
<article class="position-card platform-${normalizePlatformKey(item.platform)} ${item.side === 'long' ? 'long' : 'short'}">
|
||||||
<div class="position-card-head">
|
<div class="position-card-head">
|
||||||
<div>
|
<div>
|
||||||
<div class="position-card-symbol">${item.symbol || '-'}</div>
|
<div class="position-card-symbol">${item.symbol || '-'}</div>
|
||||||
@ -3994,7 +4074,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="position-card-tags">
|
<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>
|
<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>` : ''}
|
${item.setup_type ? `<span class="event-inline-badge">${item.setup_type}</span>` : ''}
|
||||||
</div>
|
</div>
|
||||||
@ -4028,21 +4108,40 @@
|
|||||||
const total = orders || [];
|
const total = orders || [];
|
||||||
const entryCount = total.filter((item) => item.category === 'entry').length;
|
const entryCount = total.filter((item) => item.category === 'entry').length;
|
||||||
const protectionCount = total.filter((item) => item.category === 'tp_sl').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 = `
|
toolbar.innerHTML = `
|
||||||
<span class="toolbar-chip">entry: ${entryCount}</span>
|
<div class="toolbar-group">
|
||||||
<span class="toolbar-chip">tp/sl: ${protectionCount}</span>
|
<span class="toolbar-chip">entry: ${entryCount}</span>
|
||||||
<span class="toolbar-chip">total: ${total.length}</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('当前没有跨平台挂单', '没有入场单或保护单时,这里会保持紧凑展示。');
|
container.innerHTML = compactEmpty('当前没有跨平台挂单', '没有入场单或保护单时,这里会保持紧凑展示。');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
container.innerHTML = `
|
container.innerHTML = `
|
||||||
<div class="position-card-grid">
|
<div class="position-card-grid">
|
||||||
${total.map((item) => `
|
${filtered.map((item) => `
|
||||||
<article class="position-card ${item.side === 'long' ? 'long' : 'short'}">
|
<article class="position-card platform-${normalizePlatformKey(item.platform)} ${item.side === 'long' ? 'long' : 'short'}">
|
||||||
<div class="position-card-head">
|
<div class="position-card-head">
|
||||||
<div>
|
<div>
|
||||||
<div class="position-card-symbol">${item.symbol || '-'}</div>
|
<div class="position-card-symbol">${item.symbol || '-'}</div>
|
||||||
@ -4054,7 +4153,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="position-card-tags">
|
<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>
|
<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_grade ? `<span class="event-inline-badge">${item.signal_grade}</span>` : ''}
|
||||||
${item.signal_type ? `<span class="event-inline-badge">${item.signal_type}</span>` : ''}
|
${item.signal_type ? `<span class="event-inline-badge">${item.signal_type}</span>` : ''}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user