437 lines
29 KiB
HTML
437 lines
29 KiB
HTML
<!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">Açı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">Açı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,'&').replace(/</g,'<').replace(/>/g,'>');
|
||
}
|
||
|
||
if (AUTH_TOKEN) tryConnect();
|
||
else showAuthOverlay();
|
||
</script>
|
||
</body>
|
||
</html>
|