Files
XauBot/docs/arsitektur-ai/05-Risk-Management.md
T
GifariKemal 757b499033 docs: sync architecture docs with v5 major issues fix
5 major issues reflected in documentation:

1. Confidence calibration (03-SMC, 00-ARSITEKTUR):
   - Base 55% + 10% each → base 40% + weighted scoring
   - Structure +15%, BOS/CHoCH +12%, FVG +8%, OB +10%, Trend +10%

2. ATR-based pullback filter (09-Entry, 00-ARSITEKTUR):
   - Hardcoded $2/$1.5 → bounce 15% ATR, consolidation 10% ATR

3. Smarter time-based exit (10-Exit, 05-Risk, 00-ARSITEKTUR):
   - 4h: check profit growth, not just profit<$5
   - 6h: extend to 8h if profit>$10 and growing + ML agrees

4. Slippage validation (09-Entry, 23-Main, 00-ARSITEKTUR):
   - Check actual vs expected price, log if >0.15%

5. Partial fill handling (09-Entry, 23-Main, 00-ARSITEKTUR):
   - Check filled volume, use actual values for tracking

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 10:06:43 +07:00

460 lines
14 KiB
Markdown

# 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. EARLY CUT (v4 — Smart Hold DIHAPUS)
Jika loss >= 30% max ($15) DAN momentum < -30:
-> TUTUP CEPAT (early cut, jangan tunggu recovery)
v4: "Smart Hold" dihapus — tidak ada lagi hold losers
menunggu golden time atau sesi London.
MAX LOSS CHECK (50% threshold):
Jika loss >= $25 (50% dari $50 max):
-> 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. SMART TIME-BASED EXIT (v5: Don't Cut Winners)
Jika posisi terbuka >= 4 jam:
- profit < $5 DAN tidak growing -> TUTUP
- profit >= $5 DAN growing + ML agrees -> HOLD (extend)
Jika posisi terbuka >= 6 jam:
- profit < $10 ATAU tidak growing -> TUTUP
- profit >= $10 DAN growing -> extend ke 8 jam
Jika posisi terbuka >= 8 jam:
-> TUTUP (take profit atau max time)
```
### Smart Time-Based Exit Detail (v5 Update)
```
Jam 0 Jam 4 Jam 6 Jam 8
|------------|------------------|------------------|-----> waktu
| | |
| stuck? | profitable? | FINAL EXIT
| (no growth) | (growing?) |
| -> TUTUP | -> extend! |
| | not growing? |
| growing? | -> TUTUP |
| -> HOLD | |
v5 Perubahan dari v3:
- 4h: Cek profit GROWTH (momentum), bukan hanya profit < $5
- 6h: Bukan force close lagi — extend ke 8h jika profit > $10 + growing
- ML agreement diperhitungkan sebelum timeout
- Prinsip: jangan potong pemenang yang masih berjalan
```
### 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 (candle-based + position check setiap ~10 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
Smart time-based exit (v5):
16 bars (4 jam M15) + no growth -> exit (stuck)
16 bars + growing + ML agrees -> hold (extend)
24 bars (6 jam M15) + profit<$10 -> exit
24 bars + profit>$10 + growing -> extend ke 32 bars (8 jam)
32 bars (8 jam M15) -> final exit
Perhitungan bar:
bars_since_entry = current_bar_index - entry_bar_index
16 bars * 15 menit = 4 jam
24 bars * 15 menit = 6 jam
32 bars * 15 menit = 8 jam (v5: max extended time)
```
**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. **Smart Time-Bounded** — Tidak ada posisi "zombie", max 6-8 jam, tapi jangan potong pemenang (v5 update)
7. **Faster Reversal** — Exit lebih cepat di 65% ML confidence (v3 update)