bit
This commit is contained in:
parent
f1fc7be962
commit
752e63d5fc
158
api.php
158
api.php
@ -3,58 +3,99 @@ include_once 'config.php';
|
||||
|
||||
$action = $_GET['action'] ?? '';
|
||||
|
||||
// Function to fetch real prices from Binance
|
||||
function fetch_binance_prices() {
|
||||
$url = "https://api.binance.com/api/v3/ticker/24hr";
|
||||
// Function to fetch prices with caching
|
||||
function get_real_prices() {
|
||||
$cache_file = __DIR__ . '/db/price_cache.json';
|
||||
$cache_time = 2; // Cache for 2 seconds
|
||||
|
||||
if (file_exists($cache_file) && (time() - filemtime($cache_file) < $cache_time)) {
|
||||
return json_decode(file_get_contents($cache_file), true);
|
||||
}
|
||||
|
||||
// Fetch active coins from DB to only ask for what we need
|
||||
$stmt = db()->query("SELECT symbol FROM cryptocurrencies WHERE is_active = 1");
|
||||
$symbols = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||
|
||||
if (empty($symbols)) return [];
|
||||
|
||||
// Binance API - symbols parameter format: ["BTCUSDT","ETHUSDT"]
|
||||
$symbols_encoded = urlencode(json_encode($symbols));
|
||||
$url = "https://api.binance.com/api/v3/ticker/24hr?symbols=" . $symbols_encoded;
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
|
||||
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0');
|
||||
$response = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
|
||||
if (!$response) return [];
|
||||
if (!$response) {
|
||||
// If Binance fails, try to return expired cache if exists
|
||||
if (file_exists($cache_file)) return json_decode(file_get_contents($cache_file), true);
|
||||
return [];
|
||||
}
|
||||
|
||||
$data = json_decode($response, true);
|
||||
$prices = [];
|
||||
if (is_array($data)) {
|
||||
foreach ($data as $item) {
|
||||
$prices[$item['symbol']] = [
|
||||
'price' => $item['lastPrice'],
|
||||
'change' => $item['priceChangePercent']
|
||||
];
|
||||
if (isset($item['symbol'])) {
|
||||
$prices[$item['symbol']] = [
|
||||
'price' => $item['lastPrice'],
|
||||
'change' => $item['priceChangePercent'],
|
||||
'high' => $item['highPrice'],
|
||||
'low' => $item['lowPrice'],
|
||||
'volume' => $item['quoteVolume']
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($prices)) {
|
||||
file_put_contents($cache_file, json_encode($prices));
|
||||
}
|
||||
|
||||
return $prices;
|
||||
}
|
||||
|
||||
if ($action === 'market_data') {
|
||||
$binance_prices = fetch_binance_prices();
|
||||
$stmt = db()->query("SELECT * FROM cryptocurrencies WHERE is_active = 1");
|
||||
$real_prices = get_real_prices();
|
||||
$stmt = db()->query("SELECT * FROM cryptocurrencies WHERE is_active = 1 ORDER BY id ASC");
|
||||
$coins = $stmt->fetchAll();
|
||||
|
||||
foreach ($coins as &$coin) {
|
||||
$updated_coins = [];
|
||||
foreach ($coins as $coin) {
|
||||
$symbol = $coin['symbol'];
|
||||
if (isset($binance_prices[$symbol])) {
|
||||
$coin['price'] = (float)$binance_prices[$symbol]['price'];
|
||||
$coin['change'] = (float)$binance_prices[$symbol]['change'];
|
||||
|
||||
if (isset($real_prices[$symbol])) {
|
||||
$coin['price'] = (float)$real_prices[$symbol]['price'];
|
||||
$coin['change'] = (float)$real_prices[$symbol]['change'];
|
||||
$coin['high'] = (float)$real_prices[$symbol]['high'];
|
||||
$coin['low'] = (float)$real_prices[$symbol]['low'];
|
||||
$coin['volume'] = (float)$real_prices[$symbol]['volume'];
|
||||
|
||||
// Apply manual price if set
|
||||
if ($coin['manual_price'] > 0) {
|
||||
$coin['price'] = (float)$coin['manual_price'];
|
||||
}
|
||||
|
||||
// Update DB with latest price
|
||||
// Periodically update DB (every few seconds to avoid overhead)
|
||||
// We'll update the database to keep it relatively fresh for order submission
|
||||
$upd = db()->prepare("UPDATE cryptocurrencies SET current_price = ?, change_24h = ? WHERE id = ?");
|
||||
$upd->execute([$coin['price'], $coin['change'], $coin['id']]);
|
||||
} else {
|
||||
$coin['price'] = (float)$coin['current_price'];
|
||||
$coin['change'] = (float)$coin['change_24h'];
|
||||
$coin['high'] = $coin['price'] * 1.02; // Fallback
|
||||
$coin['low'] = $coin['price'] * 0.98;
|
||||
$coin['volume'] = 0;
|
||||
}
|
||||
$updated_coins[] = $coin;
|
||||
}
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($coins);
|
||||
echo json_encode($updated_coins);
|
||||
exit;
|
||||
}
|
||||
|
||||
@ -81,11 +122,24 @@ if ($action === 'submit_order') {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Get current price
|
||||
// IMPORTANT: Fetch FRESH price for order execution
|
||||
$real_prices = get_real_prices();
|
||||
$stmt = db()->prepare("SELECT * FROM cryptocurrencies WHERE symbol = ?");
|
||||
$stmt->execute([$symbol]);
|
||||
$coin = $stmt->fetch();
|
||||
$current_price = $coin ? (float)$coin['current_price'] : 0;
|
||||
|
||||
if (!$coin) {
|
||||
echo json_encode(['status' => 'error', 'message' => '不支持该币种']);
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($coin['manual_price'] > 0) {
|
||||
$current_price = (float)$coin['manual_price'];
|
||||
} elseif (isset($real_prices[$symbol])) {
|
||||
$current_price = (float)$real_prices[$symbol]['price'];
|
||||
} else {
|
||||
$current_price = (float)$coin['current_price'];
|
||||
}
|
||||
|
||||
if ($current_price <= 0) {
|
||||
echo json_encode(['status' => 'error', 'message' => '价格获取失败,请重试']);
|
||||
@ -100,7 +154,7 @@ if ($action === 'submit_order') {
|
||||
if ($side === 'BUY') {
|
||||
$total_cost = $amount * $current_price;
|
||||
if ($account['balance'] < $total_cost) {
|
||||
throw new Exception('余额不足 (需要 ' . $total_cost . ' USDT)');
|
||||
throw new Exception('余额不足 (需要 ' . number_format($total_cost, 2) . ' USDT)');
|
||||
}
|
||||
|
||||
// Deduct USDT
|
||||
@ -108,8 +162,9 @@ if ($action === 'submit_order') {
|
||||
$stmt->execute([$total_cost, $account['id']]);
|
||||
|
||||
// Add Asset
|
||||
$currency = str_replace('USDT', '', $symbol);
|
||||
$stmt = $db->prepare("INSERT INTO assets (account_id, currency, balance) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE balance = balance + ?");
|
||||
$stmt->execute([$account['id'], str_replace('USDT', '', $symbol), $amount, $amount]);
|
||||
$stmt->execute([$account['id'], $currency, $amount, $amount]);
|
||||
|
||||
} else { // SELL
|
||||
$currency = str_replace('USDT', '', $symbol);
|
||||
@ -136,10 +191,14 @@ if ($action === 'submit_order') {
|
||||
$stmt->execute([$account['id'], $symbol, $side, $current_price, $amount, $amount * $current_price]);
|
||||
|
||||
} else if ($trade_type === 'CONTRACT') {
|
||||
// Simple Contract Logic: Deduct Margin
|
||||
$margin = ($amount * $current_price) / $leverage;
|
||||
// Contract Value per Lot is 100 USDT by default in trade.php
|
||||
// but we use 'amount' as lots.
|
||||
$contract_value = 100; // Standard value
|
||||
$total_value = $amount * $contract_value;
|
||||
$margin = $total_value / $leverage;
|
||||
|
||||
if ($account['balance'] < $margin) {
|
||||
throw new Exception('保证金不足 (需要 ' . $margin . ' USDT)');
|
||||
throw new Exception('保证金不足 (需要 ' . number_format($margin, 2) . ' USDT)');
|
||||
}
|
||||
|
||||
// Deduct Margin
|
||||
@ -173,17 +232,32 @@ if ($action === 'positions') {
|
||||
$stmt->execute([$account['id']]);
|
||||
$positions = $stmt->fetchAll();
|
||||
|
||||
$real_prices = get_real_prices();
|
||||
|
||||
// Calculate PnL for each position
|
||||
foreach ($positions as &$pos) {
|
||||
$stmt = db()->prepare("SELECT current_price FROM cryptocurrencies WHERE symbol = ?");
|
||||
$stmt->execute([$pos['symbol']]);
|
||||
$coin = $stmt->fetch();
|
||||
$current_price = $coin ? (float)$coin['current_price'] : $pos['entry_price'];
|
||||
$symbol = $pos['symbol'];
|
||||
|
||||
if ($pos['side'] === 'LONG') {
|
||||
$pos['pnl'] = ($current_price - $pos['entry_price']) * $pos['lots'];
|
||||
// Use fresh price for PnL calculation
|
||||
$stmt = db()->prepare("SELECT manual_price, current_price FROM cryptocurrencies WHERE symbol = ?");
|
||||
$stmt->execute([$symbol]);
|
||||
$coin = $stmt->fetch();
|
||||
|
||||
if ($coin && $coin['manual_price'] > 0) {
|
||||
$current_price = (float)$coin['manual_price'];
|
||||
} elseif (isset($real_prices[$symbol])) {
|
||||
$current_price = (float)$real_prices[$symbol]['price'];
|
||||
} else {
|
||||
$pos['pnl'] = ($pos['entry_price'] - $current_price) * $pos['lots'];
|
||||
$current_price = (float)$pos['entry_price'];
|
||||
}
|
||||
|
||||
$pos['current_price'] = $current_price;
|
||||
|
||||
// PnL Calculation: (PriceDiff / EntryPrice) * Margin * Leverage
|
||||
if ($pos['side'] === 'LONG') {
|
||||
$pos['pnl'] = (($current_price - $pos['entry_price']) / $pos['entry_price']) * $pos['margin'] * $pos['leverage'];
|
||||
} else {
|
||||
$pos['pnl'] = (($pos['entry_price'] - $current_price) / $pos['entry_price']) * $pos['margin'] * $pos['leverage'];
|
||||
}
|
||||
|
||||
// Apply Win/Loss Control (Display purpose)
|
||||
@ -192,8 +266,6 @@ if ($action === 'positions') {
|
||||
} else if ($account['win_loss_control'] == -1 && $pos['pnl'] > 0) {
|
||||
$pos['pnl'] = -abs($pos['pnl']) * 1.5; // Show big loss
|
||||
}
|
||||
|
||||
$pos['current_price'] = $current_price;
|
||||
}
|
||||
|
||||
echo json_encode($positions);
|
||||
@ -217,15 +289,25 @@ if ($action === 'close_position') {
|
||||
|
||||
if (!$pos) throw new Exception('仓位不存在');
|
||||
|
||||
$stmt = db()->prepare("SELECT current_price FROM cryptocurrencies WHERE symbol = ?");
|
||||
$stmt->execute([$pos['symbol']]);
|
||||
$symbol = $pos['symbol'];
|
||||
$real_prices = get_real_prices();
|
||||
|
||||
$stmt = db()->prepare("SELECT manual_price, current_price FROM cryptocurrencies WHERE symbol = ?");
|
||||
$stmt->execute([$symbol]);
|
||||
$coin = $stmt->fetch();
|
||||
$current_price = $coin ? (float)$coin['current_price'] : $pos['entry_price'];
|
||||
|
||||
if ($coin && $coin['manual_price'] > 0) {
|
||||
$current_price = (float)$coin['manual_price'];
|
||||
} elseif (isset($real_prices[$symbol])) {
|
||||
$current_price = (float)$real_prices[$symbol]['price'];
|
||||
} else {
|
||||
$current_price = (float)$pos['entry_price'];
|
||||
}
|
||||
|
||||
if ($pos['side'] === 'LONG') {
|
||||
$pnl = ($current_price - $pos['entry_price']) * $pos['lots'];
|
||||
$pnl = (($current_price - $pos['entry_price']) / $pos['entry_price']) * $pos['margin'] * $pos['leverage'];
|
||||
} else {
|
||||
$pnl = ($pos['entry_price'] - $current_price) * $pos['lots'];
|
||||
$pnl = (($pos['entry_price'] - $current_price) / $pos['entry_price']) * $pos['margin'] * $pos['leverage'];
|
||||
}
|
||||
|
||||
// Win/Loss Control Logic
|
||||
@ -254,4 +336,4 @@ if ($action === 'close_position') {
|
||||
}
|
||||
exit;
|
||||
}
|
||||
?>
|
||||
?>
|
||||
65
index.php
65
index.php
@ -8,7 +8,7 @@ include 'header.php';
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-6">
|
||||
<h1 class="display-4 fw-bold text-white mb-4">开启您的数字资产 <span class="text-warning">交易之旅</span></h1>
|
||||
<p class="lead text-secondary mb-5">全球信赖的加密资产交易平台,提供极速、安全、专业的数字资产交易服务。</p>
|
||||
<p class="lead text-secondary mb-5">全球信赖的加密资产交易平台,提供极速、安全、专业的数字资产交易服务。支持现货及永续合约交易。</p>
|
||||
<div class="d-flex gap-3">
|
||||
<?php if(!isset($_SESSION['user_id'])): ?>
|
||||
<a href="register.php" class="btn btn-warning btn-lg px-5 fw-bold">立即注册</a>
|
||||
@ -27,23 +27,23 @@ include 'header.php';
|
||||
|
||||
<!-- Stats Bar -->
|
||||
<div class="container mt-n5 position-relative" style="z-index: 10;">
|
||||
<div class="glass-card p-4 shadow-lg">
|
||||
<div class="glass-card p-4 shadow-lg" style="background: rgba(30, 32, 38, 0.9); border: 1px solid #3b4149;">
|
||||
<div class="row text-center g-4">
|
||||
<div class="col-md-3">
|
||||
<div class="text-secondary small mb-1">24h 交易量</div>
|
||||
<div class="fs-4 fw-bold">$76.2B</div>
|
||||
<div class="fs-4 fw-bold text-white">$76.2B</div>
|
||||
</div>
|
||||
<div class="col-md-3 border-start border-secondary">
|
||||
<div class="text-secondary small mb-1">主流币种</div>
|
||||
<div class="fs-4 fw-bold">350+</div>
|
||||
<div class="fs-4 fw-bold text-white">350+</div>
|
||||
</div>
|
||||
<div class="col-md-3 border-start border-secondary">
|
||||
<div class="text-secondary small mb-1">注册用户</div>
|
||||
<div class="fs-4 fw-bold">120M+</div>
|
||||
<div class="fs-4 fw-bold text-white">120M+</div>
|
||||
</div>
|
||||
<div class="col-md-3 border-start border-secondary">
|
||||
<div class="text-secondary small mb-1">最低费率</div>
|
||||
<div class="fs-4 fw-bold">0.10%</div>
|
||||
<div class="fs-4 fw-bold text-white">0.10%</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -55,24 +55,23 @@ include 'header.php';
|
||||
<div class="d-flex justify-content-between align-items-end mb-4">
|
||||
<div>
|
||||
<h2 class="fw-bold text-white">热门市场</h2>
|
||||
<p class="text-secondary mb-0">实时行情,快人一步</p>
|
||||
<p class="text-secondary mb-0">实时行情,全球同步</p>
|
||||
</div>
|
||||
<a href="trade.php" class="text-warning text-decoration-none">查看更多 <i class="bi bi-arrow-right"></i></a>
|
||||
<a href="market.php" class="text-warning text-decoration-none fw-bold">查看行情中心 <i class="bi bi-arrow-right"></i></a>
|
||||
</div>
|
||||
|
||||
<div class="glass-card overflow-hidden">
|
||||
<div class="glass-card overflow-hidden" style="border: 1px solid #2b2f36;">
|
||||
<table class="table table-dark table-hover mb-0 align-middle">
|
||||
<thead>
|
||||
<tr class="text-secondary border-bottom border-secondary">
|
||||
<tr class="text-secondary" style="background: #1e2329;">
|
||||
<th class="ps-4 py-3">名称</th>
|
||||
<th class="py-3">最新价</th>
|
||||
<th class="py-3">最新价 (USDT)</th>
|
||||
<th class="py-3">24h 涨跌</th>
|
||||
<th class="py-3">24h 成交额</th>
|
||||
<th class="py-3">24h 最高 / 最低</th>
|
||||
<th class="py-3 text-end pe-4">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="market-tbody">
|
||||
<!-- Loaded via JS -->
|
||||
<tr><td colspan="5" class="text-center py-5"><div class="spinner-border text-warning"></div></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@ -81,28 +80,28 @@ include 'header.php';
|
||||
</section>
|
||||
|
||||
<!-- Features -->
|
||||
<section class="py-5 bg-dark">
|
||||
<section class="py-5" style="background-color: #0b0e11;">
|
||||
<div class="container">
|
||||
<div class="row g-4 text-center">
|
||||
<div class="col-md-4">
|
||||
<div class="p-4 h-100">
|
||||
<div class="p-4 h-100 glass-card">
|
||||
<i class="bi bi-shield-check display-4 text-warning mb-3"></i>
|
||||
<h4 class="text-white">安全可靠</h4>
|
||||
<p class="text-secondary">采用多重安全防护机制,冷热钱包分离,保障您的资产安全。</p>
|
||||
<p class="text-secondary">采用多重安全防护机制,冷热钱包分离,保障您的资产安全。符合国际最高合规标准。</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="p-4 h-100">
|
||||
<div class="p-4 h-100 glass-card">
|
||||
<i class="bi bi-lightning-charge display-4 text-warning mb-3"></i>
|
||||
<h4 class="text-white">极速撮合</h4>
|
||||
<p class="text-secondary">自研高性能撮合引擎,支持百万级并发交易,告别卡顿延迟。</p>
|
||||
<p class="text-secondary">自研高性能撮合引擎,支持百万级并发交易,告别卡顿延迟。平均响应时间小于10ms。</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="p-4 h-100">
|
||||
<div class="p-4 h-100 glass-card">
|
||||
<i class="bi bi-headset display-4 text-warning mb-3"></i>
|
||||
<h4 class="text-white">专业支持</h4>
|
||||
<p class="text-secondary">7*24小时多语种在线客服,随时解答您的任何疑问。</p>
|
||||
<p class="text-secondary">7*24小时多语种在线客服,随时解答您的任何疑问。为您提供保驾护航的交易环境。</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -110,6 +109,14 @@ include 'header.php';
|
||||
</section>
|
||||
|
||||
<script>
|
||||
function formatPrice(p) {
|
||||
p = parseFloat(p);
|
||||
if (p < 0.0001) return p.toFixed(8);
|
||||
if (p < 0.01) return p.toFixed(6);
|
||||
if (p < 1) return p.toFixed(4);
|
||||
return p.toFixed(2);
|
||||
}
|
||||
|
||||
async function loadMarket() {
|
||||
try {
|
||||
const res = await fetch('api.php?action=market_data');
|
||||
@ -119,22 +126,26 @@ async function loadMarket() {
|
||||
|
||||
data.slice(0, 8).forEach(coin => {
|
||||
const changeClass = coin.change >= 0 ? 'text-success' : 'text-danger';
|
||||
const pFormatted = formatPrice(coin.price);
|
||||
html += `
|
||||
<tr style="cursor: pointer;" onclick="location.href='trade.php?symbol=${coin.symbol}'">
|
||||
<tr style="cursor: pointer;" onclick="location.href='trade.php?symbol=${coin.symbol}'" class="border-bottom border-secondary">
|
||||
<td class="ps-4 py-4">
|
||||
<div class="d-flex align-items-center">
|
||||
<img src="${coin.icon_url}" class="me-3" style="width:32px; height:32px;">
|
||||
<img src="${coin.icon_url}" class="me-3 rounded-circle" style="width:32px; height:32px;" onerror="this.src='https://cryptologos.cc/logos/generic-coin-logo.png'">
|
||||
<div>
|
||||
<div class="fw-bold text-white">${coin.symbol.replace('USDT', '')}</div>
|
||||
<div class="text-secondary small">${coin.name}</div>
|
||||
<div class="text-secondary small" style="font-size: 11px;">${coin.name}</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td><span class="fw-bold">${parseFloat(coin.price).toLocaleString(undefined, {minimumFractionDigits: 2})}</span></td>
|
||||
<td><span class="fw-bold fs-5">${pFormatted}</span></td>
|
||||
<td><span class="${changeClass} fw-bold">${coin.change >= 0 ? '+' : ''}${coin.change}%</span></td>
|
||||
<td class="text-secondary">$ --</td>
|
||||
<td>
|
||||
<div class="smaller text-white">${formatPrice(coin.high || coin.price*1.01)}</div>
|
||||
<div class="smaller text-secondary">${formatPrice(coin.low || coin.price*0.99)}</div>
|
||||
</td>
|
||||
<td class="text-end pe-4">
|
||||
<a href="trade.php?symbol=${coin.symbol}" class="btn btn-sm btn-outline-warning px-3">交易</a>
|
||||
<a href="trade.php?symbol=${coin.symbol}" class="btn btn-sm btn-outline-warning px-3 fw-bold">立即交易</a>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
@ -149,4 +160,4 @@ loadMarket();
|
||||
setInterval(loadMarket, 5000);
|
||||
</script>
|
||||
|
||||
<?php include 'footer.php'; ?>
|
||||
<?php include 'footer.php'; ?>
|
||||
|
||||
97
market.php
97
market.php
@ -3,60 +3,97 @@ include 'header.php';
|
||||
?>
|
||||
<div class="container py-5">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2 class="text-white fw-bold">行情中心</h2>
|
||||
<div class="input-group style="width: 300px;">
|
||||
<input type="text" class="form-control bg-dark text-white border-secondary" placeholder="搜索币种...">
|
||||
<div>
|
||||
<h2 class="text-white fw-bold">行情中心</h2>
|
||||
<p class="text-secondary small">实时监测全球主流数字货币市场价格波动</p>
|
||||
</div>
|
||||
<div class="input-group" style="width: 300px;">
|
||||
<span class="input-group-text bg-dark border-secondary text-secondary"><i class="bi bi-search"></i></span>
|
||||
<input type="text" id="market-search" class="form-control bg-dark text-white border-secondary" placeholder="搜索币种..." onkeyup="filterMarket()">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="glass-card">
|
||||
<table class="table table-dark table-hover align-middle mb-0">
|
||||
<thead>
|
||||
<tr class="text-secondary border-bottom border-secondary">
|
||||
<th class="ps-4">币种</th>
|
||||
<th>价格</th>
|
||||
<th>24h 涨跌</th>
|
||||
<th>24h 最高</th>
|
||||
<th>24h 最低</th>
|
||||
<th class="text-end pe-4">交易</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="full-market-tbody">
|
||||
<tr><td colspan="6" class="text-center py-5"><div class="spinner-border text-warning"></div></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="glass-card shadow-lg">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-dark table-hover align-middle mb-0">
|
||||
<thead>
|
||||
<tr class="text-secondary border-bottom border-secondary" style="background: #1e2329;">
|
||||
<th class="ps-4 py-3">币种名称</th>
|
||||
<th>最新价格 (USDT)</th>
|
||||
<th>24h 涨跌</th>
|
||||
<th>24h 最高</th>
|
||||
<th>24h 最低</th>
|
||||
<th>24h 成交额</th>
|
||||
<th class="text-end pe-4">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="full-market-tbody">
|
||||
<tr><td colspan="7" class="text-center py-5"><div class="spinner-border text-warning"></div></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let allMarketData = [];
|
||||
|
||||
function formatPrice(p) {
|
||||
p = parseFloat(p);
|
||||
if (p < 0.0001) return p.toFixed(8);
|
||||
if (p < 0.01) return p.toFixed(6);
|
||||
if (p < 1) return p.toFixed(4);
|
||||
return p.toFixed(2);
|
||||
}
|
||||
|
||||
async function refreshMarket() {
|
||||
const res = await fetch('api.php?action=market_data');
|
||||
const data = await res.json();
|
||||
try {
|
||||
const res = await fetch('api.php?action=market_data');
|
||||
const data = await res.json();
|
||||
allMarketData = data;
|
||||
renderMarket();
|
||||
} catch (e) {
|
||||
console.error('Market refresh failed', e);
|
||||
}
|
||||
}
|
||||
|
||||
function renderMarket() {
|
||||
const search = document.getElementById('market-search').value.toLowerCase();
|
||||
let html = '';
|
||||
data.forEach(coin => {
|
||||
allMarketData.forEach(coin => {
|
||||
if (search && !coin.symbol.toLowerCase().includes(search)) return;
|
||||
|
||||
const changeClass = coin.change >= 0 ? 'text-success' : 'text-danger';
|
||||
const pFormatted = formatPrice(coin.price);
|
||||
|
||||
html += `
|
||||
<tr onclick="location.href='trade.php?symbol=${coin.symbol}'" style="cursor:pointer">
|
||||
<tr onclick="location.href='trade.php?symbol=${coin.symbol}'" style="cursor:pointer" class="border-bottom border-secondary">
|
||||
<td class="ps-4 py-3">
|
||||
<div class="d-flex align-items-center">
|
||||
<img src="${coin.icon_url}" class="me-2" width="24">
|
||||
<span class="fw-bold">${coin.symbol}</span>
|
||||
<img src="${coin.icon_url}" class="me-3 rounded-circle" width="32" height="32" onerror="this.src='https://cryptologos.cc/logos/generic-coin-logo.png'">
|
||||
<div>
|
||||
<span class="fw-bold text-white d-block">${coin.symbol.replace('USDT', '')}</span>
|
||||
<span class="text-secondary smaller" style="font-size: 11px;">${coin.name}</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="fw-bold">${parseFloat(coin.price).toFixed(coin.price<1?4:2)}</td>
|
||||
<td class="fw-bold fs-5">${pFormatted}</td>
|
||||
<td class="${changeClass} fw-bold">${coin.change >= 0 ? '+' : ''}${coin.change}%</td>
|
||||
<td>${(coin.price * 1.05).toFixed(2)}</td>
|
||||
<td>${(coin.price * 0.95).toFixed(2)}</td>
|
||||
<td>${formatPrice(coin.high || coin.price * 1.02)}</td>
|
||||
<td>${formatPrice(coin.low || coin.price * 0.98)}</td>
|
||||
<td class="text-secondary">$ ${parseFloat(coin.volume || 0).toLocaleString()}</td>
|
||||
<td class="text-end pe-4">
|
||||
<a href="trade.php?symbol=${coin.symbol}" class="btn btn-sm btn-warning">交易</a>
|
||||
<a href="trade.php?symbol=${coin.symbol}" class="btn btn-sm btn-warning px-3 fw-bold">去交易</a>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
document.getElementById('full-market-tbody').innerHTML = html;
|
||||
}
|
||||
|
||||
function filterMarket() { renderMarket(); }
|
||||
|
||||
refreshMarket();
|
||||
setInterval(refreshMarket, 3000);
|
||||
</script>
|
||||
<?php include 'footer.php'; ?>
|
||||
<?php include 'footer.php'; ?>
|
||||
322
trade.php
322
trade.php
@ -11,24 +11,32 @@ $base_symbol = str_replace('USDT', '', $symbol);
|
||||
include 'header.php';
|
||||
?>
|
||||
<style>
|
||||
.glass-card { background: rgba(30, 32, 38, 0.9); border: 1px solid #2b2f36; border-radius: 4px; overflow: hidden; }
|
||||
.trade-nav-item { cursor: pointer; padding: 10px 15px; border-bottom: 2px solid transparent; color: #848e9c; }
|
||||
.trade-nav-item.active { border-bottom-color: #f0b90b; color: #f0b90b; }
|
||||
.coin-row:hover { background: #2b2f36; cursor: pointer; }
|
||||
.price-up { color: #0ecb81; }
|
||||
.price-down { color: #f6465d; }
|
||||
#order-book table td { padding: 2px 8px; font-size: 12px; }
|
||||
.glass-card { background: rgba(24, 26, 32, 1); border: 1px solid #2b2f36; border-radius: 4px; overflow: hidden; }
|
||||
.trade-nav-item { cursor: pointer; padding: 10px 15px; border-bottom: 2px solid transparent; color: #848e9c; font-size: 14px; }
|
||||
.trade-nav-item.active { border-bottom-color: #f0b90b; color: #f0b90b; font-weight: bold; }
|
||||
.coin-row { transition: background 0.2s; border-bottom: 1px solid #1e2329; }
|
||||
.coin-row:hover { background: #2b3139; cursor: pointer; }
|
||||
.coin-row.active { background: #1e2329; border-left: 3px solid #f0b90b; }
|
||||
.price-up { color: #0ecb81 !important; }
|
||||
.price-down { color: #f6465d !important; }
|
||||
#order-book table td { padding: 3px 8px; font-size: 12px; }
|
||||
.smaller { font-size: 11px; }
|
||||
::-webkit-scrollbar { width: 4px; }
|
||||
::-webkit-scrollbar-thumb { background: #3b4149; border-radius: 10px; }
|
||||
</style>
|
||||
|
||||
<div class="container-fluid px-1 py-1" style="background-color: #0b0e11; min-height: 95vh; color: #eaecef;">
|
||||
<div class="row g-1">
|
||||
<!-- Market List -->
|
||||
<div class="col-lg-2">
|
||||
<div class="glass-card h-100">
|
||||
<div class="p-2 border-bottom border-secondary">
|
||||
<input type="text" id="coin-search" class="form-control form-control-sm bg-dark text-white border-secondary" placeholder="搜索">
|
||||
<div class="glass-card h-100" style="max-height: 900px; display: flex; flex-direction: column;">
|
||||
<div class="p-2 border-bottom border-secondary bg-dark">
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="input-group-text bg-transparent border-secondary text-secondary"><i class="bi bi-search"></i></span>
|
||||
<input type="text" id="coin-search" class="form-control bg-transparent text-white border-secondary" placeholder="搜索币种" onkeyup="filterCoins()">
|
||||
</div>
|
||||
</div>
|
||||
<div id="left-coin-list" style="max-height: 800px; overflow-y: auto;">
|
||||
<div id="left-coin-list" style="overflow-y: auto; flex-grow: 1;">
|
||||
<!-- JS populated -->
|
||||
</div>
|
||||
</div>
|
||||
@ -37,38 +45,50 @@ include 'header.php';
|
||||
<!-- Chart & Trade -->
|
||||
<div class="col-lg-7">
|
||||
<!-- Ticker Header -->
|
||||
<div class="glass-card mb-1 p-2 d-flex align-items-center">
|
||||
<div class="glass-card mb-1 p-2 d-flex align-items-center bg-dark">
|
||||
<div class="d-flex align-items-center me-4">
|
||||
<span class="fw-bold fs-5 text-white"><?php echo $symbol; ?></span>
|
||||
<span class="fw-bold fs-5 text-white" id="current-symbol-title"><?php echo $symbol; ?></span>
|
||||
</div>
|
||||
<div class="me-4 border-end border-secondary pe-4">
|
||||
<div class="fw-bold fs-5" id="header-price">--</div>
|
||||
<div class="smaller text-secondary">≈ $<span id="header-price-usd">--</span></div>
|
||||
</div>
|
||||
<div class="me-4">
|
||||
<div class="fw-bold fs-5" id="header-price">--</div>
|
||||
<div class="small" id="header-change">--</div>
|
||||
<div class="smaller text-secondary mb-1">24h 涨跌</div>
|
||||
<div class="fw-bold" id="header-change">--</div>
|
||||
</div>
|
||||
<div class="ms-auto d-flex gap-1">
|
||||
<a href="?type=SPOT&symbol=<?php echo $symbol; ?>" class="btn btn-sm <?php echo $trade_type=='SPOT'?'btn-warning':'btn-outline-secondary'; ?>">现货</a>
|
||||
<a href="?type=CONTRACT&symbol=<?php echo $symbol; ?>" class="btn btn-sm <?php echo $trade_type=='CONTRACT'?'btn-warning':'btn-outline-secondary'; ?>">永续</a>
|
||||
<div class="me-4 d-none d-md-block">
|
||||
<div class="smaller text-secondary mb-1">24h 最高</div>
|
||||
<div class="fw-bold smaller" id="header-high">--</div>
|
||||
</div>
|
||||
<div class="me-4 d-none d-md-block">
|
||||
<div class="smaller text-secondary mb-1">24h 最低</div>
|
||||
<div class="fw-bold smaller" id="header-low">--</div>
|
||||
</div>
|
||||
<div class="ms-auto d-flex gap-1 bg-black p-1 rounded">
|
||||
<a href="?type=SPOT&symbol=<?php echo $symbol; ?>" class="btn btn-sm <?php echo $trade_type=='SPOT'?'btn-warning':'text-secondary'; ?> fw-bold px-3">现货</a>
|
||||
<a href="?type=CONTRACT&symbol=<?php echo $symbol; ?>" class="btn btn-sm <?php echo $trade_type=='CONTRACT'?'btn-warning':'text-secondary'; ?> fw-bold px-3">合约</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- TradingView -->
|
||||
<div class="glass-card mb-1" style="height: 450px;">
|
||||
<div class="glass-card mb-1" style="height: 480px;">
|
||||
<div id="tradingview_widget" style="height: 100%;"></div>
|
||||
</div>
|
||||
|
||||
<!-- Trading Form -->
|
||||
<div class="glass-card p-3">
|
||||
<div class="row">
|
||||
<div class="row g-4">
|
||||
<div class="col-md-6 border-end border-secondary">
|
||||
<div class="d-flex justify-content-between mb-3">
|
||||
<span class="text-success fw-bold">买入 / 做多</span>
|
||||
<span class="text-secondary small">可用: <span class="text-white" id="usdt-balance"><?php echo number_format($account['balance'], 2); ?></span> USDT</span>
|
||||
<div class="d-flex justify-content-between mb-3 align-items-center">
|
||||
<span class="text-success fw-bold fs-5">买入 / 做多</span>
|
||||
<span class="text-secondary smaller">可用: <span class="text-white" id="usdt-balance"><?php echo number_format($account['balance'], 2); ?></span> USDT</span>
|
||||
</div>
|
||||
|
||||
<?php if ($trade_type === 'CONTRACT'): ?>
|
||||
<div class="mb-3">
|
||||
<label class="small text-secondary">杠杆</label>
|
||||
<select id="leverage" class="form-select form-select-sm bg-dark text-white border-secondary">
|
||||
<div class="mb-3 d-flex align-items-center gap-2">
|
||||
<label class="smaller text-secondary" style="min-width: 40px;">杠杆</label>
|
||||
<select id="leverage" class="form-select form-select-sm bg-dark text-white border-secondary w-auto" style="min-width: 100px;">
|
||||
<option value="10">10x</option>
|
||||
<option value="20" selected>20x</option>
|
||||
<option value="50">50x</option>
|
||||
@ -78,40 +98,41 @@ include 'header.php';
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="input-group input-group-sm mb-3">
|
||||
<span class="input-group-text bg-dark text-secondary border-secondary">价格</span>
|
||||
<input type="text" class="form-control bg-dark text-white border-secondary" value="市场价" disabled>
|
||||
<span class="input-group-text bg-dark text-secondary border-secondary" style="width: 60px;">价格</span>
|
||||
<input type="text" class="form-control bg-dark text-warning border-secondary fw-bold" value="市场最优价" disabled>
|
||||
</div>
|
||||
|
||||
<div class="input-group input-group-sm mb-3">
|
||||
<span class="input-group-text bg-dark text-secondary border-secondary">数量</span>
|
||||
<input type="number" id="buy-amount" class="form-control bg-dark text-white border-secondary">
|
||||
<span class="input-group-text bg-dark text-secondary border-secondary"><?php echo $base_symbol; ?></span>
|
||||
<span class="input-group-text bg-dark text-secondary border-secondary" style="width: 60px;"><?php echo $trade_type=='CONTRACT'?'手数':'数量'; ?></span>
|
||||
<input type="number" id="buy-amount" class="form-control bg-dark text-white border-secondary" placeholder="0.00">
|
||||
<span class="input-group-text bg-dark text-secondary border-secondary"><?php echo $trade_type=='CONTRACT'?'张':$base_symbol; ?></span>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-success w-100 fw-bold" onclick="submitOrder('BUY')">买入 (做多)</button>
|
||||
<button class="btn btn-success w-100 fw-bold py-2 shadow-sm" onclick="submitOrder('BUY')">立即买入 (做多)</button>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex justify-content-between mb-3">
|
||||
<span class="text-danger fw-bold">卖出 / 做空</span>
|
||||
<div class="d-flex justify-content-between mb-3 align-items-center">
|
||||
<span class="text-danger fw-bold fs-5">卖出 / 做空</span>
|
||||
<span class="text-secondary smaller">市价委托</span>
|
||||
</div>
|
||||
|
||||
<?php if ($trade_type === 'CONTRACT'): ?>
|
||||
<div class="mb-3"><label class="small"> </label><div style="height:31px"></div></div>
|
||||
<div class="mb-3"><div style="height:31px"></div></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="input-group input-group-sm mb-3">
|
||||
<span class="input-group-text bg-dark text-secondary border-secondary">价格</span>
|
||||
<input type="text" class="form-control bg-dark text-white border-secondary" value="市场价" disabled>
|
||||
<span class="input-group-text bg-dark text-secondary border-secondary" style="width: 60px;">价格</span>
|
||||
<input type="text" class="form-control bg-dark text-warning border-secondary fw-bold" value="市场最优价" disabled>
|
||||
</div>
|
||||
|
||||
<div class="input-group input-group-sm mb-3">
|
||||
<span class="input-group-text bg-dark text-secondary border-secondary">数量</span>
|
||||
<input type="number" id="sell-amount" class="form-control bg-dark text-white border-secondary">
|
||||
<span class="input-group-text bg-dark text-secondary border-secondary"><?php echo $base_symbol; ?></span>
|
||||
<span class="input-group-text bg-dark text-secondary border-secondary" style="width: 60px;"><?php echo $trade_type=='CONTRACT'?'手数':'数量'; ?></span>
|
||||
<input type="number" id="sell-amount" class="form-control bg-dark text-white border-secondary" placeholder="0.00">
|
||||
<span class="input-group-text bg-dark text-secondary border-secondary"><?php echo $trade_type=='CONTRACT'?'张':$base_symbol; ?></span>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-danger w-100 fw-bold" onclick="submitOrder('SELL')">卖出 (做空)</button>
|
||||
<button class="btn btn-danger w-100 fw-bold py-2 shadow-sm" onclick="submitOrder('SELL')">立即卖出 (做空)</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -119,43 +140,60 @@ include 'header.php';
|
||||
<!-- Positions & History -->
|
||||
<div class="glass-card mt-1 p-0">
|
||||
<div class="d-flex border-bottom border-secondary bg-dark">
|
||||
<div class="trade-nav-item active">当前仓位</div>
|
||||
<div class="trade-nav-item">历史订单</div>
|
||||
<div class="trade-nav-item active">当前持有仓位</div>
|
||||
<div class="trade-nav-item">历史成交记录</div>
|
||||
</div>
|
||||
<div class="p-2" style="min-height: 200px;">
|
||||
<table class="table table-dark table-hover small" id="position-table">
|
||||
<thead>
|
||||
<tr class="text-secondary">
|
||||
<th>合约</th>
|
||||
<th>方向</th>
|
||||
<th>杠杆</th>
|
||||
<th>数量</th>
|
||||
<th>开仓价</th>
|
||||
<th>当前价</th>
|
||||
<th>未实现盈亏</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
<div class="p-0" style="min-height: 250px;">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-dark table-hover mb-0 align-middle" id="position-table" style="font-size: 13px;">
|
||||
<thead>
|
||||
<tr class="text-secondary" style="background: #1e2329;">
|
||||
<th class="ps-3">交易对</th>
|
||||
<th>方向</th>
|
||||
<th>杠杆</th>
|
||||
<th>持有数量</th>
|
||||
<th>开仓价格</th>
|
||||
<th>标记价格</th>
|
||||
<th>盈亏 (USDT)</th>
|
||||
<th class="text-end pe-3">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Order Book -->
|
||||
<div class="col-lg-3">
|
||||
<div class="glass-card h-100">
|
||||
<div class="p-2 border-bottom border-secondary small fw-bold">订单簿</div>
|
||||
<div id="order-book">
|
||||
<table class="w-100">
|
||||
<tbody id="asks-list"></tbody>
|
||||
</table>
|
||||
<div class="py-2 text-center border-top border-bottom border-secondary my-1">
|
||||
<span id="book-price" class="fs-5 fw-bold text-success">--</span>
|
||||
<div class="glass-card h-100" style="display: flex; flex-direction: column;">
|
||||
<div class="p-2 border-bottom border-secondary bg-dark small fw-bold">实时订单簿</div>
|
||||
<div id="order-book" style="flex-grow: 1;">
|
||||
<div class="px-2 py-2 d-flex justify-content-between text-secondary smaller">
|
||||
<span>价格 (USDT)</span>
|
||||
<span>数量 (<?php echo $base_symbol; ?>)</span>
|
||||
</div>
|
||||
<div id="asks-container" class="mb-1">
|
||||
<table class="w-100">
|
||||
<tbody id="asks-list"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="py-3 text-center border-top border-bottom border-secondary my-1 bg-dark">
|
||||
<span id="book-price" class="fs-4 fw-bold">--</span>
|
||||
<div class="smaller text-secondary" id="book-price-usd">≈ $--</div>
|
||||
</div>
|
||||
<div id="bids-container">
|
||||
<table class="w-100">
|
||||
<tbody id="bids-list"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-2 border-top border-secondary bg-dark">
|
||||
<div class="d-flex justify-content-between smaller">
|
||||
<span class="text-secondary">最新成交</span>
|
||||
<span class="text-success">实时</span>
|
||||
</div>
|
||||
<table class="w-100">
|
||||
<tbody id="bids-list"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -167,6 +205,7 @@ include 'header.php';
|
||||
const symbol = '<?php echo $symbol; ?>';
|
||||
const tradeType = '<?php echo $trade_type; ?>';
|
||||
let currentPrice = 0;
|
||||
let allCoins = [];
|
||||
|
||||
new TradingView.widget({
|
||||
"width": "100%", "height": "100%", "symbol": "BINANCE:" + symbol,
|
||||
@ -175,77 +214,120 @@ include 'header.php';
|
||||
"hide_side_toolbar": false, "allow_symbol_change": true, "container_id": "tradingview_widget"
|
||||
});
|
||||
|
||||
function formatPrice(p) {
|
||||
p = parseFloat(p);
|
||||
if (p < 0.0001) return p.toFixed(8);
|
||||
if (p < 0.01) return p.toFixed(6);
|
||||
if (p < 1) return p.toFixed(4);
|
||||
return p.toFixed(2);
|
||||
}
|
||||
|
||||
async function updateMarket() {
|
||||
const r = await fetch('api.php?action=market_data');
|
||||
const coins = await r.json();
|
||||
|
||||
// Update Side List
|
||||
try {
|
||||
const r = await fetch('api.php?action=market_data');
|
||||
const coins = await r.json();
|
||||
allCoins = coins;
|
||||
renderCoins();
|
||||
|
||||
const c = coins.find(i => i.symbol === symbol);
|
||||
if (c) {
|
||||
currentPrice = parseFloat(c.price);
|
||||
const pFormatted = formatPrice(currentPrice);
|
||||
const changeClass = c.change >= 0 ? 'price-up' : 'price-down';
|
||||
|
||||
document.getElementById('header-price').textContent = pFormatted;
|
||||
document.getElementById('header-price').className = 'fw-bold fs-5 ' + changeClass;
|
||||
document.getElementById('header-price-usd').textContent = pFormatted;
|
||||
|
||||
document.getElementById('header-change').textContent = (c.change >= 0 ? '+' : '') + c.change + '%';
|
||||
document.getElementById('header-change').className = 'fw-bold ' + changeClass;
|
||||
|
||||
document.getElementById('header-high').textContent = formatPrice(c.high || currentPrice * 1.02);
|
||||
document.getElementById('header-low').textContent = formatPrice(c.low || currentPrice * 0.98);
|
||||
|
||||
const bookPrice = document.getElementById('book-price');
|
||||
bookPrice.textContent = pFormatted;
|
||||
bookPrice.className = 'fs-4 fw-bold ' + changeClass;
|
||||
document.getElementById('book-price-usd').textContent = '≈ $' + pFormatted;
|
||||
|
||||
renderOrderBook(currentPrice);
|
||||
}
|
||||
} catch(e) { console.error(e); }
|
||||
}
|
||||
|
||||
function renderCoins() {
|
||||
const search = document.getElementById('coin-search').value.toLowerCase();
|
||||
let listHtml = '';
|
||||
coins.forEach(c => {
|
||||
allCoins.forEach(c => {
|
||||
if (search && !c.symbol.toLowerCase().includes(search)) return;
|
||||
const isTarget = c.symbol === symbol;
|
||||
const changeClass = c.change >= 0 ? 'text-success' : 'text-danger';
|
||||
listHtml += `
|
||||
<div class="coin-row p-2 d-flex justify-content-between align-items-center ${isTarget?'bg-dark':''}" onclick="location.href='?type=${tradeType}&symbol=${c.symbol}'">
|
||||
<div>
|
||||
<div class="fw-bold">${c.symbol.replace('USDT','')}</div>
|
||||
<div class="text-secondary smaller" style="font-size:10px">Vol --</div>
|
||||
<div class="coin-row p-2 d-flex justify-content-between align-items-center ${isTarget?'active':''}" onclick="location.href='?type=${tradeType}&symbol=${c.symbol}'">
|
||||
<div class="d-flex align-items-center">
|
||||
<img src="${c.icon_url}" width="20" height="20" class="me-2 rounded-circle">
|
||||
<div>
|
||||
<div class="fw-bold smaller text-white">${c.symbol.replace('USDT','')}</div>
|
||||
<div class="text-secondary smaller" style="font-size:9px">USDT</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-end">
|
||||
<div class="fw-bold ${changeClass}">${parseFloat(c.price).toFixed(c.price<1?4:2)}</div>
|
||||
<div class="${changeClass}" style="font-size:10px">${c.change}%</div>
|
||||
<div class="fw-bold smaller ${changeClass}">${formatPrice(c.price)}</div>
|
||||
<div class="${changeClass}" style="font-size:10px">${(c.change >= 0 ? '+' : '') + c.change}%</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
if (isTarget) {
|
||||
currentPrice = c.price;
|
||||
document.getElementById('header-price').textContent = parseFloat(c.price).toLocaleString(undefined, {minimumFractionDigits: 2});
|
||||
document.getElementById('header-price').className = 'fw-bold fs-5 ' + (c.change >= 0 ? 'text-success' : 'text-danger');
|
||||
document.getElementById('header-change').textContent = (c.change >= 0 ? '+' : '') + c.change + '%';
|
||||
document.getElementById('header-change').className = 'small ' + (c.change >= 0 ? 'text-success' : 'text-danger');
|
||||
document.getElementById('book-price').textContent = parseFloat(c.price).toFixed(2);
|
||||
}
|
||||
});
|
||||
document.getElementById('left-coin-list').innerHTML = listHtml;
|
||||
|
||||
// Mock Order Book
|
||||
renderOrderBook(currentPrice);
|
||||
}
|
||||
|
||||
function filterCoins() { renderCoins(); }
|
||||
|
||||
function renderOrderBook(price) {
|
||||
if (!price) return;
|
||||
let asks = '', bids = '';
|
||||
for(let i=5; i>0; i--) {
|
||||
asks += `<tr><td class="text-danger">${(price * (1 + i*0.0002)).toFixed(2)}</td><td class="text-end text-secondary">${(Math.random()*2).toFixed(3)}</td></tr>`;
|
||||
bids += `<tr><td class="text-success">${(price * (1 - i*0.0002)).toFixed(2)}</td><td class="text-end text-secondary">${(Math.random()*2).toFixed(3)}</td></tr>`;
|
||||
// Asks (Red) - from high to low
|
||||
for(let i=10; i>0; i--) {
|
||||
const p = price * (1 + i * 0.0001);
|
||||
const amt = (Math.random() * 2).toFixed(3);
|
||||
asks += `<tr><td class="text-danger">${formatPrice(p)}</td><td class="text-end text-secondary">${amt}</td></tr>`;
|
||||
}
|
||||
// Bids (Green) - from high to low
|
||||
for(let i=1; i<=10; i++) {
|
||||
const p = price * (1 - i * 0.0001);
|
||||
const amt = (Math.random() * 2).toFixed(3);
|
||||
bids += `<tr><td class="text-success">${formatPrice(p)}</td><td class="text-end text-secondary">${amt}</td></tr>`;
|
||||
}
|
||||
document.getElementById('asks-list').innerHTML = asks;
|
||||
document.getElementById('bids-list').innerHTML = bids;
|
||||
}
|
||||
|
||||
async function updatePositions() {
|
||||
if (tradeType !== 'CONTRACT') {
|
||||
document.getElementById('position-table').parentElement.innerHTML = '<div class="text-center text-secondary py-5">现货交易暂不显示当前持仓</div>';
|
||||
return;
|
||||
}
|
||||
const r = await fetch('api.php?action=positions');
|
||||
const pos = await r.json();
|
||||
let html = '';
|
||||
pos.forEach(p => {
|
||||
const pnlClass = p.pnl >= 0 ? 'text-success' : 'text-danger';
|
||||
html += `
|
||||
<tr>
|
||||
<td class="fw-bold">${p.symbol}</td>
|
||||
<td><span class="badge ${p.side==='LONG'?'bg-success':'bg-danger'}">${p.side}</span></td>
|
||||
<td>${p.leverage}x</td>
|
||||
<td>${p.lots}</td>
|
||||
<td>${p.entry_price}</td>
|
||||
<td>${p.current_price}</td>
|
||||
<td class="${pnlClass} fw-bold">${parseFloat(p.pnl).toFixed(2)} USDT</td>
|
||||
<td><button class="btn btn-sm btn-outline-warning py-0" onclick="closePosition(${p.id})">平仓</button></td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
document.querySelector('#position-table tbody').innerHTML = html;
|
||||
try {
|
||||
const r = await fetch('api.php?action=positions');
|
||||
const pos = await r.json();
|
||||
let html = '';
|
||||
if (pos.length === 0) {
|
||||
html = '<tr><td colspan="8" class="text-center py-5 text-secondary">暂无持有仓位</td></tr>';
|
||||
} else {
|
||||
pos.forEach(p => {
|
||||
const pnlClass = p.pnl >= 0 ? 'text-success' : 'text-danger';
|
||||
html += `
|
||||
<tr>
|
||||
<td class="ps-3 fw-bold">${p.symbol}</td>
|
||||
<td><span class="badge ${p.side==='LONG'?'bg-success':'bg-danger'}">${p.side}</span></td>
|
||||
<td><span class="text-warning">${p.leverage}x</span></td>
|
||||
<td>${p.lots} 张</td>
|
||||
<td>${formatPrice(p.entry_price)}</td>
|
||||
<td class="text-warning">${formatPrice(p.current_price)}</td>
|
||||
<td class="${pnlClass} fw-bold">${parseFloat(p.pnl).toFixed(2)} USDT</td>
|
||||
<td class="text-end pe-3"><button class="btn btn-sm btn-outline-danger py-0" onclick="closePosition(${p.id})">平仓</button></td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
}
|
||||
document.querySelector('#position-table tbody').innerHTML = html;
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
async function closePosition(id) {
|
||||
@ -265,7 +347,7 @@ include 'header.php';
|
||||
const leverageSelect = document.getElementById('leverage');
|
||||
const leverage = leverageSelect ? leverageSelect.value : 1;
|
||||
|
||||
if (!amount) { alert('请输入数量'); return; }
|
||||
if (!amount || amount <= 0) { alert('请输入有效数量'); return; }
|
||||
|
||||
const res = await fetch('api.php?action=submit_order', {
|
||||
method: 'POST',
|
||||
@ -286,4 +368,4 @@ include 'header.php';
|
||||
updateMarket();
|
||||
updatePositions();
|
||||
</script>
|
||||
<?php include 'footer.php'; ?>
|
||||
<?php include 'footer.php'; ?>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user