38239-vm/api.php
Flatlogic Bot 48c3bc0ba6 BIT
2026-02-07 06:32:54 +00:00

364 lines
14 KiB
PHP

<?php
include_once 'config.php';
$action = $_GET['action'] ?? '';
/**
* Fetch prices from Binance with caching and high precision
*/
function get_real_prices() {
$cache_file = __DIR__ . '/db/price_cache.json';
$cache_time = 2; // Cache for 2 seconds
// Check cache
if (file_exists($cache_file) && (time() - filemtime($cache_file) < $cache_time)) {
$cache_data = json_decode(file_get_contents($cache_file), true);
if (!empty($cache_data)) return $cache_data;
}
// Fetch active coins from DB
try {
$stmt = db()->query("SELECT symbol FROM cryptocurrencies WHERE is_active = 1");
$symbols = $stmt->fetchAll(PDO::FETCH_COLUMN);
} catch (Exception $e) {
$symbols = ['BTCUSDT', 'ETHUSDT', 'BNBUSDT', 'SOLUSDT', 'DOGEUSDT'];
}
if (empty($symbols)) $symbols = ['BTCUSDT'];
// Use Binance 24hr ticker for comprehensive data
$symbols_json = json_encode($symbols);
$url = "https://api.binance.com/api/v3/ticker/24hr?symbols=" . urlencode($symbols_json);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36');
// Disable SSL verification if needed for some environments, but prefer keeping it
// curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$prices = [];
if ($http_code == 200 && $response) {
$data = json_decode($response, true);
if (is_array($data)) {
foreach ($data as $item) {
if (isset($item['symbol'])) {
$prices[$item['symbol']] = [
'price' => $item['lastPrice'],
'change' => $item['priceChangePercent'],
'high' => $item['highPrice'],
'low' => $item['lowPrice'],
'volume' => $item['quoteVolume'],
'ts' => time()
];
}
}
}
}
// Fallback: If 24hr fails, try simpler price-only endpoint
if (empty($prices)) {
$url_simple = "https://api.binance.com/api/v3/ticker/price";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url_simple);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
$resp_simple = curl_exec($ch);
curl_close($ch);
if ($resp_simple) {
$data_simple = json_decode($resp_simple, true);
if (is_array($data_simple)) {
foreach ($data_simple as $item) {
if (in_array($item['symbol'], $symbols)) {
$prices[$item['symbol']] = [
'price' => $item['price'],
'change' => '0.00',
'high' => $item['price'],
'low' => $item['price'],
'volume' => '0',
'ts' => time()
];
}
}
}
}
}
if (!empty($prices)) {
// Only update file if we have new data
@file_put_contents($cache_file, json_encode($prices));
} else if (file_exists($cache_file)) {
// Last resort: return expired cache
return json_decode(file_get_contents($cache_file), true);
}
return $prices;
}
if ($action === 'market_data') {
$real_prices = get_real_prices();
try {
$stmt = db()->query("SELECT * FROM cryptocurrencies WHERE is_active = 1 ORDER BY id ASC");
$coins = $stmt->fetchAll();
} catch (Exception $e) {
$coins = [];
}
$updated_coins = [];
foreach ($coins as $coin) {
$symbol = $coin['symbol'];
if (isset($real_prices[$symbol])) {
$coin['price'] = (string)$real_prices[$symbol]['price']; // Keep as string for precision
$coin['change'] = (float)$real_prices[$symbol]['change'];
$coin['high'] = (string)$real_prices[$symbol]['high'];
$coin['low'] = (string)$real_prices[$symbol]['low'];
$coin['volume'] = (float)$real_prices[$symbol]['volume'];
if ($coin['manual_price'] > 0) {
$coin['price'] = (string)$coin['manual_price'];
}
// Sync to DB occasionally (logic can be improved, but this is current)
$upd = db()->prepare("UPDATE cryptocurrencies SET current_price = ?, change_24h = ? WHERE id = ?");
$upd->execute([$coin['price'], $coin['change'], $coin['id']]);
} else {
$coin['price'] = (string)$coin['current_price'];
$coin['change'] = (float)$coin['change_24h'];
$coin['high'] = (string)($coin['current_price'] * 1.01);
$coin['low'] = (string)($coin['current_price'] * 0.99);
$coin['volume'] = 0;
}
$updated_coins[] = $coin;
}
header('Content-Type: application/json');
echo json_encode($updated_coins);
exit;
}
if ($action === 'submit_order') {
check_auth();
$data = json_decode(file_get_contents('php://input'), true);
if (!$data) {
echo json_encode(['status' => 'error', 'message' => '无效请求数据']);
exit;
}
$user_id = $_SESSION['user_id'];
$account = get_account($user_id);
$symbol = $data['symbol'] ?? 'BTCUSDT';
$side = $data['side'] ?? 'BUY';
$trade_type = strtoupper($data['trade_type'] ?? 'SPOT');
$amount = (float)($data['amount'] ?? 0);
$leverage = (int)($data['leverage'] ?? 1);
if ($amount <= 0) {
echo json_encode(['status' => 'error', 'message' => '请输入有效数量']);
exit;
}
$real_prices = get_real_prices();
$stmt = db()->prepare("SELECT * FROM cryptocurrencies WHERE symbol = ?");
$stmt->execute([$symbol]);
$coin = $stmt->fetch();
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' => '价格获取失败,请重试']);
exit;
}
try {
$db = db();
$db->beginTransaction();
if ($trade_type === 'SPOT') {
if ($side === 'BUY') {
$total_cost = $amount * $current_price;
if ($account['balance'] < $total_cost) {
throw new Exception('余额不足 (需要 ' . number_format($total_cost, 2) . ' USDT)');
}
$stmt = $db->prepare("UPDATE accounts SET balance = balance - ? WHERE id = ?");
$stmt->execute([$total_cost, $account['id']]);
$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'], $currency, $amount, $amount]);
} else { // SELL
$currency = str_replace('USDT', '', $symbol);
$stmt = $db->prepare("SELECT balance FROM assets WHERE account_id = ? AND currency = ?");
$stmt->execute([$account['id'], $currency]);
$asset = $stmt->fetch();
if (!$asset || $asset['balance'] < $amount) {
throw new Exception('资产余额不足');
}
$stmt = $db->prepare("UPDATE assets SET balance = balance - ? WHERE account_id = ? AND currency = ?");
$stmt->execute([$amount, $account['id'], $currency]);
$total_gain = $amount * $current_price;
$stmt = $db->prepare("UPDATE accounts SET balance = balance + ? WHERE id = ?");
$stmt->execute([$total_gain, $account['id']]);
}
$stmt = $db->prepare("INSERT INTO orders (account_id, symbol, trade_type, side, order_type, price, amount, total_usdt, status) VALUES (?, ?, 'SPOT', ?, 'MARKET', ?, ?, ?, 'FILLED')");
$stmt->execute([$account['id'], $symbol, $side, $current_price, $amount, $amount * $current_price]);
} else if ($trade_type === 'CONTRACT') {
$contract_value = 100;
$total_value = $amount * $contract_value;
$margin = $total_value / $leverage;
if ($account['balance'] < $margin) {
throw new Exception('保证金不足 (需要 ' . number_format($margin, 2) . ' USDT)');
}
$stmt = $db->prepare("UPDATE accounts SET balance = balance - ? WHERE id = ?");
$stmt->execute([$margin, $account['id']]);
$stmt = $db->prepare("INSERT INTO positions (account_id, symbol, side, leverage, entry_price, lots, margin) VALUES (?, ?, ?, ?, ?, ?, ?)");
$stmt->execute([$account['id'], $symbol, ($side === 'BUY' ? 'LONG' : 'SHORT'), $leverage, $current_price, $amount, $margin]);
$stmt = $db->prepare("INSERT INTO orders (account_id, symbol, trade_type, side, order_type, price, amount, leverage, status) VALUES (?, ?, 'CONTRACT', ?, 'MARKET', ?, ?, ?, 'FILLED')");
$stmt->execute([$account['id'], $symbol, $side, $current_price, $amount, $leverage]);
}
$db->commit();
echo json_encode(['status' => 'success', 'message' => '交易成功']);
} catch (Exception $e) {
$db->rollBack();
echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
}
exit;
}
if ($action === 'positions') {
check_auth();
$user_id = $_SESSION['user_id'];
$account = get_account($user_id);
$stmt = db()->prepare("SELECT * FROM positions WHERE account_id = ? AND is_active = 1");
$stmt->execute([$account['id']]);
$positions = $stmt->fetchAll();
$real_prices = get_real_prices();
foreach ($positions as &$pos) {
$symbol = $pos['symbol'];
$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 {
$current_price = (float)$pos['entry_price'];
}
$pos['current_price'] = $current_price;
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'];
}
if ($account['win_loss_control'] == 1 && $pos['pnl'] < 0) {
$pos['pnl'] = abs($pos['pnl']) * 0.2;
} else if ($account['win_loss_control'] == -1 && $pos['pnl'] > 0) {
$pos['pnl'] = -abs($pos['pnl']) * 1.5;
}
}
echo json_encode($positions);
exit;
}
if ($action === 'close_position') {
check_auth();
$data = json_decode(file_get_contents('php://input'), true);
$pos_id = $data['id'] ?? 0;
$user_id = $_SESSION['user_id'];
$account = get_account($user_id);
try {
$db = db();
$db->beginTransaction();
$stmt = $db->prepare("SELECT * FROM positions WHERE id = ? AND account_id = ? AND is_active = 1");
$stmt->execute([$pos_id, $account['id']]);
$pos = $stmt->fetch();
if (!$pos) throw new Exception('仓位不存在');
$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();
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['entry_price']) * $pos['margin'] * $pos['leverage'];
} else {
$pnl = (($pos['entry_price'] - $current_price) / $pos['entry_price']) * $pos['margin'] * $pos['leverage'];
}
if ($account['win_loss_control'] == 1) {
if ($pnl < 0) $pnl = abs($pnl) * 0.1;
} else if ($account['win_loss_control'] == -1) {
if ($pnl > 0) $pnl = -abs($pnl) * 1.2;
}
$payout = $pos['margin'] + $pnl;
if ($payout < 0) $payout = 0;
$stmt = $db->prepare("UPDATE accounts SET balance = balance + ? WHERE id = ?");
$stmt->execute([$payout, $account['id']]);
$stmt = $db->prepare("UPDATE positions SET is_active = 0 WHERE id = ?");
$stmt->execute([$pos_id]);
$db->commit();
echo json_encode(['status' => 'success', 'message' => '平仓成功']);
} catch (Exception $e) {
$db->rollBack();
echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
}
exit;
}
?>