From 050cc18051650bfad5165b625a93a59f798fa74f Mon Sep 17 00:00:00 2001 From: Mukan Erkin Date: Sun, 19 Apr 2026 20:38:09 +0300 Subject: [PATCH] feat(logs): color-coded log levels for buy/sell/skip events Replace emoji prefixes with dedicated log level types: buy (orange), sell (green), skip (purple), info (gray). CSS updated in bot.html. Co-Authored-By: Claude Sonnet 4.6 --- src/bot/runner.rs | 14 +- src/web/bot.html | 618 +++++++++++++++++++++++----------------------- 2 files changed, 319 insertions(+), 313 deletions(-) diff --git a/src/bot/runner.rs b/src/bot/runner.rs index 5782b59..bf05658 100644 --- a/src/bot/runner.rs +++ b/src/bot/runner.rs @@ -122,12 +122,12 @@ impl BotRunner { { Ok(Some(result)) => { info!( - "[{}] ✅ İşlem | Alış: {:.6} | Satış hedefi: {:.6} | Kar: %{:.2}", + "[{}] İşlem | Alış: {:.6} | Satış hedefi: {:.6} | Kar: %{:.2}", config.symbol, result.buy_order.price, result.sell_order.price, config.profit_percent ); { let db_guard = db.lock().await; - db_guard.insert_log(&config.id, "trade", &format!("✅ İşlem gerçekleşti | Alış: {:.6} | Satış hedefi: {:.6} | Miktar: {:.6} | Kar: %{:.2}", result.buy_order.price, result.sell_order.price, result.buy_order.quantity, config.profit_percent)).ok(); + db_guard.insert_log(&config.id, "buy", &format!("İşlem gerçekleşti | Alış: {:.6} | Satış hedefi: {:.6} | Miktar: {:.6} | Kar: %{:.2}", result.buy_order.price, result.sell_order.price, result.buy_order.quantity, config.profit_percent)).ok(); } let record = TradeRecord { @@ -175,17 +175,17 @@ impl BotRunner { }).ok(); } Ok(None) => { - info!("[{}] ⏭ İşlem yapılmadı (yeşil mum).", config.symbol); + info!("[{}] İşlem yapılmadı (yeşil mum).", config.symbol); { let db_guard = db.lock().await; - db_guard.insert_log(&config.id, "info", "⏭ Yeşil mum, işlem yapılmadı.").ok(); + db_guard.insert_log(&config.id, "skip", "Yeşil mum, işlem yapılmadı.").ok(); } } Err(e) => { - error!("[{}] ❌ Strateji hatası: {:?}", config.symbol, e); + error!("[{}] Strateji hatası: {:?}", config.symbol, e); { let db_guard = db.lock().await; - db_guard.insert_log(&config.id, "error", &format!("❌ Strateji hatası: {}", e)).ok(); + db_guard.insert_log(&config.id, "error", &format!("Strateji hatası: {}", e)).ok(); } } } @@ -295,7 +295,7 @@ async fn check_open_positions( } else { db_guard.remove_position(pos.order_id).ok(); info!("[{}] Pozisyon kapatıldı #{} ({})", config.symbol, pos.order_id, status); - db_guard.insert_log(&config.id, "trade", &format!("✅ Pozisyon kapatıldı | Order #{} | Durum: {}", pos.order_id, status)).ok(); + db_guard.insert_log(&config.id, "sell", &format!("Pozisyon kapatıldı | Order #{} | Durum: {}", pos.order_id, status)).ok(); } event_tx.send(TradeEvent { bot_id: config.id.clone(), diff --git a/src/web/bot.html b/src/web/bot.html index 15127e5..5a435f3 100644 --- a/src/web/bot.html +++ b/src/web/bot.html @@ -16,233 +16,275 @@ html, body { height: 100%; overflow: hidden; } body { background: var(--bg); color: var(--text); font-family: 'Segoe UI', system-ui, sans-serif; font-size: 13px; display: flex; flex-direction: column; } - /* ── HEADER / TOP BAR ───────────────────────── */ - #topbar { - background: var(--surface); border-bottom: 1px solid var(--border); - padding: 0 16px; height: 52px; display: flex; align-items: center; gap: 0; flex-shrink: 0; - } - .tb-logo { font-size: 15px; font-weight: 700; margin-right: 12px; } + /* ── SHARED HEADER STYLES ────────────────────── */ + header { background: var(--surface); border-bottom: 1px solid var(--border); padding: 0 24px; height: 52px; display: flex; align-items: center; gap: 16px; flex-shrink: 0; } + .logo { font-size: 16px; font-weight: 700; } .logo-crypto { color: #d0d0d0; } .logo-fox { color: #00d4ff; } - nav { display: flex; gap: 4px; margin-right: 12px; } + .h-sep { width: 1px; height: 20px; background: var(--border); } + nav { display: flex; gap: 4px; } .nav-link { padding: 5px 12px; border-radius: 5px; font-size: 13px; color: var(--muted); text-decoration: none; transition: all .15s; } .nav-link:hover { color: var(--text); background: rgba(255,255,255,.05); } .nav-link.active { color: var(--text); background: rgba(108,99,255,.15); } - .tb-sep { width: 1px; height: 24px; background: var(--border); margin: 0 12px; } - #tb-name { font-size: 15px; font-weight: 600; color: var(--text); } - #tb-symbol { font-size: 13px; color: var(--muted); margin-left: 4px; } - #tb-price { font-size: 18px; font-weight: 700; color: var(--text); min-width: 90px; } - #tb-change { font-size: 13px; font-weight: 600; min-width: 55px; } - .tb-stat { display: flex; flex-direction: column; gap: 1px; } - .tb-stat .lbl { font-size: 10px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; } - .tb-stat .val { font-size: 12px; color: var(--text); } .spacer { flex: 1; } + .mode-toggle { display: flex; align-items: center; gap: 4px; background: var(--bg); border: 1px solid var(--border); border-radius: 6px; padding: 3px; } + .mode-btn { padding: 3px 12px; border-radius: 4px; border: none; background: transparent; color: var(--muted); font-size: 11px; font-weight: 600; cursor: pointer; transition: all .15s; } + .mode-btn.active-live { background: rgba(46,204,113,.15); color: var(--green); } + .mode-btn.active-testnet { background: rgba(243,156,18,.15); color: var(--yellow); } + .btn-logout { padding: 5px 12px; border-radius: 5px; border: 1px solid var(--red); background: transparent; color: var(--red); font-size: 12px; cursor: pointer; transition: all .15s; } + .btn-logout:hover { background: rgba(231,76,60,.1); } + + /* ── BUTTONS ─────────────────────────────────── */ + .btn { padding: 5px 12px; border-radius: 5px; border: 1px solid var(--border); background: transparent; color: var(--text); font-size: 12px; cursor: pointer; transition: all .15s; white-space: nowrap; } + .btn:hover { background: rgba(255,255,255,.05); } + .btn-primary { background: var(--accent); border-color: var(--accent); color: #fff; } + .btn-primary:hover { background: #5a52d5; } + .btn-danger { border-color: var(--red); color: var(--red); } + .btn-danger:hover { background: rgba(231,76,60,.1); } + + /* ── BADGES ──────────────────────────────────── */ .badge { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 11px; font-weight: 600; } .badge-running { background: rgba(46,204,113,.15); color: var(--green); } .badge-stopped { background: rgba(136,136,136,.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 .15s; white-space: nowrap; } - .btn:hover { background: rgba(255,255,255,.05); } - .btn-start { border-color: var(--green); color: var(--green); } - .btn-start:hover { background: rgba(46,204,113,.1); } - .btn-stop { border-color: var(--yellow); color: var(--yellow); } - .btn-stop:hover { background: rgba(243,156,18,.1); } - .btn-delete { border-color: var(--red); color: var(--red); } - .btn-delete:hover { background: rgba(231,76,60,.1); } - .btn-primary { background: var(--accent); border-color: var(--accent); color: #fff; } - .btn-primary:hover { background: #5a52d5; } - .btn-logout { border-color: var(--red); color: var(--red); font-size: 12px; } - .btn-logout:hover { background: rgba(231,76,60,.1); } - .mode-toggle { display: flex; align-items: center; gap: 4px; background: var(--bg); border: 1px solid var(--border); border-radius: 6px; padding: 3px; margin-right: 8px; } - .mode-btn { padding: 3px 10px; border-radius: 4px; border: none; background: transparent; color: var(--muted); font-size: 11px; font-weight: 600; cursor: pointer; transition: all .15s; } - .mode-btn.active-live { background: rgba(46,204,113,.15); color: var(--green); } - .mode-btn.active-testnet { background: rgba(243,156,18,.15); color: var(--yellow); } - /* ── MAIN LAYOUT ─────────────────────────────── */ + /* ── PRICE BAR ───────────────────────────────── */ + #price-bar { + background: var(--surface2); border-bottom: 1px solid var(--border); + padding: 0 16px; height: 44px; display: flex; align-items: center; gap: 0; flex-shrink: 0; + } + .pb-sep { width: 1px; height: 20px; background: var(--border); margin: 0 14px; } + #pb-name { font-size: 14px; font-weight: 600; } + #pb-symbol { font-size: 12px; color: var(--muted); margin-left: 6px; } + #pb-price { font-size: 18px; font-weight: 700; margin-left: 0; min-width: 90px; } + #pb-change { font-size: 12px; font-weight: 600; min-width: 52px; } + .pb-stat { display: flex; flex-direction: column; gap: 1px; } + .pb-stat .lbl { font-size: 10px; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; } + .pb-stat .val { font-size: 12px; color: var(--text); } + #pb-tf { background: rgba(108,99,255,.15); color: var(--accent); padding: 2px 8px; border-radius: 4px; font-size: 11px; font-weight: 600; } + #chart-ohlc { font-size: 11px; color: var(--muted); display: flex; gap: 10px; } + #chart-ohlc span b { color: var(--text); } + + /* ── MAIN 3-COLUMN LAYOUT ────────────────────── */ #layout { flex: 1; display: grid; min-height: 0; - grid-template-columns: 360px 1fr; + grid-template-columns: 260px 1fr 260px; grid-template-rows: 1fr; } - /* ── LEFT PANE ───────────────────────────────── */ - #left-pane { - border-right: 1px solid var(--border); display: flex; flex-direction: column; overflow: hidden; + /* ── PANE COMMONS ────────────────────────────── */ + .pane { border-right: 1px solid var(--border); display: flex; flex-direction: column; overflow: hidden; } + .pane:last-child { border-right: none; border-left: 1px solid var(--border); } + .pane-hdr { + padding: 7px 12px; border-bottom: 1px solid var(--border); + font-size: 10px; font-weight: 600; text-transform: uppercase; + letter-spacing: .06em; color: var(--muted); flex-shrink: 0; + display: flex; align-items: center; justify-content: space-between; + background: var(--surface2); } - .pane-header { - padding: 8px 14px; border-bottom: 1px solid var(--border); - font-size: 11px; font-weight: 600; text-transform: uppercase; - letter-spacing: .05em; color: var(--muted); display: flex; align-items: center; justify-content: space-between; - flex-shrink: 0; - } - .pane-tabs { display: flex; border-bottom: 1px solid var(--border); flex-shrink: 0; } - .pane-tab { - flex: 1; padding: 9px 8px; text-align: center; font-size: 11px; font-weight: 600; - text-transform: uppercase; letter-spacing: .04em; color: var(--muted); - cursor: pointer; border-bottom: 2px solid transparent; transition: all .15s; - } - .pane-tab.active { color: var(--accent); border-bottom-color: var(--accent); } - .pane-tab:hover:not(.active) { color: var(--text); } - .pane-content { overflow-y: auto; } - .pane-content::-webkit-scrollbar { width: 4px; } - .pane-content::-webkit-scrollbar-track { background: transparent; } - .pane-content::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; } - /* settings section */ - #settings-section { border-bottom: 1px solid var(--border); flex-shrink: 0; } - .form-group { display: flex; flex-direction: column; gap: 4px; } - .form-group label { font-size: 10px; color: var(--muted); text-transform: uppercase; letter-spacing: .05em; } - .form-group input { - background: var(--bg); border: 1px solid var(--border); border-radius: 4px; - padding: 6px 9px; color: var(--text); font-size: 12px; width: 100%; - } - .form-group input:focus { outline: none; border-color: var(--accent); } - .form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; } - #save-status { font-size: 10px; color: var(--green); display: none; } + /* ── LEFT PANE — POSITIONS ───────────────────── */ + #left-pane { } + .pos-half { flex: 1; display: flex; flex-direction: column; min-height: 0; overflow: hidden; } + .pos-half + .pos-half { border-top: 1px solid var(--border); } + .pos-scroll { flex: 1; overflow-y: auto; } + .pos-scroll::-webkit-scrollbar { width: 3px; } + .pos-scroll::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; } - /* positions */ - #pos-section { flex: 1; display: flex; flex-direction: column; min-height: 0; overflow: hidden; } .pos-table { width: 100%; border-collapse: collapse; } - .pos-table th, .pos-table td { padding: 7px 14px; text-align: right; border-bottom: 1px solid rgba(255,255,255,.04); font-size: 12px; } - .pos-table th { font-size: 10px; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); font-weight: 500; text-align: right; position: sticky; top: 0; background: var(--surface2); z-index: 1; } - .pos-table td:first-child, .pos-table th:first-child { text-align: left; } + .pos-table th { font-size: 9px; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); font-weight: 500; padding: 5px 10px; text-align: right; position: sticky; top: 0; background: var(--surface2); z-index: 1; border-bottom: 1px solid var(--border); } + .pos-table th:first-child { text-align: left; } + .pos-table td { padding: 6px 10px; text-align: right; font-size: 11px; border-bottom: 1px solid rgba(255,255,255,.03); } + .pos-table td:first-child { text-align: left; font-size: 10px; color: var(--muted); } .pos-table tr:hover td { background: rgba(255,255,255,.02); } - .empty-row { padding: 24px 14px; text-align: center; color: var(--muted); font-size: 12px; } - .profit-up { color: var(--green); } - .profit-down { color: var(--red); } + .empty-row { padding: 16px 10px; text-align: center; color: var(--muted); font-size: 11px; } + .c-green { color: var(--green); } + .c-red { color: var(--red); } + .c-muted { color: var(--muted); } /* ── CENTER PANE ─────────────────────────────── */ - #center-pane { display: flex; flex-direction: column; overflow: hidden; } - - /* chart */ - #chart-header { padding: 8px 14px; border-bottom: 1px solid var(--border); display: flex; align-items: center; gap: 12px; flex-shrink: 0; } - #chart-tf-label { background: rgba(108,99,255,.15); color: var(--accent); padding: 2px 8px; border-radius: 4px; font-size: 11px; font-weight: 600; } - #chart-ohlc { font-size: 11px; color: var(--muted); display: flex; gap: 10px; } - #chart-ohlc span b { color: var(--text); } + #center-pane { display: flex; flex-direction: column; overflow: hidden; border-right: 1px solid var(--border); } #chart-container { flex: 6; min-height: 0; position: relative; } #chart { width: 100%; height: 100%; } - - /* log terminal */ - #log-section { flex: 4; display: flex; flex-direction: column; min-height: 0; border-top: 1px solid var(--border); } + #log-section { flex: 3; display: flex; flex-direction: column; min-height: 0; border-top: 1px solid var(--border); } #log-terminal { - flex: 1; background: #0a0a0e; padding: 10px 12px; overflow-y: auto; - font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace; font-size: 11px; line-height: 1.7; + flex: 1; background: #0a0a0e; padding: 8px 10px; overflow-y: auto; + font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace; font-size: 11px; line-height: 1.6; } - #log-terminal::-webkit-scrollbar { width: 4px; } + #log-terminal::-webkit-scrollbar { width: 3px; } #log-terminal::-webkit-scrollbar-thumb { background: #2a2a38; border-radius: 2px; } .log-line { display: flex; gap: 8px; } - .log-time { color: #444; min-width: 70px; flex-shrink: 0; font-size: 10px; padding-top: 1px; } - .log-level { min-width: 40px; flex-shrink: 0; font-weight: 700; font-size: 10px; padding-top: 1px; } - .log-level.info { color: #6c63ff; } - .log-level.trade { color: var(--green); } + .log-time { color: #444; min-width: 62px; flex-shrink: 0; font-size: 10px; padding-top: 1px; } + .log-level { min-width: 38px; flex-shrink: 0; font-weight: 700; font-size: 10px; padding-top: 1px; } + .log-level.info { color: #888; } + .log-level.buy { color: #f0a500; } + .log-level.sell { color: var(--green); } + .log-level.skip { color: #6c63ff; } .log-level.error { color: var(--red); } + .log-level.trade { color: var(--green); } .log-msg { color: #a0a0b8; word-break: break-word; } #log-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--muted); display: inline-block; } + + /* ── RIGHT PANE ──────────────────────────────── */ + #right-pane { overflow-y: auto; } + #right-pane::-webkit-scrollbar { width: 3px; } + #right-pane::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; } + + /* status card */ + .status-card { padding: 16px 14px; border-bottom: 1px solid var(--border); display: flex; flex-direction: column; align-items: center; gap: 12px; } + .status-badge-lg { padding: 4px 16px; border-radius: 20px; font-size: 12px; font-weight: 700; letter-spacing: .04em; } + .play-btn { + width: 52px; height: 52px; border-radius: 50%; border: 2px solid var(--border); + background: transparent; cursor: pointer; display: flex; align-items: center; justify-content: center; + font-size: 20px; color: var(--text); transition: all .2s; + } + .play-btn.state-running { border-color: var(--yellow); color: var(--yellow); } + .play-btn.state-running:hover { background: rgba(243,156,18,.1); } + .play-btn.state-stopped { border-color: var(--green); color: var(--green); } + .play-btn.state-stopped:hover { background: rgba(46,204,113,.1); } + .del-btn-small { font-size: 11px; color: var(--muted); background: none; border: none; cursor: pointer; text-decoration: underline; } + .del-btn-small:hover { color: var(--red); } + + /* settings card */ + .settings-card { padding: 12px 14px; border-bottom: 1px solid var(--border); display: flex; flex-direction: column; gap: 10px; } + .form-group { display: flex; flex-direction: column; gap: 4px; } + .form-group label { font-size: 10px; color: var(--muted); text-transform: uppercase; letter-spacing: .05em; } + .form-group input { background: var(--bg); border: 1px solid var(--border); border-radius: 4px; padding: 6px 9px; color: var(--text); font-size: 12px; width: 100%; } + .form-group input:focus { outline: none; border-color: var(--accent); } + .form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; } + #save-status { font-size: 10px; color: var(--green); } + + /* stats card */ + .stats-card { padding: 12px 14px; display: flex; flex-direction: column; gap: 10px; } + .stat-row { display: flex; justify-content: space-between; align-items: center; } + .stat-row .lbl { font-size: 11px; color: var(--muted); } + .stat-row .val { font-size: 12px; font-weight: 600; } - -
- - -
-
-
-
-
-
-
-
24s Yüksek
-
24s Düşük
-
24s Hacim
-
- -
-
-
- - +{% include "_header.html" %} + + +
+ + +
+ + +
+
24s Yüksek
+
+
24s Düşük
+
+
24s Hacim
+
+ +
+
+ A: + Y: + D: + K:
-
- +
- -
+ +
- -
-
- Bot Ayarları - ✓ Kaydedildi +
+
+ Açık Pozisyonlar + 0
-
-
- - -
-
-
- - -
-
- - -
-
- +
+ + + +
ZamanAlışHedefAdet
- -
-
Pozisyonlar
-
-
Açık
-
Kapalı
+
+
+ Kapalı İşlemler + 0
-
-
Yükleniyor...
+
+ + + +
ZamanAlışSatışSonuç
- +
-
- -
- A: - Y: - D: - K: -
-
- -
-
+
Canlı Log
- +
+ +
+ + +
+ Durduruldu + + +
+ + +
+ Bot Ayarları + +
+
+
+ + +
+
+
+ + +
+
+ + +
+
+ +
+ + +
İstatistikler
+
+
Toplam İşlem
+
Kazanılan
+
Kaybedilen
+
Açık Pozisyon
+
Sembol
+
Timeframe
+
+ +
+