# 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)
