38239-vm/trade.php
Flatlogic Bot f1fc7be962 BIT
2026-02-07 06:05:18 +00:00

289 lines
14 KiB
PHP

<?php
include_once 'config.php';
check_auth();
$user_id = $_SESSION['user_id'];
$account = get_account($user_id);
$symbol = $_GET['symbol'] ?? 'BTCUSDT';
$trade_type = $_GET['type'] ?? 'SPOT';
$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; }
</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>
<div id="left-coin-list" style="max-height: 800px; overflow-y: auto;">
<!-- JS populated -->
</div>
</div>
</div>
<!-- Chart & Trade -->
<div class="col-lg-7">
<!-- Ticker Header -->
<div class="glass-card mb-1 p-2 d-flex align-items-center">
<div class="d-flex align-items-center me-4">
<span class="fw-bold fs-5 text-white"><?php echo $symbol; ?></span>
</div>
<div class="me-4">
<div class="fw-bold fs-5" id="header-price">--</div>
<div class="small" 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>
</div>
<!-- TradingView -->
<div class="glass-card mb-1" style="height: 450px;">
<div id="tradingview_widget" style="height: 100%;"></div>
</div>
<!-- Trading Form -->
<div class="glass-card p-3">
<div class="row">
<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>
<?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">
<option value="10">10x</option>
<option value="20" selected>20x</option>
<option value="50">50x</option>
<option value="100">100x</option>
</select>
</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>
</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>
</div>
<button class="btn btn-success w-100 fw-bold" 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>
<?php if ($trade_type === 'CONTRACT'): ?>
<div class="mb-3"><label class="small">&nbsp;</label><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>
</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>
</div>
<button class="btn btn-danger w-100 fw-bold" onclick="submitOrder('SELL')">卖出 (做空)</button>
</div>
</div>
</div>
<!-- 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>
<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>
</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>
<table class="w-100">
<tbody id="bids-list"></tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript" src="https://s3.tradingview.com/tv.js"></script>
<script>
const symbol = '<?php echo $symbol; ?>';
const tradeType = '<?php echo $trade_type; ?>';
let currentPrice = 0;
new TradingView.widget({
"width": "100%", "height": "100%", "symbol": "BINANCE:" + symbol,
"interval": "15", "timezone": "Etc/UTC", "theme": "dark", "style": "1",
"locale": "zh_CN", "toolbar_bg": "#f1f3f6", "enable_publishing": false,
"hide_side_toolbar": false, "allow_symbol_change": true, "container_id": "tradingview_widget"
});
async function updateMarket() {
const r = await fetch('api.php?action=market_data');
const coins = await r.json();
// Update Side List
let listHtml = '';
coins.forEach(c => {
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>
<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>
</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 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>`;
}
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;
}
async function closePosition(id) {
if (!confirm('确定要平掉该仓位吗?')) return;
const res = await fetch('api.php?action=close_position', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id })
});
const json = await res.json();
alert(json.message);
updatePositions();
}
async function submitOrder(side) {
const amount = document.getElementById(side.toLowerCase() + '-amount').value;
const leverageSelect = document.getElementById('leverage');
const leverage = leverageSelect ? leverageSelect.value : 1;
if (!amount) { alert('请输入数量'); return; }
const res = await fetch('api.php?action=submit_order', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ symbol, side, trade_type: tradeType, amount, leverage })
});
const json = await res.json();
if (json.status === 'success') {
alert('下单成功');
location.reload();
} else {
alert('错误: ' + json.message);
}
}
setInterval(updateMarket, 2000);
setInterval(updatePositions, 3000);
updateMarket();
updatePositions();
</script>
<?php include 'footer.php'; ?>