|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>CYBERGRID - Rotten Market Dominator</title> |
|
<script src="https://cdn.tailwindcss.com"></script> |
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> |
|
<script src="https://cdn.jsdelivr.net/npm/ccxt"></script> |
|
<style> |
|
@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&family=Share+Tech+Mono&display=swap'); |
|
|
|
:root { |
|
--rotten-orange: #ff6d00; |
|
--cyber-purple: #7b2cbf; |
|
--neon-blue: #00f5d4; |
|
--dark-bg: #0a0a0a; |
|
} |
|
|
|
body { |
|
font-family: 'Share Tech Mono', monospace; |
|
background-color: var(--dark-bg); |
|
color: white; |
|
background-image: |
|
radial-gradient(circle at 10% 20%, rgba(255, 109, 0, 0.05) 0%, transparent 20%), |
|
radial-gradient(circle at 90% 80%, rgba(123, 44, 191, 0.05) 0%, transparent 20%), |
|
linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.8)); |
|
overflow-x: hidden; |
|
} |
|
|
|
.cyber-font { |
|
font-family: 'Orbitron', sans-serif; |
|
} |
|
|
|
.rotten-texture { |
|
position: relative; |
|
} |
|
|
|
.rotten-texture::after { |
|
content: ""; |
|
position: absolute; |
|
top: 0; |
|
left: 0; |
|
right: 0; |
|
bottom: 0; |
|
background: |
|
linear-gradient(45deg, |
|
transparent 48%, |
|
rgba(255, 109, 0, 0.1) 48%, |
|
rgba(255, 109, 0, 0.1) 52%, |
|
transparent 52%), |
|
linear-gradient(-45deg, |
|
transparent 48%, |
|
rgba(255, 109, 0, 0.1) 48%, |
|
rgba(255, 109, 0, 0.1) 52%, |
|
transparent 52%); |
|
background-size: 10px 10px; |
|
pointer-events: none; |
|
} |
|
|
|
.glitch-effect { |
|
text-shadow: |
|
0.05em 0 0 rgba(255, 0, 0, 0.7), |
|
-0.05em -0.025em 0 rgba(0, 255, 0, 0.7), |
|
-0.025em 0.05em 0 rgba(0, 0, 255, 0.7); |
|
animation: glitch 500ms infinite; |
|
} |
|
|
|
@keyframes glitch { |
|
0% { text-shadow: 0.05em 0 0 rgba(255, 0, 0, 0.7), -0.05em -0.025em 0 rgba(0, 255, 0, 0.7), -0.025em 0.05em 0 rgba(0, 0, 255, 0.7); } |
|
14% { text-shadow: 0.05em 0 0 rgba(255, 0, 0, 0.7), -0.05em -0.025em 0 rgba(0, 255, 0, 0.7), -0.025em 0.05em 0 rgba(0, 0, 255, 0.7); } |
|
15% { text-shadow: -0.05em -0.025em 0 rgba(255, 0, 0, 0.7), 0.025em 0.025em 0 rgba(0, 255, 0, 0.7), -0.05em -0.05em 0 rgba(0, 0, 255, 0.7); } |
|
49% { text-shadow: -0.05em -0.025em 0 rgba(255, 0, 0, 0.7), 0.025em 0.025em 0 rgba(0, 255, 0, 0.7), -0.05em -0.05em 0 rgba(0, 0, 255, 0.7); } |
|
50% { text-shadow: 0.025em 0.05em 0 rgba(255, 0, 0, 0.7), 0.05em 0 0 rgba(0, 255, 0, 0.7), 0 -0.05em 0 rgba(0, 0, 255, 0.7); } |
|
99% { text-shadow: 0.025em 0.05em 0 rgba(255, 0, 0, 0.7), 0.05em 0 0 rgba(0, 255, 0, 0.7), 0 -0.05em 0 rgba(0, 0, 255, 0.7); } |
|
100% { text-shadow: -0.025em 0 0 rgba(255, 0, 0, 0.7), -0.025em -0.025em 0 rgba(0, 255, 0, 0.7), -0.025em -0.05em 0 rgba(0, 0, 255, 0.7); } |
|
} |
|
|
|
.neon-pulse { |
|
animation: neon-pulse 2s infinite alternate; |
|
} |
|
|
|
@keyframes neon-pulse { |
|
from { box-shadow: 0 0 5px rgba(0, 245, 212, 0.3), 0 0 10px rgba(0, 245, 212, 0.2); } |
|
to { box-shadow: 0 0 15px rgba(0, 245, 212, 0.6), 0 0 30px rgba(0, 245, 212, 0.4); } |
|
} |
|
|
|
.terminal-scroll::-webkit-scrollbar { |
|
width: 8px; |
|
height: 8px; |
|
} |
|
|
|
.terminal-scroll::-webkit-scrollbar-track { |
|
background: rgba(0, 0, 0, 0.2); |
|
} |
|
|
|
.terminal-scroll::-webkit-scrollbar-thumb { |
|
background: var(--rotten-orange); |
|
border-radius: 4px; |
|
} |
|
|
|
.terminal-scroll::-webkit-scrollbar-thumb:hover { |
|
background: var(--cyber-purple); |
|
} |
|
|
|
.grid-cell { |
|
transition: all 0.3s ease; |
|
} |
|
|
|
.grid-cell:hover { |
|
transform: scale(1.05); |
|
box-shadow: 0 0 15px rgba(123, 44, 191, 0.5); |
|
} |
|
|
|
.search-dropdown { |
|
max-height: 300px; |
|
overflow-y: auto; |
|
scrollbar-width: thin; |
|
} |
|
|
|
.search-dropdown::-webkit-scrollbar { |
|
width: 6px; |
|
} |
|
|
|
.search-dropdown::-webkit-scrollbar-thumb { |
|
background-color: var(--rotten-orange); |
|
border-radius: 3px; |
|
} |
|
</style> |
|
</head> |
|
<body class="min-h-screen"> |
|
<div class="rotten-texture"> |
|
|
|
<header class="bg-black bg-opacity-70 border-b border-purple-900 py-4 px-6 flex justify-between items-center sticky top-0 z-50 backdrop-blur-sm"> |
|
<div class="flex items-center space-x-4"> |
|
<div class="w-10 h-10 bg-gradient-to-br from-orange-600 to-purple-800 rounded-full flex items-center justify-center neon-pulse"> |
|
<span class="cyber-font text-xl">⚡</span> |
|
</div> |
|
<h1 class="cyber-font text-2xl md:text-3xl bg-clip-text text-transparent bg-gradient-to-r from-orange-500 via-purple-500 to-blue-400"> |
|
CYBER<span class="glitch-effect">GRID</span> |
|
</h1> |
|
</div> |
|
<div class="flex items-center space-x-4"> |
|
<div class="hidden md:block px-4 py-2 bg-gray-900 rounded-lg text-sm"> |
|
<span class="text-gray-400">STATUS:</span> |
|
<span id="connection-status" class="ml-2 text-green-400">CONNECTED</span> |
|
</div> |
|
<div class="px-4 py-2 bg-gray-900 rounded-lg text-sm"> |
|
<span class="text-gray-400">TIME:</span> |
|
<span id="current-time" class="ml-2">00:00:00</span> |
|
</div> |
|
</div> |
|
</header> |
|
|
|
|
|
<main class="container mx-auto px-4 py-6"> |
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6"> |
|
|
|
<div class="lg:col-span-2 space-y-6"> |
|
|
|
<div class="bg-gray-900 bg-opacity-70 rounded-xl border border-purple-900 p-4"> |
|
<div class="flex flex-col md:flex-row md:items-center md:justify-between space-y-4 md:space-y-0"> |
|
<h2 class="cyber-font text-xl text-orange-400">MARKET DOMINATOR</h2> |
|
<div class="relative w-full md:w-64"> |
|
<input type="text" id="pair-search" placeholder="Search trading pair..." |
|
class="w-full bg-gray-800 border border-purple-700 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-purple-500"> |
|
<div id="search-results" class="hidden absolute z-10 mt-1 w-full bg-gray-900 border border-purple-700 rounded-lg shadow-lg search-dropdown"></div> |
|
</div> |
|
</div> |
|
|
|
<div class="mt-6 grid grid-cols-1 md:grid-cols-3 gap-4"> |
|
<div class="bg-gray-800 bg-opacity-50 rounded-lg p-4 border border-orange-900 grid-cell"> |
|
<div class="text-gray-400 text-sm">SELECTED PAIR</div> |
|
<div id="selected-pair" class="cyber-font text-xl text-purple-300 mt-1">-/-</div> |
|
</div> |
|
<div class="bg-gray-800 bg-opacity-50 rounded-lg p-4 border border-purple-900 grid-cell"> |
|
<div class="text-gray-400 text-sm">CURRENT PRICE</div> |
|
<div id="current-price" class="cyber-font text-xl text-orange-400 mt-1">$0.00</div> |
|
</div> |
|
<div class="bg-gray-800 bg-opacity-50 rounded-lg p-4 border border-blue-900 grid-cell"> |
|
<div class="text-gray-400 text-sm">24H VOLUME</div> |
|
<div id="daily-volume" class="cyber-font text-xl text-blue-400 mt-1">$0.00</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="bg-gray-900 bg-opacity-70 rounded-xl border border-purple-900 p-4"> |
|
<div class="flex justify-between items-center mb-4"> |
|
<h2 class="cyber-font text-xl text-orange-400">PRICE CHART</h2> |
|
<div class="flex space-x-2"> |
|
<button class="px-3 py-1 bg-gray-800 rounded-lg text-xs border border-purple-700 hover:bg-purple-900">1H</button> |
|
<button class="px-3 py-1 bg-gray-800 rounded-lg text-xs border border-purple-700 hover:bg-purple-900">4H</button> |
|
<button class="px-3 py-1 bg-purple-900 rounded-lg text-xs border border-purple-700">1D</button> |
|
<button class="px-3 py-1 bg-gray-800 rounded-lg text-xs border border-purple-700 hover:bg-purple-900">1W</button> |
|
</div> |
|
</div> |
|
<div class="h-64 md:h-80"> |
|
<canvas id="price-chart"></canvas> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="bg-gray-900 bg-opacity-70 rounded-xl border border-purple-900 p-4"> |
|
<div class="flex justify-between items-center mb-4"> |
|
<h2 class="cyber-font text-xl text-orange-400">GRID ORDERS</h2> |
|
<div class="flex items-center space-x-2"> |
|
<span class="text-gray-400 text-sm">GRID SPACING:</span> |
|
<input type="number" id="grid-spacing" value="0.02" step="0.01" min="0.01" |
|
class="w-20 bg-gray-800 border border-purple-700 rounded-lg px-2 py-1 text-sm focus:outline-none focus:ring-1 focus:ring-purple-500"> |
|
</div> |
|
</div> |
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4"> |
|
<div> |
|
<h3 class="text-purple-400 mb-2">BUY ORDERS</h3> |
|
<div id="buy-orders" class="space-y-2 max-h-60 overflow-y-auto terminal-scroll"></div> |
|
</div> |
|
<div> |
|
<h3 class="text-orange-400 mb-2">SELL ORDERS</h3> |
|
<div id="sell-orders" class="space-y-2 max-h-60 overflow-y-auto terminal-scroll"></div> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="space-y-6"> |
|
|
|
<div class="bg-gray-900 bg-opacity-70 rounded-xl border border-purple-900 p-4"> |
|
<h2 class="cyber-font text-xl text-orange-400 mb-4">BOT CONTROLS</h2> |
|
|
|
<div class="space-y-4"> |
|
<div> |
|
<label class="block text-gray-400 text-sm mb-1">ORDER SIZE (USDT)</label> |
|
<input type="number" id="order-size" value="3" min="1" step="1" |
|
class="w-full bg-gray-800 border border-purple-700 rounded-lg px-3 py-2 focus:outline-none focus:ring-1 focus:ring-purple-500"> |
|
</div> |
|
|
|
<div> |
|
<label class="block text-gray-400 text-sm mb-1">TOTAL DEPOSIT (USDT)</label> |
|
<input type="number" id="total-deposit" value="60" min="10" step="10" |
|
class="w-full bg-gray-800 border border-purple-700 rounded-lg px-3 py-2 focus:outline-none focus:ring-1 focus:ring-purple-500"> |
|
</div> |
|
|
|
<div> |
|
<label class="block text-gray-400 text-sm mb-1">MAX ORDERS</label> |
|
<input type="number" id="max-orders" value="33" min="5" max="50" step="1" |
|
class="w-full bg-gray-800 border border-purple-700 rounded-lg px-3 py-2 focus:outline-none focus:ring-1 focus:ring-purple-500"> |
|
</div> |
|
|
|
<div class="pt-2"> |
|
<button id="start-bot" class="w-full bg-gradient-to-r from-orange-600 to-purple-700 hover:from-orange-700 hover:to-purple-800 text-white py-2 px-4 rounded-lg cyber-font transition-all duration-300"> |
|
ACTIVATE GRID |
|
</button> |
|
</div> |
|
|
|
<div class="pt-2"> |
|
<button id="stop-bot" class="w-full bg-gray-800 hover:bg-gray-700 text-white py-2 px-4 rounded-lg cyber-font border border-red-900 transition-all duration-300"> |
|
EMERGENCY STOP |
|
</button> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="bg-gray-900 bg-opacity-70 rounded-xl border border-purple-900 p-4"> |
|
<h2 class="cyber-font text-xl text-orange-400 mb-4">ACCOUNT STATUS</h2> |
|
|
|
<div class="space-y-3"> |
|
<div class="flex justify-between"> |
|
<span class="text-gray-400">USDT Balance:</span> |
|
<span id="usdt-balance" class="text-green-400">0.00</span> |
|
</div> |
|
<div class="flex justify-between"> |
|
<span class="text-gray-400">Base Asset:</span> |
|
<span id="base-balance" class="text-blue-400">0.00</span> |
|
</div> |
|
<div class="flex justify-between"> |
|
<span class="text-gray-400">Active Orders:</span> |
|
<span id="active-orders" class="text-purple-400">0</span> |
|
</div> |
|
<div class="flex justify-between"> |
|
<span class="text-gray-400">Total Profit:</span> |
|
<span id="total-profit" class="text-orange-400">0.00</span> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="bg-gray-900 bg-opacity-70 rounded-xl border border-purple-900 p-4"> |
|
<div class="flex justify-between items-center mb-3"> |
|
<h2 class="cyber-font text-xl text-orange-400">SYSTEM LOG</h2> |
|
<button id="clear-log" class="text-xs bg-gray-800 hover:bg-gray-700 px-2 py-1 rounded border border-purple-700"> |
|
CLEAR |
|
</button> |
|
</div> |
|
<div id="log-terminal" class="bg-black bg-opacity-80 rounded-lg p-3 h-48 overflow-y-auto terminal-scroll text-xs font-mono space-y-1"></div> |
|
</div> |
|
</div> |
|
</div> |
|
</main> |
|
</div> |
|
|
|
<script> |
|
|
|
let exchange; |
|
let selectedPair = ''; |
|
let botRunning = false; |
|
let priceUpdateInterval; |
|
let gridUpdateInterval; |
|
let chart; |
|
let allMarkets = []; |
|
|
|
|
|
const pairSearch = document.getElementById('pair-search'); |
|
const searchResults = document.getElementById('search-results'); |
|
const selectedPairElement = document.getElementById('selected-pair'); |
|
const currentPriceElement = document.getElementById('current-price'); |
|
const dailyVolumeElement = document.getElementById('daily-volume'); |
|
const buyOrdersElement = document.getElementById('buy-orders'); |
|
const sellOrdersElement = document.getElementById('sell-orders'); |
|
const logTerminal = document.getElementById('log-terminal'); |
|
const startBotButton = document.getElementById('start-bot'); |
|
const stopBotButton = document.getElementById('stop-bot'); |
|
const connectionStatus = document.getElementById('connection-status'); |
|
const currentTimeElement = document.getElementById('current-time'); |
|
const usdtBalanceElement = document.getElementById('usdt-balance'); |
|
const baseBalanceElement = document.getElementById('base-balance'); |
|
const activeOrdersElement = document.getElementById('active-orders'); |
|
const totalProfitElement = document.getElementById('total-profit'); |
|
|
|
|
|
const API_KEY = '4efbe203fbac0e4bcd0003a0910c801b'; |
|
const API_SECRET = '8b0e9cf47fdd97f2a42bca571a74105c53a5f906cd4ada125938d05115d063a0'; |
|
|
|
|
|
async function initExchange() { |
|
try { |
|
exchange = new ccxt.gateio({ |
|
'apiKey': API_KEY, |
|
'secret': API_SECRET, |
|
'enableRateLimit': true, |
|
'options': {'defaultType': 'futures'} |
|
}); |
|
|
|
await exchange.loadMarkets(); |
|
allMarkets = Object.keys(exchange.markets); |
|
logMessage('Exchange connected successfully', 'success'); |
|
connectionStatus.textContent = 'CONNECTED'; |
|
connectionStatus.className = 'ml-2 text-green-400'; |
|
|
|
|
|
loadPopularPairs(); |
|
} catch (error) { |
|
logMessage(`Connection error: ${error.message}`, 'error'); |
|
connectionStatus.textContent = 'DISCONNECTED'; |
|
connectionStatus.className = 'ml-2 text-red-400'; |
|
} |
|
} |
|
|
|
|
|
function loadPopularPairs() { |
|
const popularPairs = [ |
|
'BTC/USDT', 'ETH/USDT', 'SOL/USDT', |
|
'ADA/USDT', 'DOT/USDT', 'AVAX/USDT', |
|
'MATIC/USDT', 'LINK/USDT', 'UNI/USDT' |
|
]; |
|
|
|
const availablePairs = popularPairs.filter(pair => allMarkets.includes(pair)); |
|
|
|
if (availablePairs.length > 0) { |
|
selectPair(availablePairs[0]); |
|
} |
|
} |
|
|
|
|
|
pairSearch.addEventListener('input', () => { |
|
const searchTerm = pairSearch.value.toUpperCase(); |
|
|
|
if (searchTerm.length < 2) { |
|
searchResults.classList.add('hidden'); |
|
return; |
|
} |
|
|
|
const filteredPairs = allMarkets.filter(pair => |
|
pair.includes(searchTerm) || |
|
pair.replace('/', '').includes(searchTerm) |
|
).slice(0, 20); |
|
|
|
displaySearchResults(filteredPairs); |
|
}); |
|
|
|
|
|
function displaySearchResults(pairs) { |
|
searchResults.innerHTML = ''; |
|
|
|
if (pairs.length === 0) { |
|
const noResult = document.createElement('div'); |
|
noResult.className = 'px-4 py-2 text-gray-400'; |
|
noResult.textContent = 'No results found'; |
|
searchResults.appendChild(noResult); |
|
} else { |
|
pairs.forEach(pair => { |
|
const resultItem = document.createElement('div'); |
|
resultItem.className = 'px-4 py-2 hover:bg-purple-900 cursor-pointer flex justify-between'; |
|
resultItem.innerHTML = ` |
|
<span>${pair}</span> |
|
<span class="text-gray-400 text-xs">${exchange.markets[pair].type}</span> |
|
`; |
|
|
|
resultItem.addEventListener('click', () => { |
|
selectPair(pair); |
|
pairSearch.value = ''; |
|
searchResults.classList.add('hidden'); |
|
}); |
|
|
|
searchResults.appendChild(resultItem); |
|
}); |
|
} |
|
|
|
searchResults.classList.remove('hidden'); |
|
} |
|
|
|
|
|
async function selectPair(pair) { |
|
try { |
|
selectedPair = pair; |
|
selectedPairElement.textContent = pair; |
|
|
|
logMessage(`Selected pair: ${pair}`, 'info'); |
|
|
|
|
|
await updatePriceData(); |
|
await updateAccountBalances(); |
|
|
|
|
|
initChart(); |
|
|
|
|
|
if (priceUpdateInterval) clearInterval(priceUpdateInterval); |
|
priceUpdateInterval = setInterval(updatePriceData, 5000); |
|
|
|
} catch (error) { |
|
logMessage(`Error selecting pair: ${error.message}`, 'error'); |
|
} |
|
} |
|
|
|
|
|
async function updatePriceData() { |
|
if (!selectedPair) return; |
|
|
|
try { |
|
const ticker = await exchange.fetchTicker(selectedPair); |
|
const price = ticker.last; |
|
const volume = ticker.quoteVolume; |
|
|
|
currentPriceElement.textContent = `$${price.toFixed(6)}`; |
|
dailyVolumeElement.textContent = `$${volume.toFixed(2)}`; |
|
|
|
|
|
updateChart(price); |
|
|
|
} catch (error) { |
|
logMessage(`Price update error: ${error.message}`, 'error'); |
|
} |
|
} |
|
|
|
|
|
function initChart() { |
|
const ctx = document.getElementById('price-chart').getContext('2d'); |
|
|
|
chart = new Chart(ctx, { |
|
type: 'line', |
|
data: { |
|
labels: Array(30).fill(''), |
|
datasets: [{ |
|
label: 'Price', |
|
data: Array(30).fill(0), |
|
borderColor: '#7b2cbf', |
|
backgroundColor: 'rgba(123, 44, 191, 0.1)', |
|
borderWidth: 2, |
|
tension: 0.3, |
|
pointRadius: 0, |
|
fill: true |
|
}] |
|
}, |
|
options: { |
|
responsive: true, |
|
maintainAspectRatio: false, |
|
plugins: { |
|
legend: { |
|
display: false |
|
} |
|
}, |
|
scales: { |
|
x: { |
|
display: false, |
|
grid: { |
|
display: false |
|
} |
|
}, |
|
y: { |
|
display: true, |
|
grid: { |
|
color: 'rgba(255, 255, 255, 0.1)' |
|
}, |
|
ticks: { |
|
color: 'rgba(255, 255, 255, 0.7)' |
|
} |
|
} |
|
}, |
|
interaction: { |
|
intersect: false, |
|
mode: 'index' |
|
} |
|
} |
|
}); |
|
} |
|
|
|
|
|
function updateChart(price) { |
|
if (!chart) return; |
|
|
|
|
|
chart.data.datasets[0].data.shift(); |
|
chart.data.datasets[0].data.push(price); |
|
|
|
|
|
chart.update(); |
|
} |
|
|
|
|
|
async function updateAccountBalances() { |
|
if (!selectedPair) return; |
|
|
|
try { |
|
const [base, quote] = selectedPair.split('/'); |
|
const balance = await exchange.fetchBalance(); |
|
|
|
const usdtBalance = balance.total[quote] || 0; |
|
const baseBalance = balance.total[base] || 0; |
|
|
|
usdtBalanceElement.textContent = usdtBalance.toFixed(4); |
|
baseBalanceElement.textContent = baseBalance.toFixed(4); |
|
|
|
} catch (error) { |
|
logMessage(`Balance update error: ${error.message}`, 'error'); |
|
} |
|
} |
|
|
|
|
|
function generateGridOrders() { |
|
if (!selectedPair || !botRunning) return; |
|
|
|
const price = parseFloat(currentPriceElement.textContent.replace('$', '')); |
|
if (isNaN(price) || price <= 0) return; |
|
|
|
const gridSpacing = parseFloat(document.getElementById('grid-spacing').value) || 0.02; |
|
const orderSize = parseFloat(document.getElementById('order-size').value) || 3; |
|
const maxOrders = parseInt(document.getElementById('max-orders').value) || 33; |
|
|
|
|
|
buyOrdersElement.innerHTML = ''; |
|
sellOrdersElement.innerHTML = ''; |
|
|
|
|
|
for (let i = 1; i <= maxOrders; i++) { |
|
const buyPrice = price * (1 - (i * gridSpacing)); |
|
const buyAmount = orderSize / buyPrice; |
|
|
|
if (buyPrice > 0) { |
|
const buyOrderElement = createOrderElement('buy', buyPrice, buyAmount, i); |
|
buyOrdersElement.appendChild(buyOrderElement); |
|
} |
|
} |
|
|
|
|
|
for (let i = 1; i <= maxOrders; i++) { |
|
const sellPrice = price * (1 + (i * gridSpacing)); |
|
const sellAmount = orderSize / price; |
|
|
|
if (sellPrice > 0) { |
|
const sellOrderElement = createOrderElement('sell', sellPrice, sellAmount, i); |
|
sellOrdersElement.appendChild(sellOrderElement); |
|
} |
|
} |
|
} |
|
|
|
|
|
function createOrderElement(type, price, amount, index) { |
|
const orderElement = document.createElement('div'); |
|
orderElement.className = 'bg-gray-800 rounded-lg p-2 flex justify-between items-center'; |
|
|
|
const colorClass = type === 'buy' ? 'text-purple-400' : 'text-orange-400'; |
|
const bgClass = type === 'buy' ? 'bg-purple-900' : 'bg-orange-900'; |
|
|
|
orderElement.innerHTML = ` |
|
<div class="flex items-center"> |
|
<span class="w-6 h-6 ${bgClass} rounded-full flex items-center justify-center text-xs mr-2">${index}</span> |
|
<span class="${colorClass}">${type.toUpperCase()}</span> |
|
</div> |
|
<div class="text-right"> |
|
<div class="text-sm">$${price.toFixed(6)}</div> |
|
<div class="text-xs text-gray-400">${amount.toFixed(4)}</div> |
|
</div> |
|
`; |
|
|
|
return orderElement; |
|
} |
|
|
|
|
|
async function startBot() { |
|
if (botRunning) return; |
|
|
|
if (!selectedPair) { |
|
logMessage('Please select a trading pair first', 'warning'); |
|
return; |
|
} |
|
|
|
botRunning = true; |
|
logMessage('Grid trading bot activated', 'success'); |
|
|
|
startBotButton.disabled = true; |
|
startBotButton.classList.add('opacity-50'); |
|
stopBotButton.disabled = false; |
|
stopBotButton.classList.remove('opacity-50'); |
|
|
|
|
|
generateGridOrders(); |
|
|
|
|
|
if (gridUpdateInterval) clearInterval(gridUpdateInterval); |
|
gridUpdateInterval = setInterval(generateGridOrders, 10000); |
|
} |
|
|
|
|
|
function stopBot() { |
|
if (!botRunning) return; |
|
|
|
botRunning = false; |
|
logMessage('Grid trading bot deactivated', 'warning'); |
|
|
|
startBotButton.disabled = false; |
|
startBotButton.classList.remove('opacity-50'); |
|
stopBotButton.disabled = true; |
|
stopBotButton.classList.add('opacity-50'); |
|
|
|
|
|
if (gridUpdateInterval) { |
|
clearInterval(gridUpdateInterval); |
|
gridUpdateInterval = null; |
|
} |
|
|
|
|
|
buyOrdersElement.innerHTML = ''; |
|
sellOrdersElement.innerHTML = ''; |
|
} |
|
|
|
|
|
function logMessage(message, type = 'info') { |
|
const now = new Date(); |
|
const timestamp = now.toLocaleTimeString(); |
|
|
|
let colorClass; |
|
switch (type) { |
|
case 'error': colorClass = 'text-red-400'; break; |
|
case 'success': colorClass = 'text-green-400'; break; |
|
case 'warning': colorClass = 'text-orange-400'; break; |
|
default: colorClass = 'text-gray-300'; |
|
} |
|
|
|
const messageElement = document.createElement('div'); |
|
messageElement.className = `flex ${colorClass}`; |
|
messageElement.innerHTML = ` |
|
<span class="text-gray-500 mr-2">[${timestamp}]</span> |
|
<span>${message}</span> |
|
`; |
|
|
|
logTerminal.appendChild(messageElement); |
|
logTerminal.scrollTop = logTerminal.scrollHeight; |
|
} |
|
|
|
|
|
function updateCurrentTime() { |
|
const now = new Date(); |
|
currentTimeElement.textContent = now.toLocaleTimeString(); |
|
} |
|
|
|
|
|
startBotButton.addEventListener('click', startBot); |
|
stopBotButton.addEventListener('click', stopBot); |
|
|
|
document.getElementById('clear-log').addEventListener('click', () => { |
|
logTerminal.innerHTML = ''; |
|
}); |
|
|
|
|
|
document.addEventListener('DOMContentLoaded', () => { |
|
initExchange(); |
|
setInterval(updateCurrentTime, 1000); |
|
|
|
|
|
document.addEventListener('click', (e) => { |
|
if (!pairSearch.contains(e.target) && !searchResults.contains(e.target)) { |
|
searchResults.classList.add('hidden'); |
|
} |
|
}); |
|
}); |
|
</script> |
|
</body> |
|
</html> |