feat: Smart AI Trading Bot for XAUUSD with ML and SMC

- XGBoost ML model with 37 features for market direction prediction
- Smart Money Concepts (SMC): Order Blocks, FVG, BOS, CHoCH
- HMM market regime detection (trending/ranging/volatile)
- ATR-based stop loss with 1.5 ATR minimum distance
- Broker-level SL protection with fallback
- Time-based exit (max 6 hours per trade)
- Session-aware trading optimized for London/NY overlap
- Auto-retraining based on market conditions
- Telegram notifications and web dashboard
- Backtest results: 63.9% win rate, 2.64 profit factor, 4.83 Sharpe

Backtest period: Jan 2025 - Feb 2026, 654 trades, $4,189 net P/L

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
GifariKemal
2026-02-06 09:01:35 +07:00
co-authored by Claude Opus 4.5
commit 7af9183af3
121 changed files with 43387 additions and 0 deletions
@@ -0,0 +1,198 @@
# HMM (Hidden Markov Model) — Regime Detector
> **File:** `src/regime_detector.py`
> **Model:** `models/hmm_regime.pkl`
> **Library:** `hmmlearn.GaussianHMM`
---
## Apa Itu HMM?
Hidden Markov Model adalah model statistik yang mendeteksi **"hidden state" (kondisi tersembunyi)** dari data yang terlihat. Dalam konteks trading, HMM membaca pola volatilitas dan return harga untuk mengklasifikasikan **kondisi pasar saat ini**.
**Analogi:** HMM adalah **radar cuaca** untuk pasar — menentukan apakah pasar sedang cerah, mendung, atau badai.
---
## Fungsi Utama
HMM bertugas **mengklasifikasikan kondisi pasar** ke dalam 3 regime:
| Regime | Nama | Aksi Trading | Lot Multiplier |
|--------|------|-------------|----------------|
| 0 | `LOW_VOLATILITY` | Trade normal | 1.0x |
| 1 | `MEDIUM_VOLATILITY` | Trade normal | 1.0x |
| 2 | `HIGH_VOLATILITY` | Kurangi lot | 0.5x |
| - | `CRISIS` | Stop trading | 0.0x |
---
## Arsitektur Model
```python
GaussianHMM(
n_components=3, # 3 regime (low/medium/high volatility)
covariance_type="diag", # Diagonal covariance (stabil)
n_iter=200, # Iterasi training
random_state=42,
)
```
**Konfigurasi** (`config.py`):
```
n_regimes = 3 # Jumlah regime
lookback_periods = 500 # Bar untuk training
retrain_frequency = 20 # Retrain setiap 20 bar
```
---
## Input (Fitur)
HMM hanya menggunakan **2 fitur sederhana**:
| Fitur | Formula | Fungsi |
|-------|---------|--------|
| **Log Returns** | `ln(close[t] / close[t-1])` | Momentum & arah harga |
| **Rolling Volatility** | `StdDev(log_returns, 20)` | Gejolak pasar 20 bar |
**Kenapa hanya 2?** HMM bekerja optimal dengan fitur sedikit tapi representatif. Dua fitur ini sudah cukup menangkap pola volatilitas pasar.
---
## Cara Kerja
### Proses Prediksi (Setiap Loop)
```
200 bar M15 terakhir dari MT5
|
v
prepare_features()
- Hitung log_returns = ln(close[t] / close[t-1])
- Hitung rolling volatility = StdDev(20 bar)
|
v
model.predict(features)
- Output: regime per bar (0, 1, atau 2)
|
v
model.predict_proba(features)
- Output: probabilitas tiap regime (0-1)
|
v
Mapping ke nama regime:
- Sort berdasarkan volatilitas
- Volatilitas terendah = LOW_VOLATILITY
- Volatilitas tertinggi = HIGH_VOLATILITY
|
v
Output per bar:
- regime: 0/1/2
- regime_name: "low_volatility" / "medium_volatility" / "high_volatility"
- regime_confidence: 0.0 - 1.0
```
### Proses Training
```
1. Ambil 10,000 bar M15 XAUUSD dari MT5
2. Hitung fitur: log_returns + volatility
3. Fit GaussianHMM dengan 3 komponen
-> Model belajar transition probability antar regime
-> Model belajar emission probability (pola tiap state)
4. Map state ke nama regime berdasarkan sorting volatilitas
5. Simpan ke models/hmm_regime.pkl
```
---
## Output & Dampak ke Trading
### 1. Position Size Multiplier
```python
get_position_multiplier(regime):
LOW_VOLATILITY -> 1.0x (lot penuh)
MEDIUM_VOLATILITY -> 1.0x (lot penuh)
HIGH_VOLATILITY -> 0.5x (lot setengah)
CRISIS -> 0.0x (tidak trading)
# Contoh:
base_lot = 0.02
actual_lot = base_lot * multiplier
# HIGH_VOL: 0.02 * 0.5 = 0.01
```
### 2. Trading Gate
```
if regime == CRISIS:
return None # STOP — tidak boleh trading sama sekali
```
### 3. Fitur Input untuk XGBoost
Kolom `regime` (0/1/2) juga dikirim sebagai salah satu dari 24 fitur XGBoost, sehingga model ML tahu kondisi pasar saat membuat prediksi.
---
## Transition Matrix
HMM menghasilkan **matriks transisi** yang menunjukkan probabilitas perpindahan antar regime:
```
Ke:
Dari: LOW MED HIGH
LOW [ 0.85 0.12 0.03 ] <- 85% tetap low
MED [ 0.10 0.78 0.12 ] <- 78% tetap medium
HIGH [ 0.05 0.15 0.80 ] <- 80% tetap high
```
**Kegunaan:** Memprediksi seberapa lama regime saat ini akan bertahan.
---
## Auto-Retraining
- **Jadwal:** Harian pukul 05:00 WIB (saat pasar tutup)
- **Data:** 5,000 bar terakhir
- **Validasi:** Jika log-likelihood terlalu rendah, rollback ke model lama
- **Backup:** Model lama disimpan di `models/backups/[timestamp]/`
---
## Metrik Evaluasi
```python
{
"samples": 10000, # Bar yang digunakan
"n_regimes": 3, # Jumlah state
"log_likelihood": -1234.5, # Kualitas fit (makin tinggi makin baik)
}
```
---
## Contoh Skenario
**Skenario 1: Pasar tenang**
```
Input: Volatilitas rendah, return stabil
Output: regime=0 (LOW_VOLATILITY), confidence=0.92
Aksi: Trading normal, lot penuh (1.0x)
```
**Skenario 2: Volatilitas melonjak (berita NFP)**
```
Input: Volatilitas tinggi, return besar
Output: regime=2 (HIGH_VOLATILITY), confidence=0.88
Aksi: Lot dikurangi 50% (0.5x), melindungi modal
```
**Skenario 3: Flash crash**
```
Input: Volatilitas ekstrem, return sangat besar
Output: regime=CRISIS, confidence=0.95
Aksi: STOP trading — 0% lot, lindungi akun
```
@@ -0,0 +1,245 @@
# XGBoost — Signal Predictor
> **File:** `src/ml_model.py`
> **Model:** `models/xgboost_model.pkl`
> **Library:** `xgboost`
---
## Apa Itu XGBoost?
XGBoost (eXtreme Gradient Boosting) adalah algoritma machine learning berbasis **ensemble decision tree**. Model ini belajar dari puluhan fitur teknikal untuk **memprediksi arah harga** di bar berikutnya.
**Analogi:** XGBoost adalah **navigator AI** — menentukan apakah harga akan naik atau turun.
---
## Fungsi Utama
XGBoost bertugas **memprediksi probabilitas harga naik atau turun** di bar M15 berikutnya, lalu menghasilkan signal BUY, SELL, atau HOLD.
```
prob_up > 0.65 -> BUY
prob_down > 0.65 -> SELL
lainnya -> HOLD (tidak cukup yakin)
```
---
## Arsitektur Model
```python
params = {
"objective": "binary:logistic", # Klasifikasi biner (naik/turun)
"eval_metric": "auc", # Area Under Curve
"max_depth": 3, # Kedalaman tree (anti-overfitting)
"learning_rate": 0.05, # Lambat & stabil
"min_child_weight": 10, # Minimum sampel per leaf
"subsample": 0.7, # 70% data per round
"colsample_bytree": 0.6, # 60% fitur per tree
"reg_alpha": 1.0, # L1 regularization
"reg_lambda": 5.0, # L2 regularization (kuat)
"gamma": 1.0, # Min loss reduction per split
}
```
**Anti-Overfitting:**
- Tree dangkal (depth 3, bukan 6)
- Early stopping setelah 5 round tanpa improvement
- Feature subsampling 60%
- Regularisasi L2 kuat (lambda=5.0)
---
## Input (24 Fitur)
### Indikator Teknikal
| Fitur | Sumber | Fungsi |
|-------|--------|--------|
| `rsi` | Feature Eng | Overbought/oversold |
| `atr`, `atr_percent` | Feature Eng | Volatilitas |
| `macd`, `macd_signal`, `macd_histogram` | Feature Eng | Momentum tren |
| `bb_percent_b`, `bb_width` | Feature Eng | Posisi dalam Bollinger Band |
| `ema_9`, `ema_21` | Feature Eng | Tren jangka pendek |
### Returns & Momentum
| Fitur | Formula | Fungsi |
|-------|---------|--------|
| `returns_1` | `close[t]/close[t-1] - 1` | Return 1 bar |
| `returns_5` | `close[t]/close[t-5] - 1` | Return 5 bar |
| `returns_20` | `close[t]/close[t-20] - 1` | Return 20 bar |
| `log_returns` | `ln(close[t]/close[t-1])` | Log return |
### Volatilitas & Posisi Harga
| Fitur | Fungsi |
|-------|--------|
| `volatility_20` | Realized volatility 20 bar |
| `normalized_range` | (High-Low)/Close |
| `avg_normalized_range` | Rata-rata range 14 bar |
| `price_position` | Posisi 0-1 dalam range |
| `dist_from_sma_20` | Jarak dari SMA 20 |
### Smart Money Concepts (SMC)
| Fitur | Fungsi |
|-------|--------|
| `swing_high`, `swing_low` | Fractal structure |
| `fvg_signal` | Fair Value Gap (1/-1/0) |
| `ob` | Order Block (1/-1/0) |
| `bos`, `choch` | Break of Structure, Change of Character |
| `market_structure` | Bullish/Bearish (1/-1/0) |
### Waktu & Regime
| Fitur | Fungsi |
|-------|--------|
| `hour`, `weekday` | Pola jam & hari |
| `london_session`, `ny_session` | Flag sesi trading |
| `regime` | HMM regime state (0/1/2) |
---
## Cara Kerja
### Proses Prediksi (Setiap Loop)
```
DataFrame lengkap (200 bar + semua fitur)
|
v
Ambil baris terakhir (1 bar)
|
v
Pilih 24 fitur yang sesuai dengan training
|
v
Buat DMatrix (format XGBoost)
|
v
model.predict() -> probabilitas harga NAIK (0-1)
|
v
Tentukan signal:
prob_up > 0.65 -> BUY
prob_down > 0.65 -> SELL
lainnya -> HOLD
|
v
Output: PredictionResult
- signal: "BUY" / "SELL" / "HOLD"
- probability: 0-1 (prob naik)
- confidence: max(prob_up, prob_down)
- feature_importance: {fitur: skor}
```
### Proses Training
```
1. Ambil 10,000 bar M15 XAUUSD
2. Feature engineering (40+ kolom)
3. SMC analysis (swing, FVG, OB, BOS, CHoCH)
4. Buat target: 1 jika close[t+1] > close[t], else 0
5. Split: 70% train, 30% test
6. Train XGBoost 50 round + early stopping (patience=5)
7. Evaluasi: Train AUC vs Test AUC
8. Simpan model + feature names ke .pkl
```
---
## Output & Dampak ke Trading
### 1. Validasi Signal SMC
```
SMC bilang BUY + XGBoost setuju (>55%) -> TRADE
SMC bilang BUY + XGBoost netral (<55%) -> SKIP
SMC bilang BUY + XGBoost bilang SELL >75% -> TOLAK (veto)
```
### 2. Confidence Gate
```
ML confidence < 55% -> Tidak boleh entry (terlalu tidak yakin)
ML confidence 55-65% -> Entry dengan lot kecil
ML confidence > 65% -> Entry dengan lot penuh
```
### 3. Exit Signal (Penutupan Posisi)
```
Posisi BUY terbuka
XGBoost prediksi SELL dengan confidence > 75%
-> TUTUP posisi (ML reversal exit)
```
### 4. Feature Importance
```python
# Contoh output (top 5)
{
"market_structure": 0.85, # Fitur paling penting
"rsi": 0.68,
"atr_percent": 0.65,
"macd_histogram": 0.52,
"bos": 0.48,
}
```
Menunjukkan fitur mana yang paling berpengaruh dalam keputusan model.
---
## Metrik Evaluasi
```python
{
"train_auc": 0.6234, # Performa di data training
"test_auc": 0.5932, # Performa di data testing
"train_samples": 7000,
"test_samples": 3000,
"num_features": 24,
}
```
| AUC | Interpretasi |
|-----|-------------|
| 0.50 | Sama dengan tebak acak |
| 0.55 | Sedikit lebih baik dari acak |
| 0.60 | Cukup baik untuk trading |
| 0.70+ | Sangat baik |
**Rollback threshold:** Jika test AUC < 0.52, model otomatis rollback ke versi sebelumnya.
---
## Auto-Retraining
- **Jadwal:** Harian pukul 05:00 WIB
- **Data:** 5,000 bar terakhir
- **Proses:** Backup lama -> retrain -> validasi AUC -> simpan/rollback
- **Minimum interval:** 20 jam antar retrain (cegah overfitting)
---
## Contoh Skenario
**Skenario 1: Signal kuat**
```
RSI=35 (oversold), MACD rising, BOS bullish, market_structure=1
-> XGBoost: prob_up=0.78 -> BUY (confidence 78%)
-> Lot penuh, entry dieksekusi
```
**Skenario 2: Konflik dengan SMC**
```
SMC signal: BUY
XGBoost: prob_down=0.82 -> SELL (confidence 82%)
-> Signal DITOLAK (ML strongly disagrees >75%)
-> Tidak ada trade
```
**Skenario 3: Tidak yakin**
```
RSI=50, MACD flat, regime=1
-> XGBoost: prob_up=0.53 -> HOLD (confidence 53% < 55%)
-> Tidak ada trade — tunggu signal lebih jelas
```
+403
View File
@@ -0,0 +1,403 @@
# SMC Analyzer (Smart Money Concepts)
> **File:** `src/smc_polars.py`
> **Framework:** Pure Polars (vectorized, tanpa loop)
---
## Apa Itu SMC?
Smart Money Concepts adalah metode analisis berdasarkan **cara institusi besar (bank, hedge fund) trading**. SMC membaca **struktur pasar** dan **jejak uang besar** untuk menemukan zona entry yang presisi.
**Analogi:** SMC adalah **peta jalan** — menunjukkan zona penting, rambu lalu lintas, dan rute terbaik.
---
## 6 Konsep yang Diimplementasikan
| # | Konsep | Fungsi | Lines |
|---|--------|--------|-------|
| 1 | Swing Points | Puncak & lembah penting | 185-261 |
| 2 | Fair Value Gap (FVG) | Imbalance/gap harga | 84-183 |
| 3 | Order Block (OB) | Zona order institusi | 263-368 |
| 4 | Break of Structure (BOS) | Kelanjutan tren | 370-457 |
| 5 | Change of Character (CHoCH) | Pembalikan tren | 370-457 |
| 6 | Liquidity Zones | Kumpulan stop loss | 459-551 |
---
## 1. Swing Points (Fractal High/Low)
**Fungsi:** Mendeteksi puncak dan lembah penting di chart.
### Algoritma
```
Window: 2 x swing_length + 1 = 11 candle (default swing_length=5)
Swing High: High saat ini = Maximum dalam 11 candle
Swing Low: Low saat ini = Minimum dalam 11 candle
```
### Visualisasi
```
/\ <- Swing High (high = max 11 candle)
/ \
/ \
/ \
/ \/ <- Swing Low (low = min 11 candle)
/
```
### Output
| Kolom | Nilai | Keterangan |
|-------|-------|-----------|
| `swing_high` | 1 / 0 | 1 jika swing high |
| `swing_low` | -1 / 0 | -1 jika swing low |
| `swing_high_level` | float | Harga di swing high |
| `swing_low_level` | float | Harga di swing low |
| `last_swing_high` | float | Swing high terakhir (forward fill) |
| `last_swing_low` | float | Swing low terakhir (forward fill) |
---
## 2. Fair Value Gap (FVG)
**Fungsi:** Mendeteksi **imbalance/gap** di harga — zona yang belum "diisi" oleh pasar.
### Algoritma
```
Bullish FVG: Bearish FVG:
Candle T-2: ████ high Candle T-2: ████ low
| |
| GAP (celah) | GAP (celah)
| |
Candle T+1: ████ low Candle T+1: ████ high
Syarat Bullish: high[T-2] < low[T+1]
Syarat Bearish: low[T-2] > high[T+1]
```
### Zona FVG
```
Bullish FVG Zone:
Top = low[T+1] (batas atas gap)
Bottom = high[T-2] (batas bawah gap)
Mid = (top + bottom) / 2 (50% retracement)
```
### Output
| Kolom | Nilai | Keterangan |
|-------|-------|-----------|
| `fvg_signal` | 1 / -1 / 0 | Bullish / Bearish / Tidak ada |
| `fvg_top` | float | Batas atas gap |
| `fvg_bottom` | float | Batas bawah gap |
| `fvg_mid` | float | Titik tengah (target retracement) |
**Peran:** Zona entry ideal — harga cenderung **kembali mengisi gap** sebelum melanjutkan.
---
## 3. Order Block (OB)
**Fungsi:** Mendeteksi candle terakhir sebelum pergerakan besar — zona dimana institusi menaruh order.
### Algoritma
```
Bullish OB:
1. Temukan swing low
2. Lihat 10 candle ke belakang
3. Cari candle bearish terakhir (close < open)
4. Jika candle berikutnya close di atas high candle tersebut:
-> Candle itu = Bullish Order Block
Bearish OB:
1. Temukan swing high
2. Lihat 10 candle ke belakang
3. Cari candle bullish terakhir (close > open)
4. Jika candle berikutnya close di bawah low candle tersebut:
-> Candle itu = Bearish Order Block
```
### Visualisasi
```
Bullish OB: Bearish OB:
████ <- Bullish candle terakhir
████ <- Bearish candle terakhir sebelum jatuh
sebelum naik ═══════════════
═══════════════ ||| turun
||| naik
```
### Output
| Kolom | Nilai | Keterangan |
|-------|-------|-----------|
| `ob` | 1 / -1 / 0 | Bullish / Bearish / Tidak ada |
| `ob_top` | float | Batas atas zona OB |
| `ob_bottom` | float | Batas bawah zona OB |
| `ob_mitigated` | bool | True jika OB sudah dikunjungi ulang |
**Peran:** Zona support/resistance berdasarkan aksi institusi besar.
---
## 4. Break of Structure (BOS)
**Fungsi:** Mendeteksi **kelanjutan tren** — harga menembus swing point searah tren.
### Algoritma
```python
# Tren sudah BULLISH, lalu:
if close > last_swing_high:
bos = 1 # Bullish BOS — tren naik BERLANJUT
# Tren sudah BEARISH, lalu:
if close < last_swing_low:
bos = -1 # Bearish BOS — tren turun BERLANJUT
```
### Visualisasi
```
Bullish BOS:
SH1 SH2 (baru ditembus!)
/ \ / close >>>
/ \ /
/ SL1 -> BOS! Tren naik lanjut
Bearish BOS:
\ SH1
\ / \
\ / \ close <<<
SL1 SL2 (baru ditembus!) -> BOS! Tren turun lanjut
```
### Output
| Kolom | Nilai | Keterangan |
|-------|-------|-----------|
| `bos` | 1 / -1 / 0 | Bullish / Bearish / Tidak ada |
**Peran:** Konfirmasi bahwa **tren masih kuat** dan lanjut.
---
## 5. Change of Character (CHoCH)
**Fungsi:** Mendeteksi **pembalikan tren** — harga menembus swing point berlawanan tren.
### Algoritma
```python
# Tren sedang BEARISH, lalu:
if close > last_swing_high:
choch = 1 # Bullish CHoCH — REVERSAL naik!
# Tren sedang BULLISH, lalu:
if close < last_swing_low:
choch = -1 # Bearish CHoCH — REVERSAL turun!
```
### Visualisasi
```
Bearish CHoCH (tren naik -> balik turun):
SH <- gagal naik
/ \
/ \
/ close menembus SL >>> CHoCH! Reversal turun!
SL
Bullish CHoCH (tren turun -> balik naik):
SH
\ close menembus SH >>> CHoCH! Reversal naik!
\ /
\ /
SL <- gagal turun
```
### Output
| Kolom | Nilai | Keterangan |
|-------|-------|-----------|
| `choch` | 1 / -1 / 0 | Bullish / Bearish / Tidak ada |
| `market_structure` | 1 / -1 / 0 | Bullish / Bearish / Netral |
**Peran:** **Early warning** perubahan arah tren.
---
## 6. Liquidity Zones
**Fungsi:** Mendeteksi kumpulan stop loss (equal highs/lows) yang bisa "disapu" oleh institusi.
### Algoritma
```
1. Hitung rolling std & mean dari highs dan lows (window=20)
2. Coefficient of Variation = std / mean
3. Jika CV < 0.001 (0.1%):
-> Harga sangat mirip = cluster likuiditas
-> BSL (Buy Side Liquidity) = level high
-> SSL (Sell Side Liquidity) = level low
4. Deteksi sweep:
-> BSL sweep: High > BSL lalu close < BSL
-> SSL sweep: Low < SSL lalu close > SSL
```
### Visualisasi
```
Buy Side Liquidity (BSL): Sell Side Liquidity (SSL):
═══════ equal highs ═══════
████ ████ ████ ████ ████ ████ ████ ████
═══════ equal lows ═══════
^ Stop loss short sellers ^ Stop loss long traders
^ Institusi sweep ke atas ^ Institusi sweep ke bawah
```
### Output
| Kolom | Nilai | Keterangan |
|-------|-------|-----------|
| `bsl_level` | float | Level buy side liquidity |
| `ssl_level` | float | Level sell side liquidity |
| `liquidity_sweep` | "BSL" / "SSL" / None | Sweep terdeteksi |
---
## Signal Generation
### ATR-Based Dynamic SL/TP (v3 Update)
Sebelum menghitung SL dan TP, sistem mengambil nilai ATR untuk kalkulasi dinamis:
```python
# Line 631-634
atr = latest["atr"] # Dari Feature Engineering
min_sl_distance = 1.5 * atr # Minimum jarak SL = 1.5 ATR
max_tp_distance = 4.0 * atr # Maximum jarak TP = 4.0 ATR
# Fallback jika ATR tidak tersedia:
atr = current_close * 0.01 # 1% dari harga
```
### Kondisi Bullish Signal
```
IF (market_structure == BULLISH ATAU ada BOS/CHoCH bullish)
AND (ada FVG bullish ATAU Order Block bullish):
Entry = FVG bottom atau OB bottom
SL (v3 - ATR-based, lebih protektif):
swing_sl = last_swing_low (jika ada & di bawah entry)
atr_sl = entry - 1.5 * ATR
SL = MIN(swing_sl, atr_sl) <- pilih yang LEBIH JAUH
TP (v3 - dibatasi realistis):
risk = entry - SL
tp = entry + (risk * 2) <- minimum 2:1 RR
IF tp > entry + 4*ATR:
tp = entry + 4*ATR <- cap TP agar realistis
```
### Kondisi Bearish Signal
```
IF (market_structure == BEARISH ATAU ada BOS/CHoCH bearish)
AND (ada FVG bearish ATAU Order Block bearish):
Entry = FVG top atau OB top
SL (v3 - ATR-based, lebih protektif):
swing_sl = last_swing_high (jika ada & di atas entry)
atr_sl = entry + 1.5 * ATR
SL = MAX(swing_sl, atr_sl) <- pilih yang LEBIH JAUH
TP (v3 - dibatasi realistis):
risk = SL - entry
tp = entry - (risk * 2) <- minimum 2:1 RR
IF tp < entry - 4*ATR:
tp = entry - 4*ATR <- cap TP agar realistis
```
### Perbandingan SL/TP Lama vs Baru
```
┌────────────┬───────────────────────────┬──────────────────────────────┐
│ Komponen │ Sebelum (v2) │ Sesudah (v3) │
├────────────┼───────────────────────────┼──────────────────────────────┤
│ SL (BUY) │ swing_low atau │ MIN(swing_low, entry-1.5ATR) │
│ │ entry * 0.995 (bisa dekat)│ <- selalu cukup jauh │
├────────────┼───────────────────────────┼──────────────────────────────┤
│ SL (SELL) │ swing_high atau │ MAX(swing_high, entry+1.5ATR)│
│ │ entry * 1.005 (bisa dekat)│ <- selalu cukup jauh │
├────────────┼───────────────────────────┼──────────────────────────────┤
│ TP │ risk * 2 │ MIN(risk*2, 4*ATR) │
│ │ (bisa sangat jauh) │ <- dibatasi realistis │
└────────────┴───────────────────────────┴──────────────────────────────┘
```
### Sistem Confidence
```
Base confidence: 55%
+ BOS/CHoCH: +10%
+ FVG: +10%
+ Order Block: +10%
Maximum: 85%
```
### Output Signal
```python
SMCSignal:
signal_type: "BUY" / "SELL"
entry_price: float
stop_loss: float # ATR-based (min 1.5 ATR dari entry)
take_profit: float # 2:1 RR, capped di 4 ATR
confidence: 0.55 - 0.85
reason: "Bullish BOS + FVG + OB"
risk_reward: float # Minimum 2.0
```
---
## Konfigurasi
```python
SMCConfig:
swing_length: 5 # Window untuk deteksi swing (11 bar total)
fvg_min_gap_pips: 2.0 # Minimum ukuran FVG
ob_lookback: 10 # Berapa jauh cari OB ke belakang
bos_close_break: True # Harus close (bukan wick) yang break
```
---
## Integrasi dalam Pipeline
```
Data OHLCV
|
v
smc.calculate_all(df)
|--- calculate_fair_value_gaps()
|--- calculate_swing_points()
|--- calculate_order_blocks() <- butuh swing points
|--- calculate_structure_breaks() <- butuh swing points
|--- calculate_liquidity_zones()
|
v
smc.generate_signal(df)
|
v
SMCSignal (entry, SL, TP, confidence)
|
v
Dikombinasikan dengan XGBoost + HMM
```
@@ -0,0 +1,317 @@
# Feature Engineering
> **File:** `src/feature_eng.py`
> **Class:** `FeatureEngineer`
> **Framework:** Pure Polars (vectorized, tanpa loop, tanpa TA-Lib)
---
## Apa Itu Feature Engineering?
Feature Engineering adalah proses **mengubah data harga mentah (OHLCV) menjadi 40+ fitur numerik** yang bisa dibaca oleh model machine learning. Ini adalah "mata" dari AI — tanpa fitur yang baik, model tidak bisa belajar apapun.
**Analogi:** Feature Engineering adalah **alat ukur** — thermometer, barometer, kompas — yang mengubah data mentah menjadi informasi bermakna.
---
## Flow Utama: `calculate_all()`
```
Input: DataFrame OHLCV (open, high, low, close, volume)
|
|-- calculate_rsi() -> rsi
|-- calculate_atr() -> atr, atr_percent
|-- calculate_macd() -> macd, macd_signal, macd_histogram
|-- calculate_bollinger_bands() -> bb_upper, bb_lower, bb_width, bb_percent_b
|-- calculate_ema_crossover() -> ema_9, ema_21, ema_cross_bull/bear
|-- calculate_volume_features() -> volume_ratio, high_volume
|
|-- [jika include_ml_features=True]
| calculate_ml_features() -> returns, volatility, lags, trends, time
|
v
Output: DataFrame dengan 40+ kolom fitur
```
**Data minimum:** 26 bar (kebutuhan MACD slow EMA) agar semua fitur stabil.
---
## Kategori 1: Indikator Teknikal
### RSI (Relative Strength Index) — Period 14
```
Formula: RSI = 100 - (100 / (1 + RS))
RS = Average Gain / Average Loss
Smoothing: Wilder's EMA (alpha = 1/14)
```
| Nilai | Interpretasi |
|-------|-------------|
| RSI > 70 | Overbought (potensi turun) |
| RSI < 30 | Oversold (potensi naik) |
| RSI ~ 50 | Netral |
**Output:** `rsi`
---
### ATR (Average True Range) — Period 14
```
True Range = max(High-Low, |High-PrevClose|, |Low-PrevClose|)
ATR = Wilder's EMA dari True Range
ATR% = (ATR / Close) * 100
```
| Kondisi | Interpretasi |
|---------|-------------|
| ATR tinggi | Pasar volatile (pergerakan besar) |
| ATR rendah | Pasar tenang (pergerakan kecil) |
**Output:** `atr`, `atr_percent`
---
### MACD (Moving Average Convergence Divergence) — 12/26/9
```
MACD Line = EMA(12) - EMA(26)
Signal = EMA(MACD Line, 9)
Histogram = MACD Line - Signal
```
| Kondisi | Interpretasi |
|---------|-------------|
| Histogram > 0 & naik | Bullish momentum menguat |
| Histogram < 0 & turun | Bearish momentum menguat |
| MACD cross Signal ke atas | Potensi reversal naik |
| MACD cross Signal ke bawah | Potensi reversal turun |
**Output:** `macd`, `macd_signal`, `macd_histogram`
---
### Bollinger Bands — Period 20, StdDev 2.0
```
Middle = SMA(20)
Upper = Middle + 2 * StdDev
Lower = Middle - 2 * StdDev
Width = (Upper - Lower) / Middle
%B = (Close - Lower) / (Upper - Lower)
```
| Kondisi | Interpretasi |
|---------|-------------|
| %B > 1 | Harga di atas upper band (extreme bullish) |
| %B < 0 | Harga di bawah lower band (extreme bearish) |
| %B ~ 0.5 | Harga di tengah |
| Width melebar | Volatilitas meningkat |
| Width menyempit | Volatilitas menurun (squeeze) |
**Output:** `bb_middle`, `bb_upper`, `bb_lower`, `bb_width`, `bb_percent_b`
---
### EMA Crossover — 9/21
```
EMA9 = Exponential Moving Average (cepat)
EMA21 = Exponential Moving Average (lambat)
```
| Kondisi | Interpretasi |
|---------|-------------|
| EMA9 > EMA21 | Tren naik |
| EMA9 < EMA21 | Tren turun |
| EMA9 cross atas EMA21 | Sinyal beli |
| EMA9 cross bawah EMA21 | Sinyal jual |
**Output:** `ema_9`, `ema_21`, `ema_cross_bull`, `ema_cross_bear`
---
## Kategori 2: Volume Features — Period 20
```
volume_sma = Rolling Mean(volume, 20)
volume_ratio = volume / volume_sma
volume_increasing = 1 jika volume > volume sebelumnya
high_volume = 1 jika volume_ratio > 1.5
```
**Fungsi:** Konfirmasi breakout — pergerakan besar harus didukung volume tinggi.
**Catatan:** Jika kolom volume tidak ada di data, fitur ini di-skip (graceful degradation).
---
## Kategori 3: ML-Specific Features
### Returns & Momentum
```
returns_1 = (Close[t] / Close[t-1]) - 1 # Return 1 bar
returns_5 = (Close[t] / Close[t-5]) - 1 # Return 5 bar
returns_20 = (Close[t] / Close[t-20]) - 1 # Return 20 bar
log_returns = ln(Close[t] / Close[t-1]) # Log return
```
**Fungsi:** Mengukur kecepatan dan arah pergerakan harga dalam berbagai timeframe.
---
### Price Position
```
price_position = (Close - Low) / (High - Low) # Posisi 0-1 dalam range candle
dist_from_sma_20 = (Close / SMA20) - 1 # Jarak (%) dari rata-rata
```
**Fungsi:** Mengukur dimana harga relatif terhadap range dan rata-rata.
---
### Volatility
```
volatility_20 = StdDev(log_returns, 20) # Realized volatility
normalized_range = (High - Low) / Close # Range sebagai % harga
avg_normalized_range = SMA(normalized_range, 14) # Rata-rata range 14 bar
```
**Fungsi:** Input penting untuk HMM regime detection dan risk sizing.
---
### Lag Features
```
close_lag_1 = Close[t-1]
close_lag_2 = Close[t-2]
close_lag_3 = Close[t-3]
close_lag_5 = Close[t-5]
```
**Fungsi:** Auto-regressive features — menangkap pola harga berulang.
---
### Trend Features
```
higher_high = 1 jika High[t] > High[t-1], else 0
lower_low = 1 jika Low[t] < Low[t-1], else 0
hh_count_5 = Sum(higher_high, 5 bar) # Berapa kali HH dalam 5 bar
ll_count_5 = Sum(lower_low, 5 bar) # Berapa kali LL dalam 5 bar
```
**Fungsi:** Mengukur konsistensi tren — banyak HH = strong uptrend.
---
### Time Features
```
hour = Jam (0-23)
weekday = Hari (0=Senin, 6=Minggu)
london_session = 1 jika jam 08:00-16:00 UTC
ny_session = 1 jika jam 13:00-21:00 UTC
```
**Fungsi:** Pasar berperilaku berbeda tiap sesi — London volatile, Asian tenang.
**Catatan:** Hanya dihitung jika kolom `time` bertipe Datetime.
---
## Kategori 4: SMC sebagai Fitur Numerik
Dari SMC Analyzer, dikonversi jadi angka untuk XGBoost:
```
swing_high = 1 / 0
swing_low = -1 / 0
fvg_signal = 1 (bull) / -1 (bear) / 0
ob = 1 (bull) / -1 (bear) / 0
bos = 1 (bull) / -1 (bear) / 0
choch = 1 (bull) / -1 (bear) / 0
market_structure = 1 (bull) / -1 (bear) / 0
regime = 0 / 1 / 2 (dari HMM)
```
---
## Target Variable (Label Training)
```python
create_target(df, lookahead=1, threshold=0.0):
target = 1 jika close[t+1] > close[t] # Harga naik
target = 0 jika close[t+1] <= close[t] # Harga turun/tetap
target_return = close[t+1] / close[t] - 1 # Return kontinu
```
**Catatan:** Target dibuat saat training saja, tidak saat live trading.
---
## Preprocessing untuk ML
### Penanganan Null
```python
# Bar awal memiliki NaN karena lookback period
# Saat training: baris dengan NaN di-drop
df_clean = df.select(features + [target]).drop_nulls()
```
### Penanganan Infinity
```python
# Saat prediksi: NaN & infinity diganti 0
X = np.nan_to_num(X, nan=0.0, posinf=0.0, neginf=0.0)
```
### Normalisasi
**Tidak dilakukan** — XGBoost berbasis tree, scale-invariant (tidak perlu scaling).
### Cleanup Kolom Temporary
Setiap method membersihkan kolom sementara yang diawali `_` (misal `_delta`, `_avg_gain`, dll).
---
## Fitur yang Digunakan vs Tidak
### Digunakan oleh XGBoost (24+ fitur)
Semua indikator teknikal, returns, volatility, trend, time, SMC numerik, regime.
### Tidak Digunakan (Excluded)
- Kolom OHLCV asli: `time`, `open`, `high`, `low`, `close`, `volume`
- Kolom meta: `spread`, `real_volume`, `target`, `target_return`
- Kolom SMC level: `fvg_top`, `fvg_bottom`, `ob_top`, `ob_bottom`, dll
- Kolom temporary: apapun yang diawali `_`
---
## Parameter Konfigurasi
| Indikator | Parameter | Default | Configurable |
|-----------|-----------|---------|-------------|
| RSI | period | 14 | Ya |
| ATR | period | 14 | Ya |
| MACD | fast/slow/signal | 12/26/9 | Ya |
| Bollinger Bands | period, std_dev | 20, 2.0 | Ya |
| EMA Crossover | fast/slow | 9/21 | Ya |
| Volume | period | 20 | Ya |
| Returns | lookback | [1, 5, 20] | Hardcoded |
| Volatility | window | 20 | Hardcoded |
| Session | London hours | 08-16 UTC | Hardcoded |
| Session | NY hours | 13-21 UTC | Hardcoded |
---
## Performa
- **5000 bar features:** < 100ms (sangat cepat)
- **Framework:** Polars vectorized (10-100x lebih cepat dari Pandas loop)
- **Memory:** ~1.6MB untuk 40 fitur x 5000 bar
+447
View File
@@ -0,0 +1,447 @@
# Risk Management
> **File utama:** `src/smart_risk_manager.py`
> **File pendukung:** `src/risk_engine.py`, `src/position_manager.py`
> **Konfigurasi:** `src/config.py`
---
## Apa Itu Risk Management?
Risk Management adalah sistem **pelindung modal** yang menentukan **seberapa besar** boleh trading, **kapan harus berhenti**, dan **bagaimana mengelola posisi terbuka**. Ini adalah komponen paling kritis — tanpa risk management yang baik, bahkan strategi terbaik pun bisa bangkrut.
**Analogi:** Risk Management adalah **sabuk pengaman + airbag + rem ABS** — melindungi dari kerugian fatal.
---
## 3 Modul Risk Management
| Modul | File | Fungsi |
|-------|------|--------|
| **SmartRiskManager** | `smart_risk_manager.py` | Ultra-safe position sizing & daily limits |
| **RiskEngine** | `risk_engine.py` | Kelly Criterion & circuit breaker |
| **SmartPositionManager** | `position_manager.py` | Trailing stop & profit protection |
---
## Trading Mode (4 State)
Bot beroperasi dalam salah satu dari 4 mode:
```
NORMAL -> RECOVERY -> PROTECTED -> STOPPED
| | | |
| 3 loss berturut | 80% limit tercapai
| | |
| | 100% limit -> STOP total
v v
Trading penuh Lot minimum saja
```
| Mode | Bisa Trade? | Lot Size | Kondisi |
|------|------------|----------|---------|
| **NORMAL** | Ya | 0.01 - 0.02 | Operasi standar |
| **RECOVERY** | Ya | 0.01 saja | Setelah 3 loss berturut |
| **PROTECTED** | Ya | 0.01 saja | Daily loss 80% dari limit |
| **STOPPED** | Tidak | 0.00 | Daily/total limit tercapai |
### Transisi Mode (Prioritas tinggi ke rendah)
```
1. Cek total_loss >= $500 (10%) -> STOPPED
2. Cek daily_loss >= $250 (5%) -> STOPPED
3. Cek total_loss >= $400 (80%) -> PROTECTED
4. Cek daily_loss >= $200 (80%) -> PROTECTED
5. Cek consecutive_losses >= 3 -> RECOVERY
6. Sisanya -> NORMAL
```
---
## Kalkulasi Lot Size
### Formula
```
calculate_lot_size(entry_price, confidence, regime, ml_confidence):
1. Base lot = 0.01
2. Cek trading mode:
NORMAL -> lot 0.01 - 0.02
RECOVERY -> lot 0.01 (fixed)
PROTECTED -> lot 0.01 (fixed)
STOPPED -> lot 0.00 (tidak trade)
3. Cek ML confidence:
effective = min(confidence, ml_confidence)
>= 0.65 -> lot 0.02 (HIGH)
>= 0.55 -> lot 0.01 (MEDIUM)
< 0.55 -> lot 0.01 (LOW)
4. Cek regime:
high_volatility / crisis -> paksa lot 0.01
5. Apply session multiplier:
Sydney session -> lot * 0.5
London-NY overlap -> lot * 1.2
6. Cap ke max_allowed_lot berdasarkan state
7. Round ke increment 0.01
```
### Contoh Perhitungan
```
Input:
confidence = 0.78 (SMC)
ml_confidence = 0.72 (XGBoost)
regime = "medium_volatility"
session = "London"
Langkah:
1. Mode = NORMAL
2. effective = min(0.78, 0.72) = 0.72 >= 0.65 -> lot = 0.02
3. Regime = medium -> tidak override
4. Session = London (1.0x) -> lot tetap 0.02
5. Final lot = 0.02
```
```
Input:
confidence = 0.65
ml_confidence = 0.60
regime = "high_volatility"
session = "Sydney"
Langkah:
1. Mode = NORMAL
2. effective = min(0.65, 0.60) = 0.60 >= 0.55 -> lot = 0.01
3. Regime = high_volatility -> paksa lot 0.01
4. Session = Sydney (0.5x) -> lot = max(0.01, 0.01*0.5) = 0.01
5. Final lot = 0.01
```
---
## Limit Proteksi (untuk modal $5,000)
### Per Trade
| Proteksi | Persentase | Nilai | Mekanisme |
|----------|-----------|-------|-----------|
| **Software S/L** | 1.0% | $50 | Bot tutup posisi otomatis |
| **Emergency Broker S/L** | 2.0% | $100 | SL broker sebagai safety net |
### Per Hari
| Proteksi | Persentase | Nilai | Aksi |
|----------|-----------|-------|------|
| **Warning** | 4.0% (80%) | $200 | Mode -> PROTECTED (lot minimum) |
| **Daily Loss Limit** | 5.0% | $250 | Mode -> STOPPED (berhenti total) |
### Total (Kumulatif)
| Proteksi | Persentase | Nilai | Aksi |
|----------|-----------|-------|------|
| **Warning** | 8.0% (80%) | $400 | Mode -> PROTECTED |
| **Total Loss Limit** | 10.0% | $500 | Mode -> STOPPED permanen |
---
## Position Limit
```
Max concurrent positions: 2
Cek sebelum buka posisi baru:
can_open_position():
jika active_positions >= 2:
return False, "Max positions reached (2/2)"
else:
return True, "OK"
```
---
## Manajemen Posisi Terbuka
### Evaluasi Posisi (`evaluate_position()`)
Setiap posisi terbuka dievaluasi setiap loop:
```
1. TAKE PROFIT CHECK
Jika profit >= $40:
-> TUTUP (exit_reason: TAKE_PROFIT)
2. ML REVERSAL CHECK (v3: threshold diturunkan)
Jika ML confidence > 65% berlawanan arah: <- sebelumnya 70%
DAN loss >= 40% dari max ($20):
-> TUTUP (exit_reason: TREND_REVERSAL)
3. MAX LOSS CHECK (50% threshold)
Jika loss >= $25 (50% dari $50 max):
Kecuali golden time DAN momentum > -40:
-> TUTUP (exit_reason: POSITION_LIMIT)
4. STALL DETECTION
Jika harga stall 10+ candle DAN loss >= $15:
stall_count++
Jika stall_count >= 5:
-> TUTUP (exit_reason: STALL)
5. PROFIT PROTECTION (Peak Tracking)
Jika peak_profit > $30 DAN current < 60% dari peak:
-> TUTUP (lindungi profit)
6. TIME-BASED EXIT (v3: BARU)
Jika posisi terbuka >= 4 jam DAN profit < $5:
- Jika profit >= $0 -> TUTUP (breakeven/profit kecil)
- Jika profit > -$15 -> TUTUP (loss kecil, daripada makin besar)
Jika posisi terbuka >= 6 jam:
-> FORCE EXIT (tutup apapun kondisinya)
```
### Time-Based Exit Detail (v3 Update)
```
Jam 0 Jam 4 Jam 6
|------------|------------------|-----> waktu
| |
| profit < $5? | FORCE EXIT
| Ya -> evaluasi: | (apapun kondisinya)
| profit >= 0 |
| -> tutup OK |
| loss > -$15 |
| -> tutup |
| loss <= -$15 |
| -> tahan |
Kenapa perlu time-based exit?
- Trade yang stuck tanpa progress = buang waktu & margin
- Lebih baik exit kecil daripada menunggu loss besar
- Mencegah posisi "zombie" yang tidak kemana-mana
```
### Broker Stop Loss (v3: ATR-Based Protection)
**Perubahan utama v3:** Bot sekarang mengirim **SL ke broker** (bukan SL=0 seperti sebelumnya).
```python
# v2 (lama): Tidak ada proteksi broker
result = mt5.send_order(sl=0, ...) # Bergantung 100% pada software
# v3 (baru): ATR-based broker protection
broker_sl = signal.stop_loss # SL dari SMC (ATR-based, min 1.5 ATR)
# Validasi jarak minimum (10 pips untuk XAUUSD)
min_sl_distance = 1.0 # $1 = 10 pips
if direction == "BUY" and current_price - broker_sl < min_sl_distance:
broker_sl = current_price - (min_sl_distance * 2) # Paksa lebih lebar
if direction == "SELL" and broker_sl - current_price < min_sl_distance:
broker_sl = current_price + (min_sl_distance * 2) # Paksa lebih lebar
result = mt5.send_order(sl=broker_sl, ...) # SL AKTIF di broker
```
**Fallback jika broker reject SL:**
```python
# Error code 10016 = SL/TP rejected
if not result.success and result.retcode == 10016:
# Fallback ke software SL (tanpa broker protection)
result = mt5.send_order(sl=0, ...) # Software tetap mengelola
```
### Emergency Stop Loss (Safety Net Terakhir)
```python
calculate_emergency_sl(entry_price, lot_size, direction):
pip_value = lot_size * 10 # XAUUSD
emergency_pips = emergency_sl_usd / pip_value # $100 / pip_value
price_distance = emergency_pips * 0.01
if direction == "BUY":
sl = entry_price - price_distance
else:
sl = entry_price + price_distance
```
### Perbandingan Proteksi Lama vs Baru
```
┌─────────────────┬───────────────────────┬──────────────────────────┐
│ Skenario │ Sebelum (v2) │ Sesudah (v3) │
├─────────────────┼───────────────────────┼──────────────────────────┤
│ Weekend Gap │ Loss unlimited │ Broker SL aktif │
├─────────────────┼───────────────────────┼──────────────────────────┤
│ Flash Crash │ Bergantung software │ Broker SL aktif │
├─────────────────┼───────────────────────┼──────────────────────────┤
│ Connection Lost │ Loss unlimited │ Broker SL aktif │
├─────────────────┼───────────────────────┼──────────────────────────┤
│ Trade Stuck │ Ditahan selamanya │ Exit max 6 jam │
├─────────────────┼───────────────────────┼──────────────────────────┤
│ Reversal Lambat │ Tunggu 70% confidence │ Exit di 65% (lebih cepat)│
└─────────────────┴───────────────────────┴──────────────────────────┘
```
---
## Circuit Breaker (RiskEngine)
```python
# Automatic halt jika kondisi darurat
if daily_pnl_percent <= -max_daily_loss:
activate_circuit_breaker("Daily loss limit breached")
can_trade = False
# Flash crash protection
if price_move > flash_crash_threshold (2.5%):
activate_circuit_breaker("Flash crash detected")
can_trade = False
```
---
## Drawdown Tracking
### Daily Drawdown
```python
# Saat loss:
daily_loss += abs(profit)
total_loss += abs(profit)
consecutive_losses += 1
# Saat profit:
total_loss = max(0, total_loss - profit) # Recovery
consecutive_losses = 0 # Reset
```
### Peak Equity Drawdown
```python
# Track peak equity
if equity > peak_equity:
peak_equity = equity
# Hitung drawdown
drawdown = ((peak_equity - equity) / peak_equity) * 100
```
### Per-Position Peak Tracking
```python
# Track peak profit per posisi
peak_profits[ticket] = max(peak_profits[ticket], current_profit)
# Profit protection: tutup jika profit turun 40% dari peak
if current_profit < peak_profit * 0.6:
close_position() # Lindungi profit
```
---
## Daily Reset
```python
check_new_day():
if date.today() != current_date:
# Reset semua counter harian
daily_loss = 0
daily_trades = 0
consecutive_losses = 0
mode = NORMAL (jika total_loss OK)
current_date = today
```
---
## Integrasi dalam Main Loop
```
Main Trading Loop (setiap 1 detik)
|
v
1. check_new_day() <- Reset harian
|
v
2. get_trading_recommendation()
|-- can_trade? -> Jika False, skip
|-- mode? -> Tentukan lot limit
|
v
3. calculate_lot_size() <- Hitung lot aman
|-- Input: confidence, regime, ml_confidence
|-- Output: lot 0.01-0.02
|
v
4. Apply session_multiplier <- Sydney 0.5x, Golden 1.2x
|
v
5. can_open_position() <- Cek limit posisi (max 2)
|
v
6. execute_trade() <- Kirim order ke MT5 (v3: DENGAN broker SL)
|-- broker_sl = signal.stop_loss (ATR-based)
|-- Fallback sl=0 jika broker reject
|-- register_position() <- Track posisi baru + entry_time
|
v
7. evaluate_position() <- Monitor posisi terbuka
|-- Cek TP, ML reversal (65%), max loss, stall
|-- Cek time-based exit (4 jam / 6 jam) <- v3 BARU
|
v
8. record_trade_result() <- Catat profit/loss
|-- Update daily_loss, total_loss
|-- Cek apakah limit tercapai
```
---
## Semua Parameter Konfigurasi
| Parameter | Nilai | Fungsi |
|-----------|-------|--------|
| `capital` | $5,000 | Modal awal |
| `max_daily_loss_percent` | 5.0% | Limit harian ($250) |
| `max_total_loss_percent` | 10.0% | Limit kumulatif ($500) |
| `max_loss_per_trade_percent` | 1.0% | Software SL ($50) |
| `emergency_sl_percent` | 2.0% | Broker SL ($100) |
| `base_lot_size` | 0.01 | Lot minimum |
| `max_lot_size` | 0.02 | Lot maximum |
| `recovery_lot_size` | 0.01 | Lot saat recovery |
| `trend_reversal_threshold` | **0.65** | ML confidence untuk tutup (v3: diturunkan dari 0.70) |
| `max_concurrent_positions` | 2 | Posisi terbuka max |
| `flash_crash_threshold` | 2.5% | Deteksi crash |
| `breakeven_pips` | 15.0 | Pindah SL ke breakeven |
| `trail_start_pips` | 25.0 | Mulai trailing stop |
| `trail_step_pips` | 10.0 | Jarak trailing |
---
## Sinkronisasi Backtest (backtest_live_sync.py)
Backtest menggunakan **logika exit yang identik** dengan live trading:
```
Exit reversal: 0.65 (65% ML confidence) <- synced dengan live
Time-based exit:
16 bars (4 jam M15) + profit < $5 -> exit
24 bars (6 jam M15) -> force exit
Perhitungan bar:
bars_since_entry = current_bar_index - entry_bar_index
16 bars * 15 menit = 4 jam
24 bars * 15 menit = 6 jam
```
**Kenapa penting disinkronkan?** Agar hasil backtest akurat mewakili performa live trading.
---
## Filosofi Kunci
1. **Dual-Layer SL** — ATR-based broker SL + software-managed exit (v3 update)
2. **Ultra-Conservative** — Lot 0.01-0.02 saja, tidak pernah agresif
3. **Multi-Layer Protection** — Per-trade, per-day, total limit, circuit breaker
4. **Recovery First** — Setelah loss, otomatis masuk mode defensif
5. **Profit Protection** — Jika profit sudah besar, lindungi dari drawback
6. **Time-Bounded** — Tidak ada posisi "zombie", max 6 jam (v3 update)
7. **Faster Reversal** — Exit lebih cepat di 65% ML confidence (v3 update)
+299
View File
@@ -0,0 +1,299 @@
# Session Filter
> **File:** `src/session_filter.py`
> **Class:** `SessionFilter`
> **Timezone:** WIB (Waktu Indonesia Barat / GMT+7)
---
## Apa Itu Session Filter?
Session Filter menentukan **kapan bot boleh trading** berdasarkan sesi pasar global. Setiap sesi memiliki karakteristik berbeda — volatilitas, likuiditas, dan spread. Bot menyesuaikan perilaku berdasarkan sesi yang sedang aktif.
**Analogi:** Session Filter adalah **jadwal kerja** — bot tahu kapan harus bekerja keras, kapan santai, dan kapan istirahat.
---
## 7 Sesi yang Didefinisikan
| Sesi | Enum | Waktu (WIB) | Volatilitas | Multiplier |
|------|------|-------------|-------------|------------|
| **Sydney** | `SYDNEY` | 06:00 - 13:00 | Low | 0.5x |
| **Tokyo** | `TOKYO` | 07:00 - 16:00 | Medium | 0.7x |
| **London** | `LONDON` | 15:00 - 23:59 | High | 1.0x |
| **New York** | `NEW_YORK` | 20:00 - 23:59 | Extreme | 1.0x |
| **Tokyo-London Overlap** | `OVERLAP_TOKYO_LONDON` | 15:00 - 16:00 | High | 1.0x |
| **London-NY Overlap** | `OVERLAP_LONDON_NY` | 20:00 - 23:59 | Extreme | **1.2x** |
| **Off Hours** | `OFF_HOURS` | Diluar sesi | - | 0.0x |
---
## Visualisasi Timeline (WIB)
```
JAM WIB: 00 02 04 06 08 10 12 14 16 18 20 22 24
|---|---|---|---|---|---|---|---|---|---|---|---|---|
DANGER: [=========] <- Dead Zone (00-04)
DANGER: [===] <- Rollover (04-06)
SYDNEY: [===========] 0.5x
TOKYO: [=============] 0.7x
OVERLAP T-L: [=] 1.0x
LONDON: [===================] 1.0x
NEW YORK: [=======] 1.0x
GOLDEN: [=======] 1.2x ★
|---|---|---|---|---|---|---|---|---|---|---|---|---|
00 02 04 06 08 10 12 14 16 18 20 22 24
```
**★ GOLDEN TIME (20:00-23:59 WIB):** Waktu terbaik — likuiditas tertinggi, London & NY overlap.
---
## Zona Bahaya (Danger Zones)
| Zona | Waktu (WIB) | Alasan | Aksi |
|------|-------------|--------|------|
| **Dead Zone** | 00:00 - 04:00 | Likuiditas rendah, spread tinggi | Block trading |
| **Rollover** | 04:00 - 06:00 | Spread melebar saat rollover broker | Block trading |
---
## Logika `can_trade()` — Keputusan Utama
```
can_trade() -> (bool, str, float)
bisa? alasan multiplier
Langkah pengecekan (urut prioritas):
1. Weekend?
|-- Sabtu / Minggu -> (False, "Market tutup", 0.0)
2. Jumat >= 23:00?
|-- Ya -> (False, "Hindari gap weekend", 0.0)
3. Danger Zone?
|-- 00:00-04:00 -> (False, "Likuiditas rendah", 0.0)
|-- 04:00-06:00 -> (False, "Spread melebar", 0.0)
4. Sesi saat ini?
|-- Cek overlap dulu (prioritas tertinggi)
|-- Lalu cek sesi utama
5. allow_trading flag?
|-- False -> (False, "Tidak diizinkan", 0.0)
6. Aggressive Mode?
|-- Sydney -> (True, "SAFE MODE 0.5x", 0.5)
|-- Low volatility -> (False, "Tunggu sesi volatile", mult)
|-- High/Extreme -> (True, "Trading OK", mult)
7. Default
|-- (True, "Trading OK - {sesi}", multiplier)
```
---
## Prioritas Deteksi Sesi
```python
# Overlap dicek PERTAMA (prioritas tertinggi)
1. London-NY Overlap (20:00-23:59) -> GOLDEN TIME 1.2x
2. Tokyo-London Overlap (15:00-16:00)
# Lalu sesi utama
3. London (15:00-23:59)
4. New York (20:00-23:59)
5. Tokyo (07:00-16:00)
6. Sydney (06:00-13:00)
# Terakhir
7. Off Hours (default)
```
---
## Dampak ke Position Sizing
Session multiplier diterapkan **setelah** kalkulasi lot dari SmartRiskManager:
```
Lot dasar dari Risk Manager: 0.02
|
v
Session multiplier:
Sydney (0.5x): 0.02 * 0.5 = 0.01
Tokyo (0.7x): 0.02 * 0.7 = 0.014 -> 0.01 (rounded)
London (1.0x): 0.02 * 1.0 = 0.02
Golden (1.2x): 0.02 * 1.2 = 0.024 -> 0.02 (capped)
|
v
Final lot (min 0.01, max 0.02)
```
---
## Weekend & Friday Handling
### Weekend
```
Sabtu (weekday=5): Market tutup -> tidak trading
Minggu (weekday=6): Market tutup -> tidak trading
```
### Friday Close
```
Jumat >= 23:00 WIB:
-> Block semua trade baru
-> Alasan: Hindari gap weekend (harga bisa gap besar saat buka Senin)
```
---
## News Event Monitoring
### Event yang Dipantau
| Event | Waktu (WIB) | Buffer Sebelum | Buffer Sesudah |
|-------|-------------|---------------|----------------|
| **NFP** (Non-Farm Payroll) | 19:30 | 15 menit | 30 menit |
| **FOMC** (Fed Decision) | 01:00 | 15 menit | 45 menit |
| **CPI** (Inflation) | 19:30 | 15 menit | 30 menit |
### Kebijakan News: MONITORING ONLY (Tidak Blocking)
```
Backtest menunjukkan:
- Win rate saat news: 62.1%
- Win rate normal: 64.9%
- Selisih kecil, tapi BLOCKING news KEHILANGAN $178 profit
Keputusan: ML model sudah cukup menangani volatilitas news.
News hanya di-LOG, TIDAK memblokir trading.
```
---
## Aggressive Mode
Bot default menggunakan `aggressive_mode=True`:
```python
create_wib_session_filter(aggressive=True)
```
### Efek Aggressive Mode
| Sesi | Tanpa Aggressive | Dengan Aggressive |
|------|-----------------|-------------------|
| Sydney | Block | **Allow** (0.5x, proven profitable) |
| Tokyo | Allow | Block (volatilitas kurang) |
| London | Allow | Allow |
| New York | Allow | Allow |
| Golden | Allow | Allow (boost 1.2x) |
**Alasan Sydney diizinkan:** Backtest menunjukkan win rate 62% dan profit $5,934 di sesi Sydney.
---
## Golden Time (London-NY Overlap)
```
Waktu: 20:00 - 23:59 WIB
Multiplier: 1.2x (BOOSTED)
Volatilitas: Extreme
Kenapa spesial?
- London dan New York sama-sama aktif
- Likuiditas TERTINGGI sepanjang hari
- Pergerakan harga paling signifikan
- Volume trading terbesar
Aturan tambahan di main_live.py:
- Require ML + SMC alignment (keduanya harus setuju)
- Lot boleh lebih besar (1.2x multiplier)
```
---
## Integrasi dalam Main Loop
```python
# 1. Inisialisasi
self.session_filter = create_wib_session_filter(aggressive=True)
# 2. Cek setiap loop
session_ok, session_reason, session_multiplier = self.session_filter.can_trade()
if not session_ok:
# Log setiap 5 menit
logger.info(f"Session: {session_reason}")
next = self.session_filter.get_next_trading_window()
logger.info(f"Next: {next['session']} in {next['hours_until']} hours")
return # Skip, tidak trading
# 3. Simpan multiplier untuk lot sizing
self._current_session_multiplier = session_multiplier
# 4. Apply ke lot size (setelah risk calculation)
safe_lot = max(0.01, safe_lot * session_multiplier)
```
---
## Status Report
```python
get_status_report() -> {
"current_time_wib": "2026-02-06 20:15:00",
"current_session": "London-NY Overlap",
"volatility": "extreme",
"can_trade": True,
"reason": "Trading OK - GOLDEN TIME (1.2x)",
"position_multiplier": 1.2,
"is_weekend": False,
"is_friday_close": False,
"is_danger_zone": False,
}
```
---
## Contoh Skenario
**Skenario 1: Golden Time**
```
Waktu: 21:30 WIB (Rabu)
Sesi: London-NY Overlap
-> can_trade = True
-> multiplier = 1.2x
-> Lot 0.02 * 1.2 = 0.024 -> cap 0.02
-> Trading optimal!
```
**Skenario 2: Sydney pagi**
```
Waktu: 08:00 WIB (Selasa)
Sesi: Sydney
-> can_trade = True (aggressive mode)
-> multiplier = 0.5x
-> Lot 0.02 * 0.5 = 0.01
-> SAFE MODE: lot minimum
```
**Skenario 3: Dead zone**
```
Waktu: 02:30 WIB (Kamis)
Sesi: Off Hours (Danger Zone)
-> can_trade = False
-> Alasan: "Likuiditas rendah, spread tinggi"
-> Bot istirahat, tunggu sesi berikutnya
```
**Skenario 4: Jumat malam**
```
Waktu: 23:15 WIB (Jumat)
-> can_trade = False
-> Alasan: "Hindari gap weekend"
-> Tidak buka posisi baru
```
+263
View File
@@ -0,0 +1,263 @@
# Stop Loss (S/L) — Sistem Proteksi Berlapis
> **File terkait:** `src/smc_polars.py`, `main_live.py`, `src/smart_risk_manager.py`
---
## Apa Itu Stop Loss di Bot Ini?
Stop Loss bukan hanya satu angka — ini adalah **sistem proteksi 4 lapis** yang bekerja bersamaan. Jika satu layer gagal, layer berikutnya siap melindungi.
**Analogi:** SL di bot ini seperti sistem keamanan gedung — ada CCTV (software monitoring), security (broker SL), alarm kebakaran (emergency SL), dan sprinkler otomatis (circuit breaker).
---
## 4 Layer Stop Loss
```
Layer 1: SMC ATR-Based SL <- Dikirim ke broker sebagai SL aktif
Layer 2: Software Smart Exit <- Bot monitor & tutup posisi secara cerdas
Layer 3: Emergency Broker SL <- Safety net 2% jika software gagal
Layer 4: Circuit Breaker <- Halt total jika flash crash / daily limit
```
```
Harga masuk (Entry)
|
|-- Layer 1: SMC SL (1.5 ATR) contoh: -$15 ~ -$30
|
|-- Layer 2: Software SL ($25-$50) 50% dari max loss
|
|-- Layer 3: Emergency SL ($100) 2% modal (jaring terakhir)
|
|-- Layer 4: Circuit Breaker Flash crash 2.5% -> HALT
|
v
Semakin jauh = semakin jarang tercapai (backup)
```
---
## Layer 1: SMC ATR-Based Stop Loss
**Sumber:** `smc_polars.py` (Lines 631-652, 694-702)
**Dikirim ke:** Broker MT5 sebagai SL order aktif
### Perhitungan
```python
# Ambil ATR dari Feature Engineering
atr = latest["atr"] # Contoh: ATR = $8.50
min_sl_distance = 1.5 * atr # 1.5 * 8.50 = $12.75
# Untuk BUY:
swing_sl = last_swing_low # Contoh: $4935.00
atr_sl = entry - min_sl_distance # $4950 - $12.75 = $4937.25
SL = MIN(swing_sl, atr_sl) # $4935.00 (pilih yang LEBIH JAUH)
# Untuk SELL:
swing_sl = last_swing_high # Contoh: $4965.00
atr_sl = entry + min_sl_distance # $4950 + $12.75 = $4962.75
SL = MAX(swing_sl, atr_sl) # $4965.00 (pilih yang LEBIH JAUH)
```
### Kenapa MIN/MAX (Pilih yang Lebih Jauh)?
```
Sebelum (v2): SL = swing_low ATAU entry * 0.995
-> Bisa sangat dekat, gampang kena whipsaw
Sesudah (v3): SL = MIN(swing_low, entry - 1.5*ATR)
-> Selalu minimal 1.5 ATR dari entry
-> Lebih protektif terhadap noise pasar
```
---
## Layer 2: Software Smart Exit
**Sumber:** `smart_risk_manager.py` (Lines 559-724)
**Mekanisme:** Bot monitor posisi setiap detik dan tutup otomatis
### Kondisi Software SL
```
Max loss per trade: $50 (1% dari modal $5,000)
Trigger exit jika:
1. Loss >= $25 (50% dari max)
Kecuali golden time DAN momentum > -40 -> hold
2. Loss >= $20 (40%) + ML reversal 65%+ berlawanan
-> Tutup karena trend reversal
3. Loss >= $15 + harga stall 10+ candle
stall_count >= 5 -> tutup
4. 4+ jam terbuka + profit < $5
-> Time-based exit
5. 6+ jam terbuka
-> Force exit (apapun kondisinya)
```
### Kelebihan Software SL vs Hard SL
```
Hard SL (broker):
- Kaku, tidak bisa diubah
- Bisa kena whipsaw lalu harga balik
- Tidak bisa mempertimbangkan konteks
Software SL (bot):
- Dinamis, mempertimbangkan momentum
- Bisa hold jika golden time & momentum positif
- Bisa exit lebih cepat jika ML deteksi reversal
- Mempertimbangkan durasi posisi
```
---
## Layer 3: Emergency Broker Stop Loss
**Sumber:** `smart_risk_manager.py` (Lines 305-346)
**Fungsi:** Jaring pengaman TERAKHIR jika software gagal (disconnect, crash, dll)
### Perhitungan
```python
# Konfigurasi: 2% dari modal
emergency_sl_percent = 2.0
emergency_sl_usd = 5000 * 0.02 = $100 # Max loss jika software gagal
# Hitung jarak SL
pip_value = lot_size * 10 # 0.01 lot -> $0.10/pip
emergency_pips = $100 / $0.10 = 1000 pips
price_distance = 1000 * 0.01 = $10.00
# SL price
BUY: SL = entry - $10.00 = $4940.00
SELL: SL = entry + $10.00 = $4960.00
```
### Kapan Emergency SL Tercapai?
Seharusnya **tidak pernah** — software SL ($50) akan menutup jauh sebelum emergency SL ($100). Emergency SL hanya tercapai jika:
- Bot crash / disconnect
- Server bermasalah
- Internet putus
- Harga gap melewati semua level
---
## Layer 4: Circuit Breaker
**Sumber:** `risk_engine.py` (Lines 143-151)
**Fungsi:** Halt trading total saat kondisi darurat
```python
# Flash crash: Pergerakan > 2.5% dalam waktu singkat
if price_move > flash_crash_threshold:
activate_circuit_breaker("Flash crash detected")
# Tutup SEMUA posisi
# Block semua trade baru
# Kirim alert Telegram
# Daily loss limit
if daily_pnl_percent <= -5.0%:
activate_circuit_breaker("Daily loss limit breached")
```
---
## Pengiriman SL ke Broker (main_live.py)
### Flow Pengiriman
```python
# Step 1: Ambil SL dari SMC signal (ATR-based)
broker_sl = signal.stop_loss
# Step 2: Validasi jarak minimum (10 pips untuk XAUUSD)
min_sl_distance = 1.0 # $1 = 10 pips
if direction == "BUY":
if current_price - broker_sl < 1.0:
broker_sl = current_price - 2.0 # Paksa lebih lebar
if direction == "SELL":
if broker_sl - current_price < 1.0:
broker_sl = current_price + 2.0 # Paksa lebih lebar
# Step 3: Kirim order DENGAN SL
result = mt5.send_order(
sl=broker_sl, # SL AKTIF di broker
tp=signal.take_profit,
...
)
# Step 4: Fallback jika broker reject (error 10016)
if not result.success and retcode == 10016:
# SL terlalu dekat / tidak valid
result = mt5.send_order(
sl=0, # Tanpa broker SL
comment="AI Safe v3 NoSL"
)
# Software SL tetap aktif sebagai proteksi
```
---
## Tabel Ringkasan Layer SL
| Layer | Sumber | Jarak dari Entry | Max Loss | Kondisi Trigger |
|-------|--------|-----------------|----------|-----------------|
| **1. SMC ATR** | Broker SL aktif | 1.5 ATR (~$12-15) | ~$15-30 | Harga hit SL level |
| **2. Software** | Bot monitoring | Dinamis | $25-50 | Loss threshold + konteks |
| **3. Emergency** | Broker safety net | 2% modal ($10) | $100 | Software gagal |
| **4. Circuit** | Halt total | Semua posisi | Unlimited cap | Flash crash / daily limit |
---
## Skenario Proteksi
### Skenario 1: Trading Normal
```
Entry BUY @ $4950, SL broker @ $4937 (1.5 ATR)
-> Harga turun ke $4938 -> Masih aman
-> Harga turun ke $4936 -> BROKER SL HIT -> Tutup otomatis
-> Loss: ~$14 (0.01 lot)
```
### Skenario 2: Connection Lost
```
Entry BUY @ $4950, SL broker @ $4937
-> Bot disconnect
-> Harga turun drastis ke $4920
-> BROKER SL sudah aktif di $4937 -> Tutup otomatis
-> Loss: ~$13 (bukan unlimited!)
```
### Skenario 3: Weekend Gap
```
Jumat: Entry BUY @ $4950, SL broker @ $4937
-> Senin buka gap di $4910 (melewati SL)
-> Broker eksekusi SL di harga terbaik ~$4910
-> Loss: ~$40 (lebih dari SL tapi terproteksi)
```
### Skenario 4: Flash Crash (Tanpa Broker SL Fallback)
```
Entry BUY @ $4950, sl=0 (broker reject)
-> Harga jatuh cepat ke $4925
-> Software: loss = $25 >= 50% max -> TUTUP
-> Loss: ~$25 (software protect)
-> Jika software juga gagal:
Emergency SL @ $4940 -> TUTUP
-> Loss: ~$100 max
```
+296
View File
@@ -0,0 +1,296 @@
# Take Profit (T/P) — Sistem Pengambilan Profit Cerdas
> **File terkait:** `src/smc_polars.py`, `main_live.py`, `src/smart_risk_manager.py`
---
## Apa Itu Take Profit di Bot Ini?
Take Profit bukan hanya satu target harga — ini adalah **sistem multi-layer** yang secara cerdas memutuskan kapan mengambil profit berdasarkan momentum, probabilitas, dan peak tracking.
**Analogi:** TP di bot ini seperti **pemanen buah pintar** — tahu kapan buah sudah matang (hard TP), kapan cuaca akan buruk (momentum drop), dan kapan panen sebelum busuk (peak protection).
---
## Layer Take Profit
```
Layer 1: Broker TP <- Target harga dikirim ke broker (SMC-generated)
Layer 2: Hard TP <- Software tutup jika profit >= $40
Layer 3: Momentum TP <- Tutup jika profit bagus tapi momentum turun
Layer 4: Peak Protection <- Tutup jika profit turun dari peak
Layer 5: Probability TP <- Tutup jika probabilitas capai TP rendah
Layer 6: Early Exit <- Tutup profit kecil jika reversal terdeteksi
```
---
## Layer 1: Broker TP (SMC-Generated)
**Sumber:** `smc_polars.py` (Lines 654-659, 704-709)
**Dikirim ke:** Broker MT5 sebagai TP order aktif
### Perhitungan
```python
# ATR-based TP cap
atr = latest["atr"] # Contoh: ATR = $8.50
max_tp_distance = 4.0 * atr # 4 * 8.50 = $34.00
# Untuk BUY:
risk = entry - sl # $4950 - $4937 = $13
tp = entry + (risk * 2) # $4950 + $26 = $4976 (2:1 RR)
if tp > entry + max_tp_distance: # $4976 vs $4950 + $34 = $4984
tp = entry + max_tp_distance # Tidak kena cap, tetap $4976
# Untuk SELL:
risk = sl - entry # $4963 - $4950 = $13
tp = entry - (risk * 2) # $4950 - $26 = $4924 (2:1 RR)
if tp < entry - max_tp_distance: # $4924 vs $4950 - $34 = $4916
tp = entry - max_tp_distance # Tidak kena cap, tetap $4924
```
### Kenapa TP Di-cap 4 ATR?
```
Sebelum (v2): TP = risk * 2 (tanpa batas)
-> Bisa sangat jauh ($50+ dari entry)
-> Jarang tercapai, posisi terbuka terlalu lama
Sesudah (v3): TP = MIN(risk * 2, 4 * ATR)
-> Dibatasi maksimal 4x ATR
-> Target lebih realistis, lebih sering tercapai
```
### Dikirim ke Broker
```python
# main_live.py
result = mt5.send_order(
sl=broker_sl,
tp=signal.take_profit, # <- TP dari SMC (ATR-capped)
...
)
```
Jika harga mencapai TP level, broker otomatis menutup posisi — tidak perlu bot online.
---
## Layer 2: Hard Take Profit ($40)
**Sumber:** `smart_risk_manager.py` (Lines 595-599)
```python
# Profit mencapai $40+ -> langsung tutup
if current_profit >= 40:
return True, ExitReason.TAKE_PROFIT,
"[TP] Target profit reached: $40.00"
```
**Kenapa $40?** Ini threshold profit yang cukup besar untuk diamankan, terlepas dari kondisi pasar.
---
## Layer 3: Momentum-Based TP ($25+)
**Sumber:** `smart_risk_manager.py` (Lines 601-603)
```python
# Profit $25+ tapi momentum turun -> amankan profit
if current_profit >= 25 and momentum < -30:
return True, ExitReason.TAKE_PROFIT,
"[SECURE] Securing $25.00 (momentum dropping)"
```
### Bagaimana Momentum Dihitung
```python
# PositionGuard.calculate_momentum() (Lines 113-131)
# Melihat 5 profit history terakhir
recent_profits = profit_history[-5:]
profit_change = recent_profits[-1] - recent_profits[0]
# Normalisasi: $10 change = 50 poin
momentum = (profit_change / 10) * 50
# Range: -100 sampai +100
# momentum < -30 artinya profit sedang TURUN cukup cepat
```
**Visualisasi:**
```
Profit ($)
40 |
35 | /\
30 | / \ <- Momentum mulai negatif
25 |------/----\------ Layer 3 trigger: amankan!
20 | / \
15 | / \
10 | / \
5 | /
0 |_/________________________> waktu
```
---
## Layer 4: Peak Protection ($30+ peak)
**Sumber:** `smart_risk_manager.py` (Lines 605-607)
```python
# Profit pernah $30+ tapi sekarang turun ke 60% dari peak
if guard.peak_profit > 30 and current_profit < guard.peak_profit * 0.6:
return True, ExitReason.TAKE_PROFIT,
"[LOCK] Securing profit (was $35 peak)"
```
### Cara Kerja Peak Tracking
```python
# Setiap evaluasi, update peak profit
guard.peak_profit = max(guard.peak_profit, current_profit)
# Contoh:
# Peak: $35 -> 60% = $21
# Current: $18 (turun dari $35)
# $18 < $21 -> TUTUP, lindungi sisa profit
```
**Visualisasi:**
```
Profit ($)
35 | * <- peak_profit = $35
30 | / \
25 | / \
21 |./.....\....... 60% threshold ($21)
18 | \* <- current = $18, TUTUP!
15 | \
10 | (kehilangan lebih banyak dihindari)
```
---
## Layer 5: Probability-Based TP ($20+)
**Sumber:** `smart_risk_manager.py` (Lines 609-611)
```python
# Probabilitas capai TP rendah + profit cukup -> ambil sekarang
if tp_probability < 25 and current_profit >= 20:
return True, ExitReason.TAKE_PROFIT,
"[PROB] Taking profit $20 (TP prob: 15%)"
```
### Cara Hitung TP Probability
```python
# PositionGuard.get_tp_probability() (Lines 133-168)
# Score 0-100% berdasarkan 4 faktor:
Factor 1: Progress ke TP (0-40 poin)
progress = (current_profit / target_tp_profit) * 100
-> Makin dekat ke TP = skor tinggi
Factor 2: Momentum (0-30 poin)
-> Momentum positif = skor tinggi
Factor 3: ML Confidence Trend (0-20 poin)
-> ML confidence naik = skor tinggi
Factor 4: Time Penalty (0-10 poin DIKURANGI)
-> 2 poin per jam (makin lama = makin rendah)
probability = factor1 + factor2 + factor3 - time_penalty
```
---
## Layer 6: Early Exit (Profit Kecil + Reversal)
**Sumber:** `smart_risk_manager.py` (Lines 617-627)
```python
# Profit $5-$15 + momentum sangat buruk + ML reversal
if 5 <= current_profit < 15:
if momentum < -50 and ml_confidence >= 0.65:
if ml_signal berlawanan dengan posisi:
return True, ExitReason.TAKE_PROFIT,
"Early exit - reversal detected"
```
**Logika:** Lebih baik ambil profit kecil ($5-$15) daripada menunggu profit hilang karena reversal.
---
## Prioritas Exit (Urutan Pengecekan)
```
1. Hard TP ($40+) <- Paling prioritas
2. Momentum TP ($25+, mom<-30)
3. Peak Protection ($30+ peak, <60%)
4. Probability TP ($20+, prob<25%)
5. Early Exit ($5-15, reversal)
6. Broker TP (harga hit level) <- Independen dari software
```
**Catatan:** Broker TP berjalan independen — jika harga hit TP level di broker, posisi tertutup otomatis meskipun bot offline.
---
## Contoh Skenario
### Skenario 1: TP Broker Hit
```
Entry BUY @ $4950, TP broker @ $4976
-> Harga naik ke $4976
-> BROKER TP HIT -> Tutup otomatis
-> Profit: ~$26 (0.01 lot = $2.60)
```
### Skenario 2: Software TP Lebih Cepat
```
Entry BUY @ $4950, TP broker @ $4990
-> Harga naik ke $4990 (profit $40)
-> Software: profit >= $40 -> HARD TP
-> Tutup sebelum broker TP level
```
### Skenario 3: Momentum Drop
```
Entry BUY @ $4950
-> Profit naik: $10 -> $20 -> $28 -> $25
-> momentum = -35 (turun)
-> Software: profit $25 + momentum < -30
-> MOMENTUM TP: amankan $25
```
### Skenario 4: Peak Protection
```
Entry BUY @ $4950
-> Profit naik: $15 -> $25 -> $35 (peak!)
-> Profit turun: $35 -> $30 -> $22 -> $19
-> 60% dari $35 = $21
-> $19 < $21 -> PEAK PROTECTION: amankan $19
(tanpa ini, profit bisa turun ke $0 atau bahkan loss)
```
---
## Tabel Ringkasan Layer TP
| Layer | Trigger | Profit Min | Kondisi Tambahan |
|-------|---------|-----------|------------------|
| **1. Broker TP** | Harga hit level | - | Otomatis, independen |
| **2. Hard TP** | profit >= $40 | $40 | Tidak ada |
| **3. Momentum TP** | profit >= $25 | $25 | momentum < -30 |
| **4. Peak Protection** | peak > $30 | ~$18+ | current < 60% peak |
| **5. Probability TP** | profit >= $20 | $20 | TP probability < 25% |
| **6. Early Exit** | profit $5-15 | $5 | ML reversal + momentum < -50 |
+353
View File
@@ -0,0 +1,353 @@
# Entry Trade — Proses Masuk Posisi
> **File utama:** `main_live.py`
> **File pendukung:** `src/smc_polars.py`, `src/ml_model.py`, `src/smart_risk_manager.py`, `src/session_filter.py`
---
## Apa Itu Entry Trade?
Entry Trade adalah keseluruhan proses dari **mendeteksi peluang** hingga **mengirim order ke broker**. Bot menggunakan **10+ filter** yang harus SEMUA lolos sebelum satu trade dieksekusi.
**Analogi:** Entry Trade seperti **proses boarding pesawat** — harus punya tiket (signal), passport valid (confirmation), lulus security check (risk), tepat waktu (session), dan gate terbuka (position limit).
---
## Checklist Entry (Semua Harus PASS)
```
1. [SESSION] Session filter izinkan trading?
2. [RISK MODE] Trading mode bukan STOPPED?
3. [SMC SIGNAL] Ada signal dari SMC Analyzer?
4. [ML CONFIRM] XGBoost confidence >= 50%?
5. [ML AGREE] ML tidak strongly disagree (>65% berlawanan)?
6. [QUALITY] Market quality bukan AVOID/CRISIS?
7. [CONFIRM] Signal konsisten 2 bar berturut?
8. [PULLBACK] Bukan sedang pullback/retrace?
9. [COOLDOWN] Sudah 5 menit sejak trade terakhir?
10. [POS LIMIT] Posisi terbuka < 2?
11. [LOT SIZE] Lot > 0 setelah semua adjustment?
SEMUA PASS -> Execute Trade
SATU GAGAL -> Skip, tunggu loop berikutnya
```
---
## Step-by-Step Flow
### Step 1: Session Filter
```python
# main_live.py Lines 472-483
session_ok, session_reason, session_multiplier = self.session_filter.can_trade()
if not session_ok:
return # Skip — bukan waktu trading
# Simpan multiplier untuk lot sizing nanti
self._current_session_multiplier = session_multiplier
```
**Bisa block:** Weekend, Friday >23:00, danger zone (00:00-06:00), low volatility session.
---
### Step 2: Risk Mode Check
```python
# main_live.py Lines 537-542
risk_rec = self.smart_risk.get_trading_recommendation()
if not risk_rec["can_trade"]:
return # STOPPED mode — daily/total limit tercapai
```
**Bisa block:** Mode STOPPED (daily loss >= $250, total loss >= $500).
---
### Step 3: SMC Signal Generation
```python
# main_live.py Lines 498-499
smc_signal = self.smc.generate_signal(df)
if smc_signal is None:
return # Tidak ada setup SMC yang valid
```
**SMC membutuhkan:**
- Market structure (bullish/bearish) ATAU BOS/CHoCH
- DAN (FVG ATAU Order Block)
- Minimum 2:1 risk/reward
**Output:** Entry price, SL, TP, confidence (55-85%), reason.
---
### Step 4: ML Confidence Check
```python
# main_live.py Lines 419-425
ml_prediction = self.ml_model.predict(df, feature_cols)
# Lines 664-669
if ml_prediction.confidence < 0.50:
return # ML terlalu tidak yakin
```
---
### Step 5: ML Agreement Check
```python
# main_live.py Lines 676-684
# Jika SMC bilang BUY tapi ML bilang SELL dengan confidence > 65%:
if smc_signal.signal_type == "BUY":
if ml_prediction.signal == "SELL" and ml_prediction.confidence > 0.65:
return # ML strongly disagrees — VETO
if smc_signal.signal_type == "SELL":
if ml_prediction.signal == "BUY" and ml_prediction.confidence > 0.65:
return # ML strongly disagrees — VETO
```
---
### Step 6: Dynamic Market Quality
```python
# main_live.py Lines 618-657
# Analisis kualitas pasar berdasarkan:
# - Session (London/NY = tinggi, Sydney = rendah)
# - Regime (low vol = bagus, crisis = block)
# - Volatility (medium = ideal)
# - Trend strength
# - SMC confluence
# - ML signal alignment
quality_score = analyze_market_quality(...)
# EXCELLENT (80+), GOOD (60+), MODERATE (40+), POOR (20+), AVOID (<20), CRISIS
if quality == "AVOID" or quality == "CRISIS":
return # Pasar tidak layak untuk trading
```
---
### Step 7: Signal Confirmation (2 Bar Berturut)
```python
# main_live.py Lines 686-709
signal_key = f"{smc_signal.signal_type}_{smc_signal.entry_price:.0f}"
if signal_key in self._signal_persistence:
self._signal_persistence[signal_key] += 1
else:
self._signal_persistence[signal_key] = 1
if self._signal_persistence[signal_key] < 2:
return # Belum dikonfirmasi — tunggu 1 loop lagi
# Signal sudah muncul 2x berturut -> CONFIRMED
```
**Tujuan:** Mencegah whipsaw — signal yang hanya muncul 1 detik kemungkinan noise.
---
### Step 8: Pullback Filter
```python
# main_live.py Lines 742-871
can_enter, pullback_reason = self._check_pullback_filter(df, signal.signal_type)
if not can_enter:
return # Sedang pullback, tunggu momentum selaras
```
**Untuk signal BUY, block jika:**
- Harga turun > $2 dalam 3 candle terakhir
- MACD bearish + harga turun
- Harga jauh di bawah EMA9 + terus turun
**Untuk signal SELL, block jika:**
- Harga naik > $2 dalam 3 candle terakhir
- MACD bullish + harga naik
- Harga jauh di atas EMA9 + terus naik
**Komponen yang dicek:**
```
1. Short-term Momentum (3 candle terakhir)
-> Arah pergerakan harga terkini
2. MACD Histogram
-> Rising = bullish momentum
-> Falling = bearish momentum
3. Harga vs EMA9
-> Di atas = bullish bias
-> Di bawah = bearish bias
4. RSI Extreme
-> RSI > 80 = overbought (block BUY)
-> RSI < 20 = oversold (block SELL)
```
---
### Step 9: Trade Cooldown
```python
# main_live.py Lines 520-524
trade_cooldown = 300 # 5 menit
if last_trade_time:
elapsed = (now - last_trade_time).total_seconds()
if elapsed < trade_cooldown:
return # Tunggu cooldown selesai
```
**Tujuan:** Mencegah overtrading — minimal 5 menit antar trade.
---
### Step 10: Position Limit
```python
# main_live.py Lines 588-592
can_open, limit_reason = self.smart_risk.can_open_position()
if not can_open:
return # Sudah 2 posisi terbuka (max)
```
---
### Step 11: Lot Size Calculation
```python
# main_live.py Lines 544-560
safe_lot = self.smart_risk.calculate_lot_size(
entry_price=signal.entry_price,
confidence=signal.confidence, # SMC confidence
regime=regime_name, # HMM regime
ml_confidence=ml_prediction.confidence, # ML confidence
)
# Apply session multiplier
safe_lot = max(0.01, safe_lot * session_multiplier)
if safe_lot <= 0:
return # Lot 0 = tidak boleh trade
```
---
## Eksekusi Order
Setelah semua 11 filter lolos:
```python
# main_live.py Lines 985-1008
# Step A: Ambil harga real-time
tick = mt5.get_tick(symbol)
current_price = tick.ask if BUY else tick.bid
# Step B: Validasi broker SL (min 10 pips)
broker_sl = signal.stop_loss
if jarak_terlalu_dekat:
broker_sl = paksa_lebih_lebar
# Step C: Kirim order
result = mt5.send_order(
symbol="XAUUSD",
order_type="BUY" / "SELL",
volume=0.01 - 0.02, # Lot dari risk calculation
sl=broker_sl, # ATR-based SL (v3)
tp=signal.take_profit, # SMC TP (ATR-capped)
magic=123456, # ID bot
comment="AI Safe v3",
)
# Step D: Fallback jika broker reject SL
if gagal dan error 10016:
result = mt5.send_order(sl=0, ...) # Tanpa broker SL
# Step E: Register posisi untuk monitoring
if result.success:
smart_risk.register_position(
ticket=result.order_id,
entry_price=signal.entry_price,
lot_size=position.lot_size,
direction=signal.signal_type,
)
```
---
## Post-Entry
```python
# Step F: Log trade detail
trade_logger.log_trade_open(
signal, ml_prediction, regime, market_quality, ...
)
# Step G: Kirim notifikasi Telegram
await telegram.send_trade_open(trade_info)
# Step H: Update cooldown timer
last_trade_time = now
```
---
## Diagram Flow Lengkap
```
Loop setiap 1 detik
|
v
Fetch 200 bar M15 -> Feature Eng -> SMC -> HMM -> XGBoost
|
v
[1] Session OK? ----NO----> Skip
|YES
[2] Risk OK? -------NO----> Skip (STOPPED)
|YES
[3] SMC Signal? ----NO----> Skip (tidak ada setup)
|YES
[4] ML >= 50%? -----NO----> Skip (terlalu uncertain)
|YES
[5] ML Agree? ------NO----> Skip (ML veto)
|YES
[6] Quality OK? ----NO----> Skip (AVOID/CRISIS)
|YES
[7] Confirmed 2x? --NO----> Skip (tunggu konfirmasi)
|YES
[8] No Pullback? ---NO----> Skip (retrace)
|YES
[9] Cooldown OK? ---NO----> Skip (< 5 menit)
|YES
[10] Pos < 2? ------NO----> Skip (full)
|YES
[11] Lot > 0? ------NO----> Skip
|YES
v
EXECUTE TRADE -> Register -> Log -> Telegram
```
---
## Statistik Filter
Dalam kondisi normal, dari ratusan loop per jam:
- **~95%** diblokir oleh "tidak ada SMC signal" (pasar sideways)
- **~3%** diblokir oleh ML disagreement atau low confidence
- **~1%** diblokir oleh pullback filter atau session
- **<1%** lolos semua filter dan menghasilkan trade
**Rata-rata:** 3-8 trade per hari (sangat selektif).
+330
View File
@@ -0,0 +1,330 @@
# Exit Trade — Proses Keluar Posisi
> **File utama:** `main_live.py`, `src/smart_risk_manager.py`
> **File pendukung:** `src/position_manager.py`
---
## Apa Itu Exit Trade?
Exit Trade adalah keseluruhan proses **monitoring posisi terbuka** dan **memutuskan kapan menutup**. Bot memeriksa setiap posisi terbuka **setiap 1 detik** dengan 10 kondisi exit berbeda.
**Analogi:** Exit Trade seperti **pilot otomatis di pesawat** — terus monitor ketinggian (profit), cuaca (momentum), bahan bakar (waktu), dan bisa landing darurat kapan saja.
---
## 2 Jalur Exit
```
Jalur 1: BROKER EXIT (otomatis, independen)
-> Harga hit TP level -> tutup otomatis
-> Harga hit SL level -> tutup otomatis
-> Tidak perlu bot online
Jalur 2: SOFTWARE EXIT (cerdas, kontekstual)
-> Bot evaluasi setiap 1 detik
-> Mempertimbangkan momentum, ML, waktu, dll
-> 10 kondisi exit berbeda
```
---
## Monitoring Loop
```python
# main_live.py Lines 1117-1215
# Setiap 1 detik, untuk SETIAP posisi terbuka:
for position in open_positions:
# Update data posisi
current_price = mt5.get_tick(symbol)
current_profit = position.profit
# Update history untuk analisis momentum
guard.update_history(current_price, current_profit, ml_confidence)
# Evaluasi: haruskah ditutup?
should_close, reason, message = smart_risk.evaluate_position(
ticket=ticket,
current_price=current_price,
current_profit=profit,
ml_signal=ml_prediction.signal,
ml_confidence=ml_prediction.confidence,
regime=regime_state,
)
if should_close:
# Tutup posisi
close_position(ticket, reason)
```
---
## 10 Kondisi Exit (Urutan Pengecekan)
### CHECK 1: Smart Take Profit (profit >= $15)
```
Ketika profit sudah cukup besar, evaluasi apakah harus diamankan:
a) Hard TP: profit >= $40
-> TUTUP langsung, target tercapai
b) Momentum TP: profit >= $25 DAN momentum < -30
-> TUTUP, profit sedang turun cepat
c) Peak Protection: peak > $30 DAN current < 60% peak
-> TUTUP, lindungi dari drawback lebih dalam
d) Probability TP: TP_prob < 25% DAN profit >= $20
-> TUTUP, kemungkinan capai TP sudah rendah
e) Strong Momentum: momentum >= 0
-> HOLD, biarkan profit berjalan (let it run)
```
---
### CHECK 2: Early Exit Small Profit ($5-$15)
```
Profit masih kecil tapi ada tanda bahaya:
IF profit $5-$15
AND momentum < -50 (turun sangat cepat)
AND ML confidence >= 65% berlawanan arah:
-> TUTUP, ambil profit kecil sebelum hilang
```
---
### CHECK 3: Smart Hold for Golden Time
```
Posisi sedang rugi tapi ada potensi recovery:
IF profit < 0 DAN BUKAN golden time:
a) Loss >= 30% max DAN momentum < -30
-> TUTUP CEPAT (early cut)
b) Loss < 30% DAN golden_time <= 3 jam DAN momentum > -50
-> HOLD, tunggu recovery di golden time
c) Loss < 20% DAN jam 15:00-19:00 WIB (London) DAN momentum > -40
-> HOLD, sesi aktif masih bisa recovery
```
---
### CHECK 4: Trend Reversal Detection
```
ML mendeteksi perubahan tren:
IF ML confidence >= 65% berlawanan dengan posisi:
a) Loss > 40% max DAN profit < -$8
-> TUTUP (reversal + loss signifikan)
b) Akumulasi 3x reversal warning DAN loss < -$10
-> TUTUP (multiple warnings = konfirmasi reversal)
c) Belum memenuhi threshold
-> reversal_warnings += 1 (catat warning)
```
---
### CHECK 5: Maximum Loss Per Trade
```
Loss mencapai batas toleransi:
IF loss >= 50% dari max_loss ($25 dari $50):
Exception: golden_time <= 1 jam DAN momentum > -40
-> HOLD (kesempatan terakhir recovery)
Selain itu:
-> TUTUP [S/L] Position loss limit
```
---
### CHECK 6: Stall Detection
```
Harga tidak bergerak kemana-mana:
IF 10 candle terakhir range profit < $3
AND current_profit < -$15:
stall_count += 1
IF stall_count >= 5:
-> TUTUP [STALL] Harga stuck, buang waktu & margin
```
---
### CHECK 7: Daily Loss Limit
```
Mencegah daily loss limit terlampaui:
potential_daily_loss = daily_loss + abs(min(0, current_profit))
IF potential_daily_loss >= max_daily_loss ($250):
-> TUTUP [LIMIT] Akan melampaui batas harian
```
---
### CHECK 8: Weekend Close
```
Proteksi dari gap weekend:
IF hari Jumat setelah 04:00 WIB:
a) profit > 0
-> TUTUP [WEEKEND] Amankan profit
b) profit > -$10
-> TUTUP [WEEKEND] Loss kecil, hindari gap
c) profit <= -$10
-> HOLD (loss terlalu besar untuk cut, evaluasi manual)
```
---
### CHECK 9: Time-Based Exit (v3 BARU)
```
Mencegah posisi "zombie" yang stuck:
trade_duration = (sekarang - entry_time) dalam jam
IF 4+ jam DAN profit < $5:
a) profit >= $0
-> TUTUP [TIMEOUT] Breakeven setelah 4 jam
b) profit > -$15
-> TUTUP [TIMEOUT] Loss kecil, daripada stuck
IF 6+ jam (apapun profit):
-> TUTUP [MAX TIME] Force exit — max hold 6 jam
```
**Visualisasi:**
```
Jam: 0 1 2 3 4 5 6
|-----|-----|-----|-----|-----|-----|
entry | |
| |
4h check: 6h FORCE EXIT
profit<$5?
Ya -> exit
```
---
### CHECK 10: Default — HOLD
```
Tidak ada kondisi exit terpenuhi:
-> HOLD posisi
-> Log status: momentum, TP probability, ML signal
-> Evaluasi ulang di loop berikutnya (1 detik kemudian)
```
---
## Exit Reason Enum
| Reason | Kode | Deskripsi |
|--------|------|-----------|
| `TAKE_PROFIT` | take_profit | Target profit tercapai |
| `TREND_REVERSAL` | trend_reversal | ML deteksi reversal |
| `DAILY_LIMIT` | daily_limit | Batas harian tercapai |
| `POSITION_LIMIT` | position_limit | Max loss per trade |
| `TOTAL_LIMIT` | total_limit | Batas total tercapai |
| `WEEKEND_CLOSE` | weekend_close | Penutupan Jumat |
| `TIMEOUT` | timeout | Time-based exit (4h/6h) |
| `STALL` | stall | Harga stuck |
| `MANUAL` | manual | Penutupan manual |
---
## Post-Exit Flow
```python
# Setelah posisi ditutup:
# 1. Record hasil trade
risk_result = smart_risk.record_trade_result(profit)
# Update: daily_loss, total_loss, consecutive_losses, mode
# 2. Unregister dari monitoring
smart_risk.unregister_position(ticket)
# 3. Log trade
trade_logger.log_trade_close(
ticket, entry_price, exit_price, profit, pips,
duration, exit_reason, ml_signal, regime, ...
)
# 4. Kirim notifikasi Telegram
await telegram.send_trade_close(trade_info)
# Format: WIN/LOSS/BE, P/L, pips, duration, balance
# 5. Cek limit violations
if risk_result["daily_limit_hit"]:
await send_critical_alert("DAILY LOSS LIMIT")
# Mode -> STOPPED, tidak ada trade lagi hari ini
if risk_result["total_limit_hit"]:
await send_critical_alert("TOTAL LOSS LIMIT")
# Mode -> STOPPED permanen
```
---
## Diagram Exit Flow
```
Setiap 1 detik, per posisi terbuka:
|
v
Update profit & momentum
|
v
[1] Profit >= $15? ----YES---> Smart TP evaluation
|NO (hard/$40, momentum, peak, prob)
v
[2] Profit $5-$15? ----YES---> Reversal + momentum drop?
|NO -> Early exit
v
[3] Profit < 0? -------YES---> Golden time hold?
|NO Early cut if weak?
v
[4] ML Reversal 65%+? -YES---> Loss > 40%? -> TUTUP
|NO Else warning++
v
[5] Loss >= 50% max? --YES---> TUTUP (kecuali golden time)
|NO
v
[6] Stall 10+ candle? -YES---> stall++ -> 5x? TUTUP
|NO
v
[7] Daily limit? ------YES---> TUTUP
|NO
v
[8] Friday close? -----YES---> TUTUP (profit>0 atau loss>-$10)
|NO
v
[9] Time >= 4h? -------YES---> profit<$5? TUTUP
| Time >= 6h? ---YES---> FORCE EXIT
|NO
v
[10] HOLD -> evaluasi ulang 1 detik kemudian
```
+212
View File
@@ -0,0 +1,212 @@
# News Agent — Monitoring Berita Ekonomi
> **File:** `src/news_agent.py`
> **Class:** `NewsAgent`
> **Status:** Aktif tapi **TIDAK MEMBLOKIR** trading (monitoring only)
---
## Apa Itu News Agent?
News Agent memonitor **berita ekonomi high-impact** (NFP, FOMC, CPI) yang bisa menyebabkan volatilitas ekstrem di pasar gold. Awalnya dirancang untuk memblokir trading saat news, tapi setelah backtest menunjukkan bahwa blocking justru **kehilangan $178 profit**, sekarang hanya berfungsi sebagai **monitor dan logger**.
**Analogi:** News Agent seperti **stasiun cuaca** — melaporkan badai yang datang, tapi pilot (bot) tetap terbang karena pesawat (ML model) sudah cukup tangguh menangani turbulensi.
---
## Kenapa Tidak Blocking?
```
Hasil Backtest (29 trades):
- Win rate tanpa filter: 64.9%
- Win rate saat news: 62.1% (selisih hanya 2.8%)
- Profit yang hilang jika filter aktif: $178.15
Kesimpulan:
-> ML model sudah cukup menangani volatilitas news
-> Blocking justru kehilangan peluang profit
-> Monitoring cukup, tidak perlu blocking
```
---
## Event yang Dipantau
### 3 Event High-Impact
| Event | Waktu (WIB) | Hari | Dampak ke Gold |
|-------|-------------|------|---------------|
| **NFP** (Non-Farm Payroll) | 20:30 | Jumat pertama bulan | Sangat tinggi |
| **FOMC** (Fed Decision) | 02:00 | ~8x per tahun | Sangat tinggi |
| **CPI** (Inflation) | 20:30 | Tgl 10-15 (Sel/Rab/Kam) | Tinggi |
### Deteksi Event
```python
# NFP: Jumat pertama bulan
if weekday == 4 and day <= 7: # Friday, day 1-7
if 19 <= hour <= 21: # 19:00-21:00 WIB
return "NFP (Non-Farm Payroll) - HIGH IMPACT"
# FOMC: Tanggal spesifik (hardcoded schedule)
fomc_dates = [
(1,29), (3,19), (5,7), (6,18), (7,30), # 2025
(9,17), (11,5), (12,17),
(1,29), (3,18), (5,6), (6,17), (7,29), # 2026
]
if (month, day) in fomc_dates:
if 1 <= hour <= 3: # 01:00-03:00 WIB
return "FOMC Decision - HIGH IMPACT"
# CPI: Sekitar tanggal 10-15, hari kerja
if 10 <= day <= 15 and 19 <= hour <= 21:
if weekday in [1, 2, 3]: # Selasa-Kamis
return "CPI (Inflation) - HIGH IMPACT"
```
---
## Buffer Times
| Parameter | Default | Aktif di Production |
|-----------|---------|-------------------|
| `news_buffer_minutes` | 30 menit | **0** (disabled) |
| `high_impact_buffer_minutes` | 60 menit | **0** (disabled) |
```python
# Inisialisasi di main_live.py
self.news_agent = create_news_agent(
news_buffer_minutes=0, # No blocking
high_impact_buffer_minutes=0, # No blocking
)
```
---
## Market Condition States
| Kondisi | Bisa Trade? | Lot Multiplier | Trigger |
|---------|------------|---------------|---------|
| `SAFE` | Ya | 1.0x | Tidak ada news |
| `CAUTION` | Ya | 0.5x | News medium-impact |
| `DANGER_NEWS` | Tidak* | 0.0x | High-impact news |
| `DANGER_SENTIMENT` | Tidak* | 0.5x | Sentimen sangat bearish |
*\*Di production, DANGER tetap diizinkan trading (monitoring only)*
---
## Analisis Sentimen
News Agent juga bisa menganalisis headline berita berdasarkan keyword:
### Keyword Bullish (untuk Gold)
```
Geopolitical: war, conflict, invasion, crisis, escalation
Economic: rate cut, dovish, easing, recession, stimulus
Market: safe haven, gold surge, gold rally, buy gold
```
### Keyword Bearish (untuk Gold)
```
Geopolitical: peace deal, ceasefire, de-escalation
Economic: rate hike, hawkish, tightening, strong dollar
Market: risk on, stocks rally, sell gold, gold crash
```
### Keyword Volatile
```
breaking, urgent, flash, sudden, unexpected, shock, crash, spike
```
### Scoring
```
Setiap keyword match:
Bullish: +0.3
Bearish: -0.3
Volatile: -0.1 (penalty)
Score range: -1.0 (sangat bearish) sampai +1.0 (sangat bullish)
Confidence berdasarkan jumlah keyword yang match
```
---
## Method `should_trade()`
```python
def should_trade(headlines=None) -> (bool, str, float):
"""
Returns:
can_trade: bool <- Apakah aman trading
reason: str <- Alasan
lot_multiplier: float <- Pengali lot (0.0-1.0)
"""
# 1. Cek economic calendar (MT5 + hardcoded events)
# 2. Analisis sentimen (jika ada headlines)
# 3. Tentukan kondisi pasar
# 4. Return rekomendasi
```
---
## Integrasi di Main Loop
```python
# main_live.py Lines 485-496
# NEWS AGENT MONITORING (NO BLOCKING)
can_trade_news, news_reason, news_lot_mult = self.news_agent.should_trade()
# Hanya LOG, TIDAK block
if not can_trade_news and loop_count % 300 == 0: # Setiap 5 menit
logger.info(f"News Agent: HIGH IMPACT NEWS - {news_reason} (trading allowed)")
# Catatan:
# - news_lot_mult dihitung tapi TIDAK diterapkan
# - Trading tetap berjalan normal
# - Informasi digunakan untuk logging dan analisis
```
---
## Sumber Data
| Sumber | Status | Keterangan |
|--------|--------|-----------|
| **MT5 Calendar** | Aktif | Cek economic calendar dari terminal |
| **Hardcoded Events** | Aktif (Fallback) | NFP, FOMC, CPI schedule |
| **NewsAPI** | Tersedia, tidak digunakan | External API (butuh API key) |
| **ForexFactory** | Tersedia, tidak diimplementasi | Placeholder untuk scraping |
---
## Konfigurasi
```python
NewsAgent(
news_buffer_minutes=30, # Buffer news biasa (disabled: 0)
high_impact_buffer_minutes=60, # Buffer high-impact (disabled: 0)
enable_mt5_calendar=True, # Cek MT5 calendar
enable_sentiment=True, # Analisis sentimen
)
# Cache
_cache_duration = 15 menit # Cache hasil calendar check
```
---
## Contoh Output Log
```
[14:30] News Agent: HIGH IMPACT NEWS - NFP (Non-Farm Payroll) (trading allowed)
[14:35] News Agent: Market condition SAFE - no upcoming events
[20:25] News Agent: HIGH IMPACT NEWS - CPI (Inflation) (trading allowed)
```
**Catatan:** Meskipun terdeteksi "HIGH IMPACT NEWS", bot tetap trading. Log ini berguna untuk analisis post-trade — apakah trade yang terjadi saat news perform baik atau buruk.
@@ -0,0 +1,380 @@
# Telegram Notifications — Sistem Notifikasi Real-Time
> **File:** `src/telegram_notifier.py`
> **Class:** `TelegramNotifier`
> **API:** Telegram Bot API (async via aiohttp)
---
## Apa Itu Telegram Notifications?
Telegram Notifications mengirimkan **laporan real-time** ke grup Telegram setiap kali terjadi event penting — trade dibuka/ditutup, laporan harian, alert darurat, dan status sistem.
**Analogi:** Telegram Notifications seperti **dashboard pilot di cockpit** — menampilkan semua informasi penting secara real-time tanpa harus melihat layar trading.
---
## Konfigurasi
```
Bot Token: Dari environment variable TELEGRAM_BOT_TOKEN
Chat ID: Dari environment variable TELEGRAM_CHAT_ID
Format: HTML (parse_mode)
Transport: Async HTTP POST via aiohttp
Timezone: WIB (Asia/Jakarta)
```
```python
# Inisialisasi
from dotenv import load_dotenv
load_dotenv()
bot_token = os.getenv("TELEGRAM_BOT_TOKEN")
chat_id = os.getenv("TELEGRAM_CHAT_ID")
enabled = bool(bot_token and chat_id) # Auto-disable jika tidak dikonfigurasi
```
---
## 11 Tipe Notifikasi
| # | Tipe | Trigger | Frekuensi |
|---|------|---------|-----------|
| 1 | Trade Open | Order berhasil dieksekusi | Per trade |
| 2 | Trade Close | Posisi ditutup | Per trade |
| 3 | Market Update | Timer 30 menit | Setiap 30 menit |
| 4 | Hourly Analysis | Timer 1 jam | Setiap 1 jam |
| 5 | Daily Summary | Pergantian hari | 1x per hari |
| 6 | Startup | Bot dinyalakan | 1x per sesi |
| 7 | Shutdown | Bot dimatikan | 1x per sesi |
| 8 | News Alert | Event ekonomi terdeteksi | Per event |
| 9 | Critical Limit | Daily/total loss limit | Per event |
| 10 | Emergency Close | Flash crash / darurat | Per event |
| 11 | System Status | Status berkala | Per request |
---
## Format Pesan
### 1. Trade Open
```
🟢 LONG #123456
├ XAUUSD
├ Entry: 4950.00
├ Lot: 0.02
├ SL: 4937.00 (-$13)
├ TP: 4976.00 (+$26)
├ R:R: 1:2.0
├ AI: 75% | medium_volatility
└ SMC Bullish BOS + FVG
⏰ 14:35 WIB
```
| Elemen | Arti |
|--------|------|
| 🟢/🔴 | BUY (hijau) / SELL (merah) |
| LONG/SHORT | Arah posisi |
| #123456 | Ticket ID dari broker |
| R:R | Risk to Reward ratio |
| AI: 75% | ML confidence |
| medium_volatility | HMM regime |
---
### 2. Trade Close
```
✅ WIN #123456
├ XAUUSD BUY
├ Entry: 4950.00
├ Exit: 4965.00
├ Lot: 0.02
├ P/L: +$30.00 (+0.49%)
├ Pips: +150.0
├ Duration: 2m
├ Bal Before: $6130.00
└ Bal After: $6160.00
⏰ 14:40 WIB
```
| Emoji | Arti |
|-------|------|
| ✅ | WIN (profit) |
| ❌ | LOSS (rugi) |
| | BREAKEVEN (impas) |
---
### 3. Market Update (Setiap 30 Menit)
```
📊 XAUUSD $4965.00
├ 🟢 BUY 75%
├ UPTREND
├ medium_volatility
├ London-NY Overlap
└ ✅
⏰ 14:45
```
---
### 4. Hourly Analysis (Setiap 1 Jam)
```
📊 HOURLY 14:00 WIB
Account
├ Bal: $5,094.68
├ Eq: $5,120.50
├ Float: +$25.82
└ Day: +$150.00 (12 trades)
Positions (2)
├ #123456 BUY: +$30.00 M:+45
└ #123457 SELL: -$15.00 M:-20
Market
├ XAUUSD $4,965.00
├ London-NY Overlap
└ medium_volatility | high
AI Signal
├ BUY 75% / thresh 70%
└ Quality: EXCELLENT (score:85) → READY
Risk NORMAL
└ Daily Loss: $0.00 / $148.34
✅ News: SAFE
```
---
### 5. Daily Summary
```
🎉 DAILY REPORT 2025-02-06
Result
├ P/L: +$150.00 (+3.03%)
├ Gross Win: +$500.00
├ Gross Loss: -$350.00
├ Bal Start: $4,944.68
└ Bal End: $5,094.68
Stats
├ Total: 12 trades
├ Wins: 8 | Losses: 4
├ Win Rate: 66.7%
├ Profit Factor: 1.43
└ Avg/Trade: $12.50
Recent Trades
├ ✅ BUY: +$30.00
├ ❌ SELL: -$25.00
├ ✅ BUY: +$45.00
SELL: $0.00
└ ✅ BUY: +$100.00
```
| Emoji Hari | Arti |
|-----------|------|
| 🎉 | Hari profit |
| 📉 | Hari loss |
| | Hari breakeven |
---
### 6. Startup
```
🚀 BOT STARTED
Config
├ Symbol: XAUUSD
├ Mode: small
├ Capital: $5,000.00
├ Balance: $4,944.68
└ ML: Loaded (37 features)
Risk Settings
├ Risk/Trade: 1%
├ Max Daily Loss: 5%
├ Max Total Loss: 10%
└ SL: Smart (ATR-based)
✅ News: SAFE
⏰ 2025-02-06 08:15 WIB
```
---
### 7. Shutdown
```
🔴 BOT STOPPED
Session Summary
├ Balance: $5,094.68
├ Total Trades: 12
├ ✅ P/L: +$150.00
└ Uptime: 8.5h
⏰ 2025-02-06 16:45 WIB
```
---
### 8. News Alert
```
🚨 NEWS DANGER_NEWS
├ NFP (Non-Farm Payroll) - HIGH IMPACT
├ High volatility expected during release
└ Buffer: 60m
⏰ 20:25
```
| Emoji | Kondisi |
|-------|---------|
| 🚨 | DANGER_NEWS |
| ⚠️ | CAUTION / DANGER_SENTIMENT |
| ✅ | SAFE |
---
### 9. Critical Limit Alert
```
🚨 DAILY LOSS LIMIT REACHED 🚨
Daily Loss: $250.00
Limit: $250.00 (5%)
⛔ TRADING STOPPED FOR TODAY
Will resume tomorrow automatically.
```
---
### 10. Emergency Close
```
🚨 EMERGENCY CLOSE COMPLETE
Closed 3 positions due to flash crash detection
Total P/L: -$45.00
```
---
### 11. Alert (Berbagai Tipe)
| Alert Type | Emoji | Contoh |
|-----------|-------|--------|
| flash_crash | 🚨 | "Flash crash detected on XAUUSD" |
| high_volatility | ⚡ | "Volatility spike detected" |
| connection_error | 📡 | "MT5 connection lost" |
| model_retrain | 🔄 | "ML model retrained successfully" |
| market_close | 🔔 | "Market closing in 30 minutes" |
| low_balance | 💰 | "Account balance below threshold" |
---
## 3 Metode Pengiriman
| Metode | Endpoint | Kegunaan |
|--------|----------|---------|
| `send_message()` | `/sendMessage` | Teks biasa (semua notifikasi) |
| `send_photo()` | `/sendPhoto` | Chart/grafik (daily report) |
| `send_document()` | `/sendDocument` | File PDF (laporan detail) |
---
## Error Handling
```
Strategi: GRACEFUL DEGRADATION
1. Try-Except di setiap send method
-> Gagal kirim? Log warning, lanjut trading
2. HTTP status check
-> Status != 200? Log error, return False
3. Emergency close
-> Telegram gagal? TETAP tutup posisi
-> Trading > notifikasi dalam prioritas
4. Disabled mode
-> Token/ChatID kosong? Auto-disable, return True
-> Bot tetap berjalan tanpa notifikasi
```
```python
# Contoh: Emergency close TIDAK boleh gagal karena Telegram
try:
await telegram.send_message("Emergency close...")
except:
pass # Jangan biarkan Telegram failure menghentikan close
```
---
## Rate Limiting
| Notifikasi | Interval |
|-----------|----------|
| Trade Open/Close | Langsung (per event) |
| Market Update | 30 menit |
| Hourly Analysis | 1 jam |
| Daily Summary | 1x per hari |
| Startup/Shutdown | 1x per sesi |
| Min message interval | 1 detik (variable) |
---
## Kapan Notifikasi Dikirim di Main Loop
```
Main Loop (setiap 1 detik)
|
|-- Cek new day? ------> Daily Summary + Reset
|
|-- Cek hourly timer? -> Hourly Analysis (setiap 1 jam)
|
|-- Cek 30min timer? --> Market Update (setiap 30 menit)
|
|-- Trade executed? ---> Trade Open notification
|
|-- Position closed? --> Trade Close notification
|
|-- Limit hit? --------> Critical Limit Alert
|
|-- Flash crash? ------> Emergency Close Alert
|
|-- (startup) ---------> Startup message
|
|-- (shutdown) --------> Shutdown message
```
---
## Formatting HTML
Semua pesan menggunakan HTML parse mode:
```html
<b>Bold</b> -> Label penting
<code>Monospace</code> -> Angka, harga, nilai
<i>Italic</i> -> Info tambahan, alasan signal
```
Tree structure menggunakan box-drawing characters:
```
├ -> Item tengah
└ -> Item terakhir
```
+326
View File
@@ -0,0 +1,326 @@
# Auto Trainer — Sistem Retraining Otomatis
> **File:** `src/auto_trainer.py`
> **Class:** `AutoTrainer`
> **Database:** PostgreSQL (opsional, fallback ke file)
---
## Apa Itu Auto Trainer?
Auto Trainer adalah sistem yang **melatih ulang model AI secara otomatis** agar tetap up-to-date dengan kondisi pasar terbaru. Retraining dilakukan saat market tutup (05:00 WIB) untuk menghindari gangguan saat trading aktif.
**Analogi:** Auto Trainer seperti **pelatih yang membuat atlet berlatih setiap malam** — setelah pertandingan selesai, atlet (model AI) dilatih dengan data terbaru agar siap menghadapi tantangan esok hari.
---
## Jadwal Retraining
| Tipe | Waktu | Data | Boost Rounds | Kondisi |
|------|-------|------|-------------|---------|
| **Daily** | 05:00 WIB (market close) | 8.000 bar | 50 | SeninJumat |
| **Weekend** | 05:00 WIB Sabtu/Minggu | 15.000 bar | 80 | Deep training |
| **Emergency** | Kapan saja | 8.000 bar | 50 | AUC < 0.65 |
| **Initial** | Pertama kali | 8.000 bar | 50 | Belum pernah training |
```
Visualisasi Jadwal (WIB):
Sen Sel Rab Kam Jum Sab Min
| | | | | | |
05:00 05:00 05:00 05:00 05:00 05:00 05:00
Daily Daily Daily Daily Daily DEEP DEEP
8K 8K 8K 8K 8K 15K 15K
```
---
## Konfigurasi
```python
AutoTrainer(
models_dir="models", # Folder simpan model
data_dir="data", # Folder data training
daily_retrain_hour_wib=5, # Jam retrain: 05:00 WIB
weekend_retrain=True, # Deep training weekend
min_hours_between_retrain=20, # Min 20 jam antar retrain
backup_models=True, # Backup model lama
use_db=True, # Simpan history ke PostgreSQL
min_auc_threshold=0.65, # Alert jika AUC < 0.65
auto_retrain_on_low_auc=True, # Auto retrain saat AUC rendah
)
```
---
## Proses Retraining (Step-by-Step)
```
1. SHOULD RETRAIN CHECK
├ Sudah >= 20 jam sejak retrain terakhir?
├ Sekarang jam 05:00 WIB (±30 menit)?
├ Weekend? → Deep training (15K bar)
└ AUC < 0.65? → Emergency retrain
2. BACKUP MODEL LAMA
├ Copy xgboost_model.pkl → backups/YYYYMMDD_HHMMSS/
├ Copy hmm_regime.pkl → backups/YYYYMMDD_HHMMSS/
└ Bersihkan backup lama (simpan 5 terakhir)
3. FETCH DATA TERBARU
├ Ambil 8K bar (daily) atau 15K bar (weekend) dari MT5
├ Symbol: XAUUSD, Timeframe: M15
└ Validasi: minimal 1000 bar
4. FEATURE ENGINEERING
├ FeatureEngineer.calculate_all() → 40+ fitur
├ SMCAnalyzer.calculate_all() → struktur pasar
└ create_target(lookahead=1) → label UP/DOWN
5. TRAINING HMM
├ MarketRegimeDetector(n_regimes=3, lookback=500)
├ hmm.fit(df)
└ Save → models/hmm_regime.pkl
6. TRAINING XGBOOST
├ TradingModel(confidence_threshold=0.60)
├ xgb.fit(train_ratio=0.7, num_boost_round=50/80)
├ Early stopping: 5 rounds
└ Save → models/xgboost_model.pkl
7. VALIDASI
├ Cek Train AUC & Test AUC
├ Test AUC < 0.52? → ROLLBACK ke model lama
├ Test AUC < 0.65? → WARNING (alert)
└ Test AUC >= 0.65? → SUCCESS
8. RECORD HASIL
├ Simpan ke PostgreSQL (training_runs table)
├ Backup ke file (retrain_history.txt)
└ Log: durasi, AUC, accuracy, status
```
---
## Backup & Rollback
### Sistem Backup
```
models/
├── xgboost_model.pkl # Model aktif
├── hmm_regime.pkl # Model aktif
└── backups/
├── 20250206_050015/ # Backup terbaru
│ ├── xgboost_model.pkl
│ └── hmm_regime.pkl
├── 20250205_050012/ # Backup kemarin
│ ├── xgboost_model.pkl
│ └── hmm_regime.pkl
└── ... (max 5 backup)
```
### Kapan Rollback?
```
Model baru di-training
|
v
Cek Test AUC
|
├── AUC >= 0.65 ──> KEEP model baru ✅
|
├── AUC 0.52-0.65 ──> KEEP tapi WARNING ⚠️
| (akan trigger emergency retrain nanti)
|
└── AUC < 0.52 ──> ROLLBACK ke model lama 🔄
(copy dari backups/ ke models/)
```
### Method Rollback
```python
def rollback_models(reason="Manual rollback"):
"""
1. Ambil backup terbaru dari models/backups/
2. Copy xgboost_model.pkl kembali ke models/
3. Copy hmm_regime.pkl kembali ke models/
4. Record rollback di database
"""
```
---
## AUC Monitoring
### Apa Itu AUC?
AUC (Area Under Curve) mengukur **seberapa baik model membedakan sinyal BUY vs SELL**:
| AUC | Arti | Aksi |
|-----|------|------|
| 0.80+ | Sangat bagus | Model dalam kondisi prima |
| 0.65-0.80 | Bagus | Normal, lanjut trading |
| 0.52-0.65 | Kurang | Warning, pertimbangkan retrain |
| < 0.52 | Buruk | Rollback + retrain segera |
| 0.50 | Sama dengan tebak koin | Model tidak berguna |
### Auto-Retrain on Low AUC
```python
def should_retrain_due_to_low_auc():
"""
Cek AUC saat ini:
AUC < 0.65? → Perlu retrain
Tapi: sudah retrain < 4 jam lalu? → Tunggu
(mencegah retrain loop)
"""
```
---
## Database Storage
### PostgreSQL (Primary)
```
Table: training_runs
├── id # Auto-increment
├── training_type # "daily" / "weekend"
├── bars_used # 8000 / 15000
├── num_boost_rounds # 50 / 80
├── started_at # Timestamp mulai
├── completed_at # Timestamp selesai
├── duration_seconds # Durasi training
├── hmm_trained # Boolean
├── xgb_trained # Boolean
├── train_auc # AUC di data training
├── test_auc # AUC di data test
├── train_accuracy # Akurasi training
├── test_accuracy # Akurasi test
├── model_path # Path model disimpan
├── backup_path # Path backup model lama
├── success # Boolean
└── error_message # Pesan error (jika gagal)
```
### File Fallback
Jika PostgreSQL tidak tersedia:
```
data/retrain_history.txt
├── 2025-02-06T05:00:15+07:00
├── 2025-02-05T05:00:12+07:00
└── ... (append per retrain)
```
---
## Integrasi di Main Loop
```python
# main_live.py — dicek setiap 5 menit (300 loop)
if loop_count % 300 == 0:
should_train, reason = auto_trainer.should_retrain()
if should_train:
logger.info(f"Auto-retraining: {reason}")
# Retrain (blocking — tapi hanya di jam 05:00 saat market tutup)
results = auto_trainer.retrain(
connector=mt5,
symbol="XAUUSD",
timeframe="M15",
is_weekend=(now.weekday() >= 5),
)
if results["success"]:
# Reload model di memory
ml_model.load()
regime_detector.load()
logger.info("Models reloaded after retraining")
else:
logger.error(f"Retraining failed: {results['error']}")
```
---
## Parameter Training
### Daily Training (Senin-Jumat)
| Parameter | Nilai |
|-----------|-------|
| Data | 8.000 bar M15 (~83 hari) |
| Train/Test Split | 70% / 30% |
| XGBoost Rounds | 50 |
| Early Stopping | 5 rounds |
| HMM Regimes | 3 |
| HMM Lookback | 500 bar |
### Weekend Deep Training (Sabtu-Minggu)
| Parameter | Nilai |
|-----------|-------|
| Data | 15.000 bar M15 (~156 hari) |
| Train/Test Split | 70% / 30% |
| XGBoost Rounds | 80 |
| Early Stopping | 5 rounds |
| HMM Regimes | 3 |
| HMM Lookback | 500 bar |
---
## Safety Guards
```
1. MIN 20 JAM ANTAR RETRAIN
-> Mencegah retrain terlalu sering
-> Exception: emergency retrain (min 4 jam)
2. VALIDASI DATA MINIMUM
-> Butuh minimal 1000 bar
-> Kurang dari itu? Skip retrain
3. BACKUP SEBELUM RETRAIN
-> Model lama selalu di-backup
-> Bisa rollback kapan saja
4. AUTO-ROLLBACK
-> AUC < 0.52? Otomatis rollback
-> Model buruk tidak akan dipakai
5. CLEANUP BACKUP
-> Hanya simpan 5 backup terakhir
-> Mencegah disk penuh
6. GRACEFUL DEGRADATION
-> DB tidak tersedia? Pakai file
-> Retrain gagal? Model lama tetap aktif
```
---
## Contoh Output Log
```
[05:00] ==================================================
[05:00] AUTO-RETRAINING STARTED
[05:00] Type: daily, Bars: 8000, Boost Rounds: 50
[05:00] ==================================================
[05:00] Models backed up to models/backups/20250206_050015
[05:00] Fetching 8000 bars of XAUUSD M15 data...
[05:01] Received 8000 bars
[05:01] Date range: 2024-11-15 to 2025-02-06
[05:01] Applying feature engineering...
[05:01] Training HMM Regime Model...
[05:01] HMM model trained and saved
[05:02] Training XGBoost Model...
[05:02] XGBoost trained: Train AUC=0.7234, Test AUC=0.6891
[05:02] Training data saved to data/training_data.parquet
[05:02] ==================================================
[05:02] AUTO-RETRAINING COMPLETED SUCCESSFULLY
[05:02] Duration: 125s
[05:02] ==================================================
```
+367
View File
@@ -0,0 +1,367 @@
# Backtest — Engine Simulasi Live-Sync
> **File:** `backtests/backtest_live_sync.py`
> **Class:** `LiveSyncBacktest`
> **Prinsip:** 100% identik dengan `main_live.py`
---
## Apa Itu Backtest?
Backtest adalah sistem **simulasi trading pada data historis** yang logikanya 100% disinkronkan dengan trading live. Tujuannya menguji strategi sebelum dipakai uang sungguhan dan memvalidasi perubahan kode.
**Analogi:** Backtest seperti **simulator penerbangan** — pilot (bot) berlatih di kondisi realistis tanpa risiko jatuh. Setiap instrumen, prosedur, dan respons sama persis dengan pesawat asli.
---
## Prinsip Sinkronisasi
```
ATURAN UTAMA: Backtest HARUS identik dengan live.
Setiap perubahan di main_live.py → HARUS di-mirror di backtest_live_sync.py
Yang disinkronkan:
├── ML Model: XGBoost dengan fitur yang sama
├── SMC Analyzer: Swing length & OB lookback sama
├── Regime Detection: HMM MarketRegimeDetector
├── Session Filter: Golden Time 19:00-23:00 WIB
├── Signal Logic: Semua filter entry
├── Position Sizing: Berdasarkan ML confidence tier
├── Trade Cooldown: 300 detik (5 menit)
└── Exit Logic: TP, ML reversal, max loss, time-based
```
---
## Komponen yang Dimuat
```python
# Sama persis dengan main_live.py
self.smc = SMCAnalyzer(swing_length=config.smc.swing_length, ob_lookback=config.smc.ob_lookback)
self.features = FeatureEngineer()
self.regime_detector = MarketRegimeDetector(model_path="models/hmm_regime.pkl")
self.ml_model = TradingModel(model_path="models/xgboost_model.pkl")
self.dynamic_confidence = create_dynamic_confidence()
```
---
## Entry Logic (Sama dengan Live)
Semua filter entry di-replikasi:
```
Untuk setiap bar dalam data historis:
|
v
[1] COOLDOWN: Jarak >= 20 bar dari trade terakhir? (~5 menit M15)
|YES
[2] SESSION: Bukan Off Hours (04:00-06:00 WIB)?
|YES
[3] GOLDEN TIME: (opsional) Hanya 19:00-23:00 WIB?
|YES
[4] REGIME: Bukan CRISIS?
|YES
[5] SMC SIGNAL: Ada signal dari SMCAnalyzer?
|YES
[6] DYNAMIC CONFIDENCE: Market quality bukan AVOID?
|YES
[7] ML THRESHOLD: Confidence >= threshold (50%-65%)?
|YES
[8] ML AGREEMENT: ML tidak strongly disagree (>65% berlawanan)?
|YES
[9] SIGNAL CONFIRMATION: Signal muncul 2x berturut?
|YES
[10] PULLBACK FILTER: Momentum tidak berlawanan?
|YES
v
EXECUTE SIMULATED TRADE
```
---
## Session Mapping
```python
# Sama dengan session_filter.py
if 6 <= hour < 15: # Sydney-Tokyo → lot 0.5x
if 15 <= hour < 16: # Tokyo-London Overlap → lot 0.75x
if 16 <= hour < 19: # London Early → lot 0.8x
if 19 <= hour < 24: # London-NY (Golden) → lot 1.0x ← TERBAIK
if 0 <= hour < 4: # NY Session → lot 0.9x
if 4 <= hour < 6: # Off Hours → SKIP
```
---
## Exit Logic (5 Kondisi)
Untuk setiap bar setelah entry (max 100 bar):
### EXIT 1: Take Profit
```
IF harga hit TP level:
BUY: high >= take_profit
SELL: low <= take_profit
-> EXIT dengan profit penuh
```
### EXIT 2: Maximum Loss
```
IF current_profit < -$50 (max_loss_per_trade):
-> EXIT, potong kerugian
```
### EXIT 3: Time-Based (Synced dengan Live v3)
```
IF 16+ bar (4 jam) DAN profit < $5:
a) profit >= $0 → EXIT (breakeven setelah 4 jam)
b) profit > -$15 → EXIT (loss kecil, daripada stuck)
IF 24+ bar (6 jam):
-> FORCE EXIT (apapun profitnya)
```
**Visualisasi:**
```
Bar: 0 5 10 15 16 20 24
|-----|-----|-----|-----|-----|-----|
entry | |
| |
4h check: 6h FORCE EXIT
profit<$5?
Ya -> exit
```
### EXIT 4: ML Reversal
```
Setiap 5 bar, cek prediksi ML:
IF direction BUY DAN ML bilang SELL dengan confidence > 65%:
-> EXIT (ML mendeteksi reversal)
IF direction SELL DAN ML bilang BUY dengan confidence > 65%:
-> EXIT (ML mendeteksi reversal)
```
### EXIT 5: Trend Reversal (Momentum)
```
Setelah 10+ bar, cek momentum 5 bar terakhir:
IF BUY DAN momentum < -$5 DAN current_profit < -$10:
-> EXIT (tren berbalik + sudah rugi)
IF SELL DAN momentum > +$5 DAN current_profit < -$10:
-> EXIT (tren berbalik + sudah rugi)
```
---
## Lot Sizing
```python
# Berdasarkan ML confidence tier (sama dengan live)
if ml_confidence >= 0.65:
lot_size = 0.02 # High confidence → lot lebih besar
elif ml_confidence >= 0.55:
lot_size = 0.01 # Medium confidence → lot standar
else:
lot_size = 0.01 # Low confidence → lot minimum
# Apply session multiplier
lot_size = max(0.01, lot_size * session_lot_multiplier)
```
---
## Pullback Filter
```
Sama persis dengan main_live.py:
Untuk signal SELL, block jika:
- Harga naik > $2 dalam 3 candle terakhir
- MACD histogram rising + harga naik
- Harga di atas EMA9 dan masih naik
Untuk signal BUY, block jika:
- Harga turun > $2 dalam 3 candle terakhir
- MACD histogram falling + harga turun
- Harga di bawah EMA9 dan masih turun
Exception (tetap boleh entry):
- Konsolidasi (pergerakan < $1.50)
- Momentum searah signal
```
---
## Metrik Performa
| Metrik | Rumus | Keterangan |
|--------|-------|------------|
| **Win Rate** | Wins / Total × 100% | Persentase trade profit |
| **Profit Factor** | Gross Profit / Gross Loss | > 1.0 = profitable |
| **Expectancy** | (WR × Avg Win) - (LR × Avg Loss) | Rata-rata per trade |
| **Max Drawdown** | (Peak - Trough) / Peak × 100% | Penurunan terbesar |
| **Sharpe Ratio** | (Avg Return / Std Dev) × √252 | Risk-adjusted return |
| **Net P/L** | Total Profit - Total Loss | Keuntungan bersih |
---
## Threshold Tuning
Mode `--tune` menguji beberapa ML threshold secara otomatis:
```python
ml_thresholds = [0.50, 0.52, 0.55, 0.58, 0.60, 0.65]
# Untuk setiap threshold:
# 1. Jalankan full backtest
# 2. Catat: trades, win rate, net P/L, profit factor, drawdown
# 3. Ranking berdasarkan net P/L
# Output:
# ML Thresh Trades Win Rate Net P/L PF DD
# --------------------------------------------------------
# 55% 145 64.8% $1,250.00 1.85 3.2%
# 52% 178 62.1% $1,100.00 1.72 4.1%
# 60% 112 67.0% $ 980.00 1.95 2.8%
# ...
```
---
## Cara Penggunaan
```bash
# Backtest standar dengan threshold default (55%)
python backtests/backtest_live_sync.py
# Backtest dengan threshold custom
python backtests/backtest_live_sync.py --threshold 0.60
# Hanya golden time
python backtests/backtest_live_sync.py --golden-only
# Threshold tuning (cari optimal)
python backtests/backtest_live_sync.py --tune
# Simpan hasil ke CSV
python backtests/backtest_live_sync.py --save
```
---
## Output Backtest
### Laporan Performa
```
==================================================================
BACKTEST RESULTS
==================================================================
Configuration:
ML Threshold: 55%
Signal Confirmation: 2 consecutive
Pullback Filter: Enabled
Golden Time Only: False
Performance:
Total Trades: 145
Wins: 94
Losses: 51
Win Rate: 64.8%
Profit/Loss:
Total Profit: $2,850.00
Total Loss: $1,600.00
Net P/L: $1,250.00
Profit Factor: 1.78
Risk Metrics:
Max Drawdown: 3.2% ($160.00)
Avg Win: $30.32
Avg Loss: $31.37
Expectancy: $8.62
Sharpe Ratio: 1.45
```
### Breakdown Exit Reason
```
Exit Reasons:
take_profit: 72 (49.7%)
timeout: 35 (24.1%)
ml_reversal: 18 (12.4%)
max_loss: 12 (8.3%)
trend_reversal: 8 (5.5%)
```
### Breakdown Session
```
Session Performance:
London-NY Overlap (Golden): 65 trades, 69.2% WR, $820.00
NY Session: 32 trades, 62.5% WR, $280.00
London Early: 28 trades, 60.7% WR, $120.00
Sydney-Tokyo: 20 trades, 55.0% WR, $30.00
```
---
## File Output
```
backtests/results/
├── backtest_20250206_143000.csv # Detail semua trade
│ ├── ticket, entry_time, exit_time
│ ├── direction, entry_price, exit_price
│ ├── stop_loss, take_profit, lot_size
│ ├── profit_usd, profit_pips, result
│ ├── exit_reason, ml_confidence, smc_confidence
│ └── regime, session, signal_reason
└── backtest_20250206_143000_summary.csv # Ringkasan metrik
├── total_trades, wins, losses, win_rate
├── total_profit, total_loss, net_pnl
├── profit_factor, avg_win, avg_loss
└── max_drawdown, expectancy, sharpe_ratio
```
---
## Data Flow
```
MT5 Connected
|
v
Fetch 50.000 bar M15 XAUUSD
|
v
FeatureEngineer.calculate_all() → 40+ fitur
SMCAnalyzer.calculate_all() → Struktur pasar
RegimeDetector.predict() → Regime label
|
v
Filter: Jan 2025 - Now
|
v
Loop setiap bar:
├── Entry check (10 filter)
├── Simulate exit (5 kondisi)
├── Record trade result
└── Update statistics
|
v
Print laporan + Save CSV
```
+295
View File
@@ -0,0 +1,295 @@
# Dynamic Confidence — Penyesuaian Threshold Otomatis
> **File:** `src/dynamic_confidence.py`
> **Class:** `DynamicConfidenceManager`
> **Digunakan di:** `main_live.py`, `backtest_live_sync.py`
---
## Apa Itu Dynamic Confidence?
Dynamic Confidence adalah sistem yang **menyesuaikan confidence threshold ML secara otomatis** berdasarkan kondisi pasar saat ini. Saat kondisi ideal, threshold diturunkan agar lebih banyak peluang. Saat kondisi buruk, threshold dinaikkan untuk lebih selektif.
**Analogi:** Dynamic Confidence seperti **termometer yang mengatur AC otomatis** — saat cuaca panas (pasar bagus), AC diset dingin (threshold rendah, lebih banyak trade). Saat cuaca dingin (pasar buruk), AC dimatikan (threshold tinggi, kurangi trade).
---
## Prinsip Dasar
```
Market BAGUS (trending, session bagus) → Threshold RENDAH (60%) → Lebih banyak trade
Market BIASA (normal) → Threshold SEDANG (70%) → Trade normal
Market JELEK (choppy, low liquidity) → Threshold TINGGI (80%) → Sangat selektif
Market BERBAHAYA (crisis, weekend) → Threshold MAXIMUM (85%) → Hindari trading
```
---
## Konfigurasi
```python
DynamicConfidenceManager(
base_threshold=0.70, # Default threshold 70%
min_threshold=0.60, # Minimum (kondisi terbaik): 60%
max_threshold=0.85, # Maximum (kondisi terburuk): 85%
)
```
---
## 6 Faktor Penilaian
Score dimulai dari **50** (tengah), lalu disesuaikan oleh 6 faktor:
### Faktor 1: Session (±20 poin)
| Session | Poin | Alasan |
|---------|------|--------|
| London-NY Overlap / Golden | **+20** | Likuiditas tertinggi, spread rendah |
| London | **+15** | Volume tinggi |
| New York | **+10** | Volume tinggi |
| Asia/Tokyo | **+0** | Volatilitas rendah |
| Market Closed/Weekend | **-30** | Tidak ada likuiditas |
| Lainnya | **+5** | Default |
### Faktor 2: Regime (±15 poin)
| Regime | Poin | Alasan |
|--------|------|--------|
| Medium Volatility | **+15** | Kondisi ideal untuk trading |
| Low Volatility | **+5** | Hati-hati ranging |
| High Volatility | **-5** | Perlu lot kecil |
| Crisis | **-25** | Hindari trading |
### Faktor 3: Volatility (±10 poin)
| Volatility | Poin | Alasan |
|-----------|------|--------|
| Medium | **+10** | Pergerakan cukup, bisa diprediksi |
| Low | **+0** | Pergerakan terlalu kecil |
| High | **-5** | Sulit diprediksi |
| Extreme | **-10** | Sangat berbahaya |
### Faktor 4: Trend Clarity (±10 poin)
| Trend | Poin | Alasan |
|-------|------|--------|
| Uptrend / Downtrend | **+10** | Arah jelas, sinyal lebih akurat |
| Neutral / Ranging | **-5** | Sinyal sering whipsaw |
### Faktor 5: SMC Confluence (±10 poin)
| Kondisi | Poin | Alasan |
|---------|------|--------|
| Ada sinyal SMC (OB/FVG/BOS) | **+10** | Konfirmasi tambahan |
| Tidak ada sinyal | **+0** | Tanpa konfirmasi |
### Faktor 6: ML Alignment (±5 poin)
| ML Confidence | Poin | Alasan |
|--------------|------|--------|
| >= 70% | **+5** | ML sangat yakin |
| >= 60% | **+2** | ML cukup yakin |
| < 60% | **+0** | ML kurang yakin |
---
## Pemetaan Score ke Quality
Score dihitung (0100), lalu dipetakan ke **5 level kualitas**:
```
Score: 0 10 20 30 35 50 65 80 100
|-----|-----|-----|-----|-----|-----|-----|-----|
| AVOID |POOR | MODERATE |GOOD | EXCELLENT
| (< 35) | | (50-64) | | (80+)
| thresh: 85% |80% | 70% |65% | 60%
```
| Score | Quality | Threshold | Aksi |
|-------|---------|-----------|------|
| **80+** | EXCELLENT | 60% | Trade dengan percaya diri |
| **65-79** | GOOD | 65% | Trade normal |
| **50-64** | MODERATE | 70% | Trade hati-hati |
| **35-49** | POOR | 80% | Sangat selektif |
| **< 35** | AVOID | 85% | Jangan trade |
---
## Contoh Perhitungan
### Contoh 1: Kondisi Ideal (Score: 95)
```
Base score: 50
[+20] Session: London-NY Overlap → 70
[+15] Regime: Medium Volatility → 85
[+10] Volatility: Medium → 95
[+10] Trend: UPTREND → 105 → cap 100
[+10] SMC: Ada FVG + BOS → 100
[+5] ML: 72% confidence → 100
Score: 100 → EXCELLENT → Threshold: 60%
```
**Artinya:** ML cukup confidence 60% saja untuk entry. Lebih banyak trade opportunity.
### Contoh 2: Kondisi Jelek (Score: 40)
```
Base score: 50
[+0] Session: Asia → 50
[+5] Regime: Low Volatility → 55
[+0] Volatility: Low → 55
[-5] Trend: RANGING → 50
[+0] SMC: Tidak ada signal → 50
[+0] ML: 58% confidence → 50
Score: 50 → MODERATE → Threshold: 70%
```
**Artinya:** ML harus confidence 70% untuk entry. Lebih selektif.
### Contoh 3: Kondisi Berbahaya (Score: 15)
```
Base score: 50
[-30] Session: Weekend → 20
[-25] Regime: Crisis → -5 → cap 0
[-10] Volatility: Extreme → 0
[-5] Trend: Ranging → 0
[+0] SMC: Tidak ada → 0
[+0] ML: 55% → 0
Score: 0 → AVOID → Threshold: 85% (praktis tidak trade)
```
---
## Integrasi di Entry Flow
```python
# main_live.py — Step 6 dari 11 filter entry
# 1. Analisis kondisi market
market_analysis = dynamic_confidence.analyze_market(
session=session_name, # "London-NY Overlap"
regime=regime_name, # "medium_volatility"
volatility=volatility_level, # "medium"
trend_direction=trend, # "UPTREND"
has_smc_signal=True, # Ada SMC signal
ml_signal=ml_pred.signal, # "BUY"
ml_confidence=ml_pred.confidence, # 0.68
)
# 2. Cek quality
if market_analysis.quality == MarketQuality.AVOID:
return # SKIP — market tidak layak
# 3. Cek apakah ML confidence memenuhi threshold dinamis
can_entry, reason = dynamic_confidence.get_entry_decision(
ml_confidence=0.68,
analysis=market_analysis,
)
# can_entry = True (0.68 >= 0.60 threshold untuk EXCELLENT)
# reason = "Entry OK: ML 68% >= threshold 60% (score=95)"
```
---
## Integrasi di Backtest
```python
# backtest_live_sync.py — identik dengan live
market_analysis = self.dynamic_confidence.analyze_market(
session=session_name,
regime=regime,
volatility="medium",
trend_direction=regime,
has_smc_signal=True,
ml_signal=ml_pred.signal,
ml_confidence=ml_pred.confidence,
)
if market_analysis.quality == MarketQuality.AVOID:
continue # Skip bar ini
```
---
## Method `get_entry_decision()`
```python
def get_entry_decision(ml_confidence, analysis) -> (bool, str):
"""
Keputusan final entry berdasarkan analisis.
1. Quality == AVOID? → False (jangan trade)
2. ML confidence >= threshold? → True (entry OK)
3. ML confidence < threshold? → False (tunggu)
"""
# Contoh output:
# True, "Entry OK: ML 68% >= threshold 60% (score=95)"
# False, "Wait: ML 55% < threshold 70% (need +15%)"
# False, "Market quality: AVOID (score=20)"
```
---
## Logging
```python
def get_threshold_summary(analysis) -> str:
"""
Output: "Market: EXCELLENT (score=95) → Threshold: 60%"
"""
```
Contoh log di main_live.py:
```
[14:30] Market: EXCELLENT (score=95) → Threshold: 60%
[14:35] Entry OK: ML 68% >= threshold 60% (score=95)
[15:00] Market: MODERATE (score=55) → Threshold: 70%
[15:05] Wait: ML 62% < threshold 70% (need +8%)
[04:00] Market: AVOID (score=15) → Threshold: 85%
```
---
## Ringkasan Visual
```
Kondisi Market Saat Ini
|
v
6 Faktor Dianalisis:
├── Session ±20 poin
├── Regime ±15 poin
├── Volatility ±10 poin
├── Trend ±10 poin
├── SMC ±10 poin
└── ML ±5 poin
|
v
Score (0-100)
|
v
Quality Level:
├── EXCELLENT (80+) → Threshold 60%
├── GOOD (65-79) → Threshold 65%
├── MODERATE (50-64)→ Threshold 70%
├── POOR (35-49) → Threshold 80%
└── AVOID (<35) → Threshold 85% / SKIP
|
v
ML Confidence >= Threshold?
├── YES → ENTRY diizinkan
└── NO → TUNGGU
```
+124
View File
@@ -0,0 +1,124 @@
# Arsitektur AI — Smart Trading Bot
> Dokumentasi lengkap semua komponen AI dan sistem pendukung.
---
## Daftar Komponen
### Inti AI & Analisis
| # | Komponen | File Source | Fungsi |
|---|----------|------------|--------|
| 1 | [HMM Regime Detector](01-HMM-Regime-Detector.md) | `src/regime_detector.py` | Deteksi kondisi pasar (radar cuaca) |
| 2 | [XGBoost Signal Predictor](02-XGBoost-Signal-Predictor.md) | `src/ml_model.py` | Prediksi arah harga (navigator AI) |
| 3 | [SMC Analyzer](03-SMC-Analyzer.md) | `src/smc_polars.py` | Analisis struktur pasar institusi (peta jalan) |
| 4 | [Feature Engineering](04-Feature-Engineering.md) | `src/feature_eng.py` | Pengolahan data mentah ke fitur ML (alat ukur) |
### Proteksi & Manajemen Risiko
| # | Komponen | File Source | Fungsi |
|---|----------|------------|--------|
| 5 | [Risk Management](05-Risk-Management.md) | `src/smart_risk_manager.py` | Perlindungan modal (sabuk pengaman) |
| 6 | [Session Filter](06-Session-Filter.md) | `src/session_filter.py` | Pengaturan waktu trading (jadwal kerja) |
| 7 | [Stop Loss (S/L)](07-Stop-Loss.md) | Multi-file | Proteksi 4 lapis dari kerugian |
| 8 | [Take Profit (T/P)](08-Take-Profit.md) | Multi-file | Pengambilan profit cerdas 6 layer |
### Proses Trading
| # | Komponen | File Source | Fungsi |
|---|----------|------------|--------|
| 9 | [Entry Trade](09-Entry-Trade.md) | `main_live.py` | Proses masuk posisi (11 filter) |
| 10 | [Exit Trade](10-Exit-Trade.md) | `main_live.py` | Proses keluar posisi (10 kondisi) |
### Pendukung
| # | Komponen | File Source | Fungsi |
|---|----------|------------|--------|
| 11 | [News Agent](11-News-Agent.md) | `src/news_agent.py` | Monitoring berita ekonomi |
| 12 | [Telegram Notifications](12-Telegram-Notifications.md) | `src/telegram_notifier.py` | Notifikasi real-time ke Telegram |
### Training & Validasi
| # | Komponen | File Source | Fungsi |
|---|----------|------------|--------|
| 13 | [Auto Trainer](13-Auto-Trainer.md) | `src/auto_trainer.py` | Retraining model otomatis (pelatih malam) |
| 14 | [Backtest](14-Backtest.md) | `backtests/backtest_live_sync.py` | Simulasi trading 100% sync dengan live |
| 15 | [Dynamic Confidence](15-Dynamic-Confidence.md) | `src/dynamic_confidence.py` | Penyesuaian threshold otomatis (termometer) |
---
## Pipeline Lengkap
```
Raw OHLCV dari MT5
|
v
[Feature Engineering] -> 40+ fitur numerik (RSI, ATR, MACD, BB, EMA, ...)
|
v
[SMC Analyzer] -> Swing, FVG, OB, BOS, CHoCH, Liquidity
| + Signal (entry, SL ATR-based, TP ATR-capped)
|
+---+---+
| |
v v
[HMM] [XGBoost]
Regime Signal
| |
+---+---+
|
v
[Signal Combination] -> SMC + ML harus setuju
|
v
[News Agent] -> Monitor berita (tidak blocking)
|
v
[Session Filter] -> Cek waktu boleh trading?
|
v
[ENTRY TRADE] -> 11 filter harus PASS:
| Session, Risk Mode, SMC Signal, ML Confirm,
| ML Agree, Quality, Confirmation 2x, Pullback,
| Cooldown, Position Limit, Lot Size
|
v
[Risk Management] -> Hitung lot aman, apply multiplier
|
v
[Execute Order] -> Kirim ke MT5 dengan broker SL & TP
|
v
[Telegram] -> Notifikasi trade open
|
v
[EXIT MONITORING] -> Setiap 1 detik, 10 kondisi exit:
| Smart TP, Early Exit, Golden Hold, ML Reversal,
| Max Loss, Stall, Daily Limit, Weekend, Time-based, Hold
|
v
[Close Position] -> Record result, update risk, notify
```
---
## Ringkasan Peran Setiap Komponen
| Komponen | Pertanyaan yang Dijawab |
|----------|------------------------|
| Feature Engineering | "Data mentah ini berarti apa?" |
| SMC Analyzer | "Dimana institusi besar trading? Entry/SL/TP dimana?" |
| HMM | "Kondisi pasar bagaimana sekarang?" |
| XGBoost | "Harga akan naik atau turun?" |
| Session Filter | "Sekarang waktu yang tepat untuk trading?" |
| News Agent | "Ada berita high-impact yang perlu diperhatikan?" |
| Risk Management | "Berapa besar boleh trading? Sudah aman?" |
| Stop Loss | "Bagaimana melindungi dari kerugian?" |
| Take Profit | "Kapan mengambil profit?" |
| Entry Trade | "Apakah semua syarat terpenuhi untuk masuk?" |
| Exit Trade | "Apakah sudah waktunya keluar?" |
| Telegram | "Apa yang sedang terjadi?" |
| Auto Trainer | "Apakah model AI masih akurat? Perlu dilatih ulang?" |
| Backtest | "Apakah strategi ini profitable di data historis?" |
| Dynamic Confidence | "Seberapa selektif bot harus trading saat ini?" |