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

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 05:46:54 +07:00

9.1 KiB
Raw Blame History

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

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

flowchart TD
    START["Untuk setiap bar dalam data historis"] --> F1{"1. COOLDOWN\n>= 20 bar dari trade terakhir?"}
    F1 -->|YES| F2{"2. SESSION\nBukan Off Hours 04:00-06:00?"}
    F1 -->|NO| SKIP["SKIP"]
    F2 -->|YES| F3{"3. GOLDEN TIME\nHanya 19:00-23:00? (opsional)"}
    F2 -->|NO| SKIP
    F3 -->|YES| F4{"4. REGIME\nBukan CRISIS?"}
    F3 -->|NO| SKIP
    F4 -->|YES| F5{"5. SMC SIGNAL\nAda signal?"}
    F4 -->|NO| SKIP
    F5 -->|YES| F6{"6. DYNAMIC CONFIDENCE\nBukan AVOID?"}
    F5 -->|NO| SKIP
    F6 -->|YES| F7{"7. ML THRESHOLD\nConfidence >= 50-65%?"}
    F6 -->|NO| SKIP
    F7 -->|YES| F8{"8. ML AGREEMENT\nTidak strongly disagree?"}
    F7 -->|NO| SKIP
    F8 -->|YES| F9{"9. SIGNAL CONFIRMATION\n2x berturut?"}
    F8 -->|NO| SKIP
    F9 -->|YES| F10{"10. PULLBACK FILTER\nMomentum tidak berlawanan?"}
    F9 -->|NO| SKIP
    F10 -->|YES| EXEC["EXECUTE SIMULATED TRADE"]
    F10 -->|NO| SKIP

Session Mapping

# 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

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

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

# 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

flowchart TD
    A["MT5 Connected"] --> B["Fetch 50.000 bar M15 XAUUSD"]
    B --> C["FeatureEngineer.calculate_all() → 40+ fitur\nSMCAnalyzer.calculate_all() → Struktur pasar\nRegimeDetector.predict() → Regime label"]
    C --> D["Filter: Jan 2025 - Now"]
    D --> E["Loop setiap bar"]
    E --> E1["Entry check (14 filter)"]
    E --> E2["Simulate exit (5 kondisi)"]
    E --> E3["Record trade result"]
    E --> E4["Update statistics"]
    E1 --> F["Print laporan + Save CSV"]
    E2 --> F
    E3 --> F
    E4 --> F