CryptoFox-Mukan-Edition/src/web/index.html

437 lines
29 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mukan Special Edition</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/tom-select@2/dist/css/tom-select.min.css">
<script src="https://cdn.jsdelivr.net/npm/tom-select@2/dist/js/tom-select.complete.min.js"></script>
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--bg: #0f0f13;
--surface: #1a1a22;
--border: #2a2a38;
--text: #e0e0f0;
--muted: #888;
--accent: #6c63ff;
--green: #2ecc71;
--red: #e74c3c;
--yellow: #f39c12;
}
body { background: var(--bg); color: var(--text); font-family: 'Segoe UI', system-ui, sans-serif; font-size: 14px; min-height: 100vh; }
header { background: var(--surface); border-bottom: 1px solid var(--border); padding: 16px 24px; display: flex; align-items: center; gap: 12px; }
header h1 { font-size: 18px; font-weight: 600; color: var(--accent); margin: 0; }
.logo-crypto { color: #d0d0d0; }
.logo-fox { color: #00d4ff; }
.logo-edition { font-size: 11px; font-weight: 400; color: var(--muted); }
header .status-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--muted); }
header .status-dot.connected { background: var(--green); }
header .spacer { flex: 1; }
.mode-toggle { display: flex; align-items: center; gap: 8px; background: var(--bg); border: 1px solid var(--border); border-radius: 6px; padding: 4px; }
.mode-btn { padding: 4px 14px; border-radius: 4px; border: none; background: transparent; color: var(--muted); font-size: 12px; font-weight: 600; cursor: pointer; transition: all 0.15s; }
.mode-btn.active-live { background: rgba(46,204,113,0.15); color: var(--green); }
.mode-btn.active-testnet { background: rgba(243,156,18,0.15); color: var(--yellow); }
main { padding: 24px; max-width: 1400px; margin: 0 auto; display: flex; flex-direction: column; gap: 24px; }
section { background: var(--surface); border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }
.section-header { padding: 14px 18px; border-bottom: 1px solid var(--border); font-weight: 600; font-size: 13px; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); display: flex; align-items: center; justify-content: space-between; }
table { width: 100%; border-collapse: collapse; }
th, td { padding: 10px 18px; text-align: left; border-bottom: 1px solid var(--border); }
th { font-size: 12px; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); font-weight: 500; }
tr:last-child td { border-bottom: none; }
tr:hover td { background: rgba(255,255,255,0.02); }
.badge { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 11px; font-weight: 600; }
.badge-running { background: rgba(46,204,113,0.15); color: var(--green); }
.badge-stopped { background: rgba(136,136,136,0.1); color: var(--muted); }
.btn { padding: 5px 12px; border-radius: 5px; border: 1px solid var(--border); background: transparent; color: var(--text); font-size: 12px; cursor: pointer; transition: all 0.15s; }
.btn:hover { background: rgba(255,255,255,0.05); }
.btn-start { border-color: var(--green); color: var(--green); }
.btn-start:hover { background: rgba(46,204,113,0.1); }
.btn-stop { border-color: var(--yellow); color: var(--yellow); }
.btn-stop:hover { background: rgba(243,156,18,0.1); }
.btn-delete { border-color: var(--red); color: var(--red); }
.btn-delete:hover { background: rgba(231,76,60,0.1); }
.btn-primary { background: var(--accent); border-color: var(--accent); color: #fff; }
.btn-primary:hover { background: #5a52d5; }
.empty { padding: 24px 18px; color: var(--muted); font-size: 13px; text-align: center; }
/* Auth overlay */
#auth-overlay { position: fixed; inset: 0; background: var(--bg); display: flex; align-items: center; justify-content: center; z-index: 200; }
.auth-box { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; padding: 32px; width: 320px; display: flex; flex-direction: column; gap: 16px; }
.auth-box h2 { font-size: 16px; color: var(--accent); }
.auth-box input { background: var(--bg); border: 1px solid var(--border); border-radius: 5px; padding: 9px 12px; color: var(--text); font-size: 14px; width: 100%; }
.auth-box input:focus { outline: none; border-color: var(--accent); }
.auth-error { color: var(--red); font-size: 12px; display: none; }
/* Modal */
#modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.6); display: none; align-items: center; justify-content: center; z-index: 100; }
#modal-overlay.open { display: flex; }
.modal { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; width: 480px; max-width: 95vw; display: flex; flex-direction: column; overflow: visible; }
.modal-header { padding: 16px 20px; border-bottom: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; }
.modal-header h2 { font-size: 15px; font-weight: 600; }
.modal-close { background: none; border: none; color: var(--muted); font-size: 20px; cursor: pointer; line-height: 1; padding: 0 4px; }
.modal-close:hover { color: var(--text); }
.modal-body { padding: 20px; display: flex; flex-direction: column; gap: 14px; }
.modal-footer { padding: 14px 20px; border-top: 1px solid var(--border); display: flex; justify-content: flex-end; gap: 8px; }
.form-group { display: flex; flex-direction: column; gap: 5px; }
.form-group label { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.05em; }
.form-group input, .form-group select { background: var(--bg); border: 1px solid var(--border); border-radius: 5px; padding: 7px 10px; color: var(--text); font-size: 13px; }
.form-group input:focus, .form-group select:focus { outline: none; border-color: var(--accent); }
.form-group select option { background: var(--surface); }
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
/* TomSelect dark theme */
.ts-wrapper .ts-control,
.ts-wrapper.multi .ts-control,
.ts-wrapper.single .ts-control { background: var(--bg) !important; border-color: var(--border) !important; color: var(--text) !important; min-height: 34px; padding: 4px 10px; border-radius: 5px; box-shadow: none !important; }
.ts-wrapper.focus .ts-control,
.ts-wrapper.single.focus .ts-control { border-color: var(--accent) !important; box-shadow: none !important; }
.ts-wrapper .ts-control input,
.ts-wrapper .ts-control input:focus { background: transparent !important; color: var(--text) !important; outline: none !important; }
.ts-dropdown,
.ts-dropdown.single,
.ts-dropdown.multi { background: var(--surface) !important; border-color: var(--border) !important; color: var(--text) !important; z-index: 150; max-height: 260px !important; }
.ts-dropdown .ts-dropdown-content { max-height: 260px !important; overflow-y: auto !important; }
.ts-dropdown .option { padding: 7px 12px; color: var(--text) !important; background: transparent !important; }
.ts-dropdown .option:hover,
.ts-dropdown .option.active { background: rgba(108,99,255,0.2) !important; color: var(--text) !important; }
.ts-dropdown .option.selected { background: rgba(108,99,255,0.1) !important; }
.ts-wrapper .ts-control .item { color: var(--text) !important; background: rgba(108,99,255,0.15) !important; border-radius: 3px; padding: 1px 6px; border: none !important; }
</style>
</head>
<body>
<div id="auth-overlay">
<div class="auth-box">
<h2>Mukan Special Edition</h2>
<input type="password" id="token-input" placeholder="Auth token" onkeydown="if(event.key==='Enter')login()" />
<button class="btn btn-primary" onclick="login()">Giriş</button>
<span class="auth-error" id="auth-error">Geçersiz token</span>
</div>
</div>
<div id="modal-overlay" onclick="if(event.target===this)closeModal()">
<div class="modal">
<div class="modal-header">
<h2>Yeni Bot Ekle</h2>
<button class="modal-close" onclick="closeModal()">×</button>
</div>
<div class="modal-body">
<div class="form-group">
<label>İsim</label>
<input id="f-name" placeholder="DOGE Bot" />
</div>
<div class="form-group">
<label>Coin (USDT çifti)</label>
<select id="f-symbol"><option value="">Yükleniyor...</option></select>
</div>
<div class="form-group">
<label>Timeframe</label>
<select id="f-timeframe">
<option value="1m">1m</option>
<option value="5m" selected>5m</option>
<option value="15m">15m</option>
<option value="30m">30m</option>
<option value="1h">1h</option>
<option value="4h">4h</option>
<option value="1d">1d</option>
</select>
</div>
<div class="form-row">
<div class="form-group">
<label>USDT Miktarı <span id="f-min-label" style="color:var(--muted);font-size:10px"></span></label>
<input id="f-usdt" type="number" step="1" inputmode="numeric" placeholder="—" />
</div>
<div class="form-group">
<label>Kar %</label>
<input id="f-profit" type="number" step="0.1" placeholder="2" />
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn" onclick="closeModal()">İptal</button>
<button class="btn btn-primary" onclick="createBot()">Bot Ekle</button>
</div>
</div>
</div>
<header>
<img src="data:image/png;base64,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pl9v8CM+k5nikMXRDlGoeyoh1qmiqLXGxQ8GyWpnsLC0UwkHC4M2Mic4OdrZFZzS3dUzOsaLS98uGR3rZYRhy3jR4vnDg5O9sO3eW74P57vb4/ioWv0PwLZBDNF9BsfImMHtjU0XQMoXKMg7JYX4+CKW1ZLk+M2mpu5gqeQIJ7LPWODnKnwYF7QfPrLxHcvVeyC/vATp6S+EROxjWxCsfbOn/CAD/kGjAeDAReeAHc5YxsC8j6itvbazsKi0rXxgxjTNCUhNzb6JSwY01ay108YEgeNOuc0Nfk7NXKvq+ukd5UMTXxZXljDbej00YsSHvIV/MPh7t8fxEV63Coo37AP9jNoosq1oM4gjx0sQSsZiJ1mRYFWFltq0Hzv1GSwccCejt9oU3KLLueIZVdGAWu9wHG4484UnYO2f7/gx6X94pf8ZX9ZvAimdgqWXnHfA4KXIS9i7xyXwbwoYHx4qQ87jcnB/f466EbAjEuHWrWZZO3XKIsEVD9WTrqPw9ItLfmzqH97Tx0fVm5sAA/WbwK7OBQjdYoeFTCQ0SzP0AkZZG+f0PP2isz8JUZrvoeYzDOHQF9PO+kk5f1R7/GeUDh0KiSx/BgyjLkaE8nrgBhRRAyTGcAhLratdpVw75SOmob2cwmKv0NIKPR+//ZNy/uRK/wv/0mpwmgYOSc6Rks2d6UO8aCNBsxD9xMjEd3JEtBtnTPhZcv1saACAoum3AVxwCUCoWxFE2SmZVoIE8rXwulXQ8fxDP2eq/774X50kkXXRQ6zFAAAA0GVYSWZJSSoACAAAAAoAAAEEAAEAAADOAQAAAQEEAAEAAADoAQAAAgEDAAMAAACGAAAAEgEDAAEAAAABAAAAGgEFAAEAAACMAAAAGwEFAAEAAACUAAAAKAEDAAEAAAACAAAAMQECAA0AAACcAAAAMgECABQAAACqAAAAaYcEAAEAAAC+AAAAAAAAAAgACAAIAEgAAAABAAAASAAAAAEAAABHSU1QIDIuMTAuMzYAADIwMjY6MDQ6MDggMDM6MjE6NDgAAQABoAMAAQAAAAEAAAAAAAAAVFPgpwAAABR0RVh0ZXhpZjpJbWFnZUxlbmd0aAA0ODi9UOnUAAAAE3RFWHRleGlmOkltYWdlV2lkdGgANDYyEHo9yQAAABp0RVh0ZXhpZjpCaXRzUGVyU2FtcGxlADgsIDgsIDgS7T4nAAAAEXRFWHRleGlmOkNvbG9yU3BhY2UAMQ+bAkkAAAAhdEVYdGV4aWY6RGF0ZVRpbWUAMjAyNjowNDowOCAwMzoyMTo0OITXgjAAAAATdEVYdGV4aWY6RXhpZk9mZnNldAAxOTBMjvPCAAAAGnRFWHRleGlmOlNvZnR3YXJlAEdJTVAgMi4xMC4zNvZoErYAAAAbdEVYdGljYzpjb3B5cmlnaHQAUHVibGljIERvbWFpbraRMVsAAAAidEVYdGljYzpkZXNjcmlwdGlvbgBHSU1QIGJ1aWx0LWluIHNSR0JMZ0ETAAAAFXRFWHRpY2M6bWFudWZhY3R1cmVyAEdJTVBMnpDKAAAADnRFWHRpY2M6bW9kZWwAc1JHQltgSUMAAAAASUVORK5CYII=" style="height:32px;width:32px;object-fit:contain" alt="logo">
<div style="display:flex;flex-direction:column;justify-content:center;align-items:center;gap:2px">
<h1><span class="logo-crypto">Crypto</span><span class="logo-fox">Fox</span></h1>
<span class="logo-edition">[ MUKAN EDITION ]</span>
</div>
<span class="status-dot" id="sse-dot"></span>
<span id="sse-label" style="font-size:12px; color:var(--muted)">bağlanıyor...</span>
<span class="spacer"></span>
<div class="mode-toggle">
<button class="mode-btn" id="btn-testnet" onclick="switchMode('testnet')">Testnet</button>
<button class="mode-btn" id="btn-live" onclick="switchMode('live')">Canlı</button>
</div>
</header>
<main>
<section>
<div class="section-header">
Botlar <span id="bot-count" style="color:var(--text)">0</span>
<button class="btn btn-primary" onclick="openModal()" style="font-size:12px;padding:4px 12px">+ Yeni Bot</button>
</div>
<table id="bots-table">
<thead><tr><th>İsim</th><th>Sembol</th><th>Timeframe</th><th>USDT</th><th>Kar %</th><th>Testnet</th><th>Durum</th><th></th></tr></thead>
<tbody id="bots-body"><tr><td colspan="8" class="empty">Yükleniyor...</td></tr></tbody>
</table>
</section>
<section>
<div class="section-header">ık Pozisyonlar</div>
<table>
<thead><tr><th>Bot</th><th>Sembol</th><th>Alış</th><th>Hedef</th><th>Miktar</th><th>Zaman</th></tr></thead>
<tbody id="positions-body"><tr><td colspan="6" class="empty">ık pozisyon yok</td></tr></tbody>
</table>
</section>
<section>
<div class="section-header">Kapalı İşlemler</div>
<table>
<thead><tr><th>Bot</th><th>Sembol</th><th>Alış</th><th>Hedef</th><th>Miktar</th><th>Durum</th><th>Zaman</th></tr></thead>
<tbody id="closed-body"><tr><td colspan="7" class="empty">Henüz işlem yok</td></tr></tbody>
</table>
</section>
</main>
<script>
let AUTH_TOKEN = localStorage.getItem('mse_token') || '';
let sseSource = null;
let symbolSelect = null;
let allSymbols = [];
let currentMode = 'testnet';
function login() {
const t = document.getElementById('token-input').value.trim();
if (!t) return;
AUTH_TOKEN = t;
localStorage.setItem('mse_token', t);
tryConnect();
}
async function api(method, path, body) {
const res = await fetch('/api' + path, {
method,
headers: { 'Authorization': 'Bearer ' + AUTH_TOKEN, 'Content-Type': 'application/json' },
body: body ? JSON.stringify(body) : undefined,
});
if (res.status === 401) { showAuthOverlay(); throw new Error('Unauthorized'); }
return res;
}
function showAuthOverlay() {
document.getElementById('auth-overlay').style.display = 'flex';
}
async function tryConnect() {
const res = await fetch('/api/bots', { headers: { 'Authorization': 'Bearer ' + AUTH_TOKEN } });
if (res.status === 401) {
document.getElementById('auth-error').style.display = 'block';
return;
}
document.getElementById('auth-overlay').style.display = 'none';
loadAll();
connectSSE();
}
async function loadAll() {
await loadMode();
loadBots();
loadPositions();
loadClosed();
loadSymbols();
}
async function loadMode() {
const res = await api('GET', '/mode');
const data = await res.json();
currentMode = data.mode;
updateModeUI();
}
function updateModeUI() {
const btnTestnet = document.getElementById('btn-testnet');
const btnLive = document.getElementById('btn-live');
btnTestnet.className = 'mode-btn' + (currentMode === 'testnet' ? ' active-testnet' : '');
btnLive.className = 'mode-btn' + (currentMode === 'live' ? ' active-live' : '');
}
async function switchMode(mode) {
if (mode === currentMode) return;
if (mode === 'live') {
if (!confirm('Canlı moda geçilecek. Çalışan tüm botlar durdurulacak. Devam edilsin mi?')) return;
}
await api('POST', '/mode', { mode });
currentMode = mode;
updateModeUI();
loadAll();
}
async function loadSymbols() {
const res = await api('GET', '/symbols');
allSymbols = await res.json();
symbolSelect = new TomSelect('#f-symbol', {
valueField: 'symbol',
labelField: 'symbol',
searchField: 'symbol',
options: allSymbols,
placeholder: 'Ara veya seç...',
minChars: 0,
maxOptions: false,
dropdownParent: 'body',
render: {
option: (data) =>
`<div style="display:flex;justify-content:space-between;align-items:center">
<strong>${data.symbol}</strong>
<span style="color:#888;font-size:11px">min ${data.min_notional} USDT</span>
</div>`,
item: (data) => `<div>${data.symbol}</div>`,
},
onChange(value) {
const item = allSymbols.find(s => s.symbol === value);
if (!item) return;
const usdtInput = document.getElementById('f-usdt');
usdtInput.value = item.min_notional;
usdtInput.min = item.min_notional;
document.getElementById('f-min-label').textContent = `(min ${item.min_notional} USDT)`;
},
});
}
function openModal() {
const modeLabel = currentMode === 'testnet' ? '🟡 Testnet' : '🟢 Canlı';
document.querySelector('.modal-header h2').textContent = `Yeni Bot Ekle — ${modeLabel}`;
document.getElementById('modal-overlay').classList.add('open');
if (symbolSelect) symbolSelect.focus();
}
function closeModal() {
document.getElementById('modal-overlay').classList.remove('open');
}
document.addEventListener('keydown', e => { if (e.key === 'Escape') closeModal(); });
async function loadBots() {
const res = await api('GET', '/bots');
const bots = await res.json();
document.getElementById('bot-count').textContent = bots.length;
const tbody = document.getElementById('bots-body');
if (!bots.length) { tbody.innerHTML = '<tr><td colspan="8" class="empty">Henüz bot yok</td></tr>'; return; }
tbody.innerHTML = bots.map(b => `
<tr>
<td>${esc(b.name)}</td>
<td><strong>${esc(b.symbol)}</strong></td>
<td>${esc(b.timeframe)}</td>
<td>${b.usdt_amount} USDT</td>
<td>%${b.profit_percent}</td>
<td>${b.testnet ? '🟡 Test' : '🟢 Gerçek'}</td>
<td><span class="badge ${b.running ? 'badge-running' : 'badge-stopped'}">${b.running ? 'Çalışıyor' : 'Durdu'}</span></td>
<td style="display:flex;gap:6px;flex-wrap:wrap">
${b.running
? `<button class="btn btn-stop" onclick="stopBot('${b.id}')">Durdur</button>`
: `<button class="btn btn-start" onclick="startBot('${b.id}')">Başlat</button>`
}
<button class="btn btn-delete" onclick="deleteBot('${b.id}','${esc(b.name)}')">Sil</button>
</td>
</tr>`).join('');
}
async function loadPositions() {
const res = await api('GET', '/positions');
const positions = await res.json();
const tbody = document.getElementById('positions-body');
if (!positions.length) { tbody.innerHTML = '<tr><td colspan="6" class="empty">Açık pozisyon yok</td></tr>'; return; }
tbody.innerHTML = positions.map(p => `
<tr>
<td>${esc(p.bot_name)}</td>
<td><strong>${esc(p.symbol)}</strong></td>
<td>${p.buy_price.toFixed(6)}</td>
<td>${p.sell_target.toFixed(6)}</td>
<td>${p.quantity}</td>
<td>${new Date(p.opened_at).toLocaleString('tr-TR')}</td>
</tr>`).join('');
}
async function loadClosed() {
const res = await api('GET', '/positions/closed');
const closed = await res.json();
const tbody = document.getElementById('closed-body');
if (!closed.length) { tbody.innerHTML = '<tr><td colspan="7" class="empty">Henüz işlem yok</td></tr>'; return; }
tbody.innerHTML = closed.map(c => `
<tr>
<td>${esc(c.bot_name)}</td>
<td><strong>${esc(c.symbol)}</strong></td>
<td>${c.buy_price.toFixed(6)}</td>
<td>${c.sell_target.toFixed(6)}</td>
<td>${c.quantity}</td>
<td><span class="badge ${c.status==='FILLED'?'badge-running':'badge-stopped'}">${c.status}</span></td>
<td>${new Date(c.closed_at).toLocaleString('tr-TR')}</td>
</tr>`).join('');
}
async function createBot() {
const name = document.getElementById('f-name').value.trim();
const symbol = symbolSelect ? symbolSelect.getValue() : '';
const timeframe = document.getElementById('f-timeframe').value;
const usdt_amount = parseFloat(document.getElementById('f-usdt').value);
const profit_percent = parseFloat(document.getElementById('f-profit').value);
const usdtInput = document.getElementById('f-usdt');
const minNotional = parseFloat(usdtInput.min) || 0;
if (!name || !symbol || !usdt_amount || !profit_percent) { alert('Tüm alanları doldurun'); return; }
if (usdt_amount < minNotional) { alert(`Minimum işlem miktarı ${minNotional} USDT`); usdtInput.focus(); return; }
await api('POST', '/bots', { name, symbol, timeframe, usdt_amount, profit_percent });
closeModal();
document.getElementById('f-name').value = '';
if (symbolSelect) symbolSelect.clear();
document.getElementById('f-usdt').value = '';
document.getElementById('f-profit').value = '';
document.getElementById('f-min-label').textContent = '';
loadBots();
}
async function startBot(id) {
await api('POST', `/bots/${id}/start`);
loadBots();
}
async function stopBot(id) {
await api('POST', `/bots/${id}/stop`);
loadBots();
}
async function deleteBot(id, name) {
if (!confirm(`"${name}" botunu silmek istiyor musun?`)) return;
await api('DELETE', `/bots/${id}`);
loadBots();
}
function connectSSE() {
if (sseSource) sseSource.close();
sseSource = new EventSource(`/api/events?token=${encodeURIComponent(AUTH_TOKEN)}`);
sseSource.addEventListener('trade', () => { loadPositions(); loadClosed(); });
sseSource.onopen = () => {
document.getElementById('sse-dot').className = 'status-dot connected';
document.getElementById('sse-label').textContent = 'aktif';
};
sseSource.onerror = () => {
document.getElementById('sse-dot').className = 'status-dot';
document.getElementById('sse-label').textContent = 'bağlantı kesildi';
setTimeout(connectSSE, 5000);
};
}
function esc(s) {
return String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
}
if (AUTH_TOKEN) tryConnect();
else showAuthOverlay();
</script>
</body>
</html>