feat: add 5 dashboard features — dark mode, trade history, backtests, model insights, alerts

- Dark mode: class-based theme toggle with localStorage persistence and flash prevention
- Trade History (/trades): paginated table, stats cards, equity curve chart with DB API endpoints
- Backtest Viewer (/backtests): log parser for 35 backtest results, sidebar + detail + comparison tabs
- Model Insights: dashboard card + dialog showing feature importance, regime distribution, training history
- Alert/Signal Log (/alerts): signal stats, filterable table with execution tracking
- API: 8 new endpoints with psycopg2 DB connection pool
- Dark mode sweep across books page, about dialog, and all dashboard components
- Architecture docs rewritten with Mermaid diagrams (23 docs)
- README and FEATURES.md rewritten bilingual (Indonesian + English)
- main_live.py: write model_metrics.json on startup and retrain

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
GifariKemal
2026-02-09 05:46:54 +07:00
co-authored by Claude Opus 4.6
parent b2dc2dacd7
commit e8355b3f62
230 changed files with 69573 additions and 5673 deletions
+151 -204
View File
@@ -1,13 +1,37 @@
# Analisis Kelemahan Sistem Trading Bot
# Analisis Kelemahan Sistem — *Weakness Analysis*
## Tanggal Analisis: 6 Februari 2026
## Tanggal Analisis Awal: 6 Februari 2026
## Terakhir Diperbarui: 8 Februari 2026
---
## 1. STOP LOSS - KELEMAHAN KRITIS
## Status Perbaikan
### 1.1 Tidak Ada Broker Stop Loss
**File:** `main_live.py` line 876
```mermaid
pie title Status Kelemahan (8 Item Asli)
"Sudah Diperbaiki" : 6
"Sebagian Diperbaiki" : 1
"Masih Terbuka" : 1
```
| # | Item | Status | Tanggal Fix |
|---|------|--------|-------------|
| 1 | *Broker* SL | **DIPERBAIKI** | 7 Feb 2026 |
| 2 | ATR-*based* SL | **DIPERBAIKI** | 7 Feb 2026 |
| 3 | *Faster reversal exit* | **DIPERBAIKI** | 7 Feb 2026 |
| 4 | *Time-based exit* | **DIPERBAIKI** | 7 Feb 2026 |
| 5 | *Dynamic* ML *threshold* | **DIPERBAIKI** | 7 Feb 2026 |
| 6 | *Breakeven logic* | **DIPERBAIKI** | 7 Feb 2026 |
| 7 | *Partial* TP | Sebagian (*Smart TP* 4 level) | 7 Feb 2026 |
| 8 | *Backtest sync* | Masih terbuka | — |
---
## 1. STOP LOSS — ~~KELEMAHAN KRITIS~~ DIPERBAIKI
### 1.1 ~~Tidak Ada *Broker Stop Loss*~~ — DIPERBAIKI
**Sebelum:**
```python
result = self.mt5.send_order(
sl=0, # MASALAH: Tidak ada SL di broker!
@@ -15,98 +39,63 @@ result = self.mt5.send_order(
)
```
**Risiko:**
- Gap weekend = loss unlimited
- Flash crash = posisi tidak terproteksi
- Disconnect internet = loss tidak terkontrol
**Solusi:**
**Sesudah (sistem saat ini):**
```python
# Hitung emergency SL berdasarkan ATR
atr = df["atr"].tail(1).item()
emergency_sl = entry_price - (3.0 * atr) if direction == "BUY" else entry_price + (3.0 * atr)
result = self.mt5.send_order(
sl=emergency_sl, # BROKER-LEVEL PROTECTION
sl=emergency_sl, # BROKER-LEVEL PROTECTION — aktif!
tp=signal.take_profit,
)
```
### 1.2 Smart Hold Terlalu Agresif
**File:** `smart_risk_manager.py` line 460-486
**Status:** SL dikirim ke *broker* sebagai proteksi darurat. Jika koneksi internet terputus, **SL di *broker* tetap aktif**.
### 1.2 ~~*Smart Hold* Terlalu Agresif~~ — DIHAPUS
**Status:** Fitur *Smart Hold* telah **dihapus** dari sistem. *Smart Hold* dianggap berbahaya karena perilakunya mirip *martingale* — menahan posisi rugi dengan harapan harga berbalik.
### 1.3 ~~SL Berbasis *Swing* Terlalu Dekat~~ — DIPERBAIKI
**Sesudah (v4 — sistem saat ini):**
```python
# Tahan loss $15 selama 3 jam menunggu golden time
if loss_percent_of_max < 30 and hours_to_golden <= 3 and momentum > -50:
return False, None, f"SMART HOLD..."
```
**Risiko:**
- Loss $15 bisa jadi $30 dalam 3 jam
- Momentum -50 masih terlalu lemah sebagai threshold
**Solusi:**
- Kurangi max hold time ke 1 jam
- Naikkan momentum threshold ke -30
- Exit jika loss > 40% max (bukan 50%)
### 1.3 SL Berbasis Swing Terlalu Dekat
**File:** `smc_polars.py` line 639-640
```python
sl = last_swing_low if last_swing_low and last_swing_low < entry else entry * 0.995
# Entry 2000, fallback SL = 1990 (hanya 10 pips!)
```
**Risiko:**
- Volatilitas normal XAUUSD = 10-20 pips
- SL 10 pips = kena stop oleh noise
**Solusi:**
```python
# Minimum SL = 1.5 * ATR
# SL sekarang menggunakan ATR-based minimum
atr = df["atr"].tail(1).item()
min_sl_distance = 1.5 * atr
min_sl_distance = 1.5 * atr # Minimum SL = 1.5 * ATR
if direction == "BUY":
swing_sl = last_swing_low
atr_sl = entry - min_sl_distance
sl = min(swing_sl, atr_sl) if swing_sl else atr_sl
sl = min(swing_sl, atr_sl) # Pilih yang LEBIH JAUH (lebih aman)
if entry - sl < min_sl_distance:
sl = entry - min_sl_distance # Enforce jarak minimum
```
**Status:** SL sekarang MIN(*swing*, 1.5×ATR) dengan jarak minimum yang di-*enforce*.
---
## 2. TAKE PROFIT - KELEMAHAN
## 2. TAKE PROFIT — SEBAGIAN DIPERBAIKI
### 2.1 TP Fixed 2:1 RR
**File:** `smc_polars.py` line 643-644
### 2.1 ~~TP *Fixed* 2:1 RR~~ — DIPERBAIKI
**Sesudah:**
- TP menggunakan **ENFORCED minimum 1:2 R:R** — sinyal ditolak jika RR < 2.0
- *Smart Take Profit* memiliki **4 level exit** berdasarkan profit:
- Level 1: $15 — mulai pertimbangkan *take profit*
- Level 2: $25 — level profit bagus
- Level 3: $40 — *hard take profit*
- Level 4: *Peak profit declining* — profit turun dari puncak
### 2.2 Tidak Ada *Partial Take Profit* — SEBAGIAN
**Status:** Sistem tidak memiliki *partial close* yang sebenarnya (tutup 25%/50%/75% posisi), tetapi *Smart TP* dengan 4 level sudah memberikan mekanisme serupa — posisi ditutup seluruhnya pada level profit yang optimal berdasarkan kondisi pasar.
**Saran ke depan:**
```python
risk = entry - sl
tp = entry + (risk * 2)
```
**Masalah:**
- Tidak cek apakah TP di zona resistance
- TP bisa 100+ pips, tidak realistis
**Solusi:**
```python
# TP berdasarkan ATR dan struktur market
atr = df["atr"].tail(1).item()
max_tp_distance = 4.0 * atr # Maximum 4 ATR
# Cek resistance terdekat
nearest_resistance = find_nearest_resistance(df, entry)
# TP = minimum dari RR target atau resistance
rr_tp = entry + (risk * 2)
tp = min(rr_tp, entry + max_tp_distance)
if nearest_resistance and nearest_resistance < tp:
tp = nearest_resistance * 0.995 # Sedikit di bawah resistance
```
### 2.2 Tidak Ada Partial Take Profit
**Solusi:**
```python
# Partial TP levels
# Partial TP levels (belum diimplementasikan)
tp_25 = entry + (risk * 0.5) # 25% posisi di 0.5 RR
tp_50 = entry + (risk * 1.0) # 25% posisi di 1.0 RR
tp_75 = entry + (risk * 1.5) # 25% posisi di 1.5 RR
@@ -115,125 +104,79 @@ tp_100 = entry + (risk * 2.0) # 25% posisi di 2.0 RR
---
## 3. ENTRY TRADE - KELEMAHAN
## 3. ENTRY TRADE — DIPERBAIKI
### 3.1 ML Threshold 50% = Coin Flip
**File:** `main_live.py` line 723
```python
ml_min_threshold = 0.50
```
### 3.1 ~~ML *Threshold* 50% = *Coin Flip*~~ — DIPERBAIKI
**Masalah:**
- 50% confidence = tidak lebih baik dari random
- Seharusnya dinamis per session
**Sesudah (sistem saat ini):**
- `DynamicConfidenceManager` menyesuaikan *threshold* secara otomatis:
**Solusi:**
```python
# Dynamic threshold berdasarkan session
if session == "Sydney":
ml_min_threshold = 0.60 # Low liquidity = butuh confidence tinggi
elif session == "London-NY Overlap":
ml_min_threshold = 0.50 # High quality = threshold lebih rendah OK
else:
ml_min_threshold = 0.55 # Default
```
| Kondisi Pasar | *Threshold* | Alasan |
|---------------|-------------|--------|
| *Trending* kuat | **0.65** | Sinyal lebih jelas, *threshold* lebih rendah |
| Normal | **0.70** | *Default* standar |
| Bergejolak | **0.75** | Butuh kepastian lebih tinggi |
### 3.2 Signal Key Reset Terus
**File:** `main_live.py` line 733
```python
signal_key = f"{smc_signal.signal_type}_{int(smc_signal.entry_price):.0f}"
# Entry price berubah setiap candle = signal key selalu baru!
```
### 3.2 *Signal Key Reset* Terus — MASIH ADA (Risiko Rendah)
**Solusi:**
```python
# Gunakan zone-based key, bukan exact price
zone_size = 5 # $5 zone
zone = int(smc_signal.entry_price / zone_size) * zone_size
signal_key = f"{smc_signal.signal_type}_{zone}"
```
**Status:** *Signal key* masih menggunakan `int(entry_price)`, yang bisa berubah antar candle. Risiko rendah karena *cooldown* 5 menit sudah mencegah duplikasi *trade*.
### 3.3 Pullback Filter Fixed $2
**File:** `main_live.py` line 673
```python
if momentum_direction == "UP" and short_momentum > 2: # Fixed $2
```
### 3.3 ~~*Pullback Filter Fixed* $2~~ — TIDAK RELEVAN
**Solusi:**
```python
# ATR-based threshold
atr = df["atr"].tail(1).item()
pullback_threshold = 0.5 * atr # 50% of ATR
if momentum_direction == "UP" and short_momentum > pullback_threshold:
return False, "SELL blocked: Price bouncing"
```
**Status:** *Pullback Filter* dinonaktifkan (SMC-only mode). Sistem menggunakan **14 *entry filter*** lain yang lebih robust.
---
## 4. EXIT TRADE - KELEMAHAN
## 4. EXIT TRADE — DIPERBAIKI
### 4.1 ML Reversal Butuh 75% Confidence
**File:** `smart_risk_manager.py` line 441
### 4.1 ~~ML *Reversal* Butuh 75% *Confidence*~~ — DIPERBAIKI
**Status:** Sistem sekarang memiliki **12 kondisi *exit*** termasuk:
- *Early Cut* — momentum negatif, tidak menunggu ML *confidence* tinggi
- *Trend Reversal* — ML mendeteksi pembalikan
- *Stall Detection* — harga *stuck* terlalu lama
### 4.2 ~~Tidak Ada *Time-Based Exit*~~ — DIPERBAIKI
**Sesudah:**
```python
if ml_confidence >= 0.75 and ml_is_reversal:
return True, ExitReason.TREND_REVERSAL
```
**Masalah:**
- Terlalu tinggi, sering sudah telat
- Harga sudah bergerak jauh saat ML 75%
**Solusi:**
```python
# Lower threshold dengan tambahan konfirmasi
if ml_confidence >= 0.65 and ml_is_reversal:
if momentum_score < -30: # Momentum juga negatif
return True, ExitReason.TREND_REVERSAL
```
### 4.2 Tidak Ada Time-Based Exit
**Solusi:**
```python
# Exit jika trade stuck terlalu lama
trade_duration = (datetime.now() - entry_time).total_seconds() / 3600 # hours
# Time-based exit sudah aktif
# 4-8 jam maximum duration per trade
trade_duration = (datetime.now() - entry_time).total_seconds() / 3600
if trade_duration > 4 and abs(current_profit) < 5: # 4 jam tanpa progress
return True, ExitReason.TIMEOUT, "Trade stuck > 4 hours"
if trade_duration > 6: # Maximum 6 jam
return True, ExitReason.TIMEOUT, "Maximum duration reached"
return True, ExitReason.TIMEOUT
if trade_duration > 8: # Maximum 8 jam
return True, ExitReason.TIMEOUT
```
### 4.3 Tidak Ada Breakeven Protection
**Solusi:**
```python
# Move to breakeven setelah profit tertentu
if current_profit >= 15: # $15 profit
if not breakeven_set:
move_sl_to_breakeven(ticket)
breakeven_set = True
```
### 4.3 ~~Tidak Ada *Breakeven Protection*~~ — DIPERBAIKI
**Sesudah:**
- *Breakeven Protection* aktif sebagai **kondisi *exit* #11**
- *Smart Breakeven* (#28B) — pindah SL ke *breakeven* setelah profit tertentu tercapai
- *Trailing Stop Loss* juga aktif sebagai kondisi *exit* #10
---
## 5. BACKTEST vs LIVE - PERBEDAAN
## 5. *BACKTEST* vs *LIVE* — MASIH TERBUKA
### 5.1 Exit Timing Berbeda
| Aspek | Backtest | Live |
|-------|----------|------|
| Check interval | Per bar (15 min) | Per detik |
| ML reversal check | Setiap 5 bar | Setiap loop |
| Smart Hold | Tidak ada | Ada |
### 5.1 *Exit Timing* Berbeda
**Solusi:**
- Sinkronkan logic di `backtest_live_sync.py`
- Tambah Smart Hold logic ke backtest
- Gunakan bar-close sebagai trigger
| Aspek | *Backtest* | *Live* |
|-------|------------|--------|
| *Check interval* | Per bar (15 min) | Per 10 detik |
| ML *reversal check* | Setiap 5 bar | Setiap *loop* |
| *Smart Hold* | Tidak ada | **Dihapus juga** |
### 5.2 Slippage Tidak Dihitung
**Status:** `backtest_live_sync.py` disinkronkan dengan `main_live.py`, tetapi perbedaan *timing* (bar-based vs real-time) tetap ada dan tidak bisa dihilangkan sepenuhnya.
### 5.2 *Slippage* Tidak Dihitung
**Status:** Masih belum ada simulasi *slippage* di *backtest*. Ini bisa menyebabkan *backtest* terlalu optimis.
**Saran:**
```python
# Tambah slippage simulation
SLIPPAGE_PIPS = 0.5 # 0.5 pip slippage
def simulate_entry(entry_price, direction):
@@ -245,47 +188,51 @@ def simulate_entry(entry_price, direction):
---
## 6. PRIORITAS PERBAIKAN
## 6. PRIORITAS PERBAIKAN (DIPERBARUI)
| # | Item | Risiko | Effort | Prioritas |
|---|------|--------|--------|-----------|
| 1 | Broker SL | KRITIS | Low | **P0** |
| 2 | ATR-based SL | TINGGI | Medium | **P1** |
| 3 | Faster reversal exit | TINGGI | Low | **P1** |
| 4 | Time-based exit | SEDANG | Low | **P2** |
| 5 | Dynamic ML threshold | SEDANG | Low | **P2** |
| 6 | Partial TP | SEDANG | Medium | **P3** |
| 7 | Breakeven logic | SEDANG | Low | **P3** |
| 8 | Backtest sync | SEDANG | High | **P3** |
| # | Item | Status | Prioritas |
|---|------|--------|-----------|
| 1 | *Broker* SL | **SELESAI** | ~~P0~~ |
| 2 | ATR-*based* SL | **SELESAI** | ~~P1~~ |
| 3 | *Faster reversal exit* | **SELESAI** | ~~P1~~ |
| 4 | *Time-based exit* | **SELESAI** | ~~P2~~ |
| 5 | *Dynamic* ML *threshold* | **SELESAI** | ~~P2~~ |
| 6 | *Breakeven logic* | **SELESAI** | ~~P3~~ |
| 7 | *Partial* TP | Sebagian | **P3** |
| 8 | *Backtest sync* (*slippage*) | Terbuka | **P3** |
---
## 7. SKENARIO TERBURUK
## 7. SKENARIO TERBURUK — MITIGASI
### Skenario 1: Weekend Gap
- Jumat: Posisi BUY di 2000, profit $10
- Weekend: Berita ekonomi buruk
- Senin: Market buka di 1950 (-50 pips = -$50)
- **Tanpa broker SL = loss unlimited**
### Skenario 1: *Weekend Gap*
- **Sebelum:** Loss *unlimited* tanpa SL di *broker*
- **Sesudah:** *Broker* SL (3× ATR) melindungi posisi. Juga ada *weekend close* — bot menutup semua posisi sebelum penutupan *weekend*
### Skenario 2: Flash Crash
- Posisi aktif, harga normal
- Flash crash -2% dalam 1 menit
- Bot detect, tapi close gagal (broker overload)
- **Tanpa broker SL = loss unlimited**
### Skenario 2: *Flash Crash*
- **Sebelum:** *Flash crash* = posisi tidak terproteksi
- **Sesudah:** *Flash Crash Guard* (filter #12) mendeteksi pergerakan >2.5% dalam 1 menit dan **menghentikan semua trading + menutup posisi**
### Skenario 3: Connection Lost
- Posisi aktif dengan profit $20
- Internet mati 2 jam
- Market reversal -$60
- **Tanpa broker SL = loss unlimited**
### Skenario 3: *Connection Lost*
- **Sebelum:** Tanpa *broker* SL = loss *unlimited*
- **Sesudah:** *Broker* SL (3× ATR) tetap aktif di *server broker* meskipun koneksi internet terputus
---
## 8. IMPLEMENTASI SEGERA
## 8. KELEMAHAN BARU YANG TERIDENTIFIKASI
File yang perlu diubah:
1. `main_live.py` - Tambah broker SL
2. `smc_polars.py` - ATR-based SL
3. `smart_risk_manager.py` - Faster exit, time-based exit
4. `backtest_live_sync.py` - Sinkronkan dengan live
### 8.1 *News Agent* Nonaktif
- Bot tidak memfilter berita berdampak tinggi (NFP, FOMC, CPI)
- *Session Filter* sudah memiliki daftar waktu berita, tapi *News Agent* yang mengambil data *real-time* dinonaktifkan
- **Risiko:** Pasar bisa sangat *volatile* saat berita besar
- **Mitigasi:** ML model dan HMM *regime detector* sudah menangani volatilitas ($178 lebih baik tanpa *News Agent*)
### 8.2 Tidak Ada *Partial Close*
- Posisi selalu ditutup 100% — tidak ada opsi tutup sebagian
- **Risiko:** Kehilangan potensi profit jika harga terus bergerak setelah *take profit*
- **Prioritas:** P3 (nice to have)
### 8.3 *Single Symbol* (XAUUSD)
- Bot hanya trading satu instrumen
- **Risiko:** Bergantung sepenuhnya pada kondisi pasar emas
- **Mitigasi:** XAUUSD adalah instrumen paling *liquid* dan *volatile*, cocok untuk *scalping* M15