e8355b3f62
- 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>
403 lines
11 KiB
Markdown
403 lines
11 KiB
Markdown
# *Database Module* — *PostgreSQL* Integration
|
||
|
||
> **File:** `src/db/connection.py`, `src/db/repository.py`
|
||
> **Database:** *PostgreSQL*
|
||
> **Library:** psycopg2 (*connection pooling*)
|
||
|
||
---
|
||
|
||
## Apa Itu *Database Module*?
|
||
|
||
*Database Module* menyediakan **penyimpanan persisten** untuk semua data trading — trade history, training log, sinyal, snapshot pasar, dan status bot. Menggunakan *PostgreSQL* dengan *connection pooling* untuk performa tinggi.
|
||
|
||
**Analogi:** *Database Module* seperti **arsip perpustakaan** — menyimpan semua catatan trading secara terorganisir, bisa dicari kapan saja, dan tidak hilang meski bot di-restart.
|
||
|
||
---
|
||
|
||
## Arsitektur
|
||
|
||
```mermaid
|
||
graph TD
|
||
TL[TradeLogger] -->|write| TR[TradeRepository]
|
||
TL -->|write| SigR[SignalRepository]
|
||
TL -->|write| MSR[MarketSnapshotRepository]
|
||
AT[AutoTrainer] -->|write| TrR[TrainingRepository]
|
||
ML[main_live.py] -->|write| BSR[BotStatusRepository]
|
||
ML -->|write| DSR[DailySummaryRepository]
|
||
DASH[Dashboard] -.->|read| TR
|
||
DASH -.->|read| SigR
|
||
DASH -.->|read| MSR
|
||
DASH -.->|read| TrR
|
||
DASH -.->|read| BSR
|
||
DASH -.->|read| DSR
|
||
|
||
TR --> DC[DatabaseConnection<br/><i>Singleton</i>]
|
||
SigR --> DC
|
||
MSR --> DC
|
||
TrR --> DC
|
||
BSR --> DC
|
||
DSR --> DC
|
||
|
||
DC --> POOL[ThreadedConnectionPool<br/>1 – 10 koneksi]
|
||
POOL --> PG[(PostgreSQL Server)]
|
||
|
||
style DC fill:#2d6a4f,stroke:#1b4332,color:#fff
|
||
style PG fill:#1b4332,stroke:#081c15,color:#fff
|
||
style POOL fill:#40916c,stroke:#2d6a4f,color:#fff
|
||
```
|
||
|
||
---
|
||
|
||
## Connection (*Singleton* + Pooling)
|
||
|
||
```python
|
||
class DatabaseConnection:
|
||
"""
|
||
Thread-safe singleton dengan connection pooling.
|
||
|
||
- Hanya 1 instance (singleton pattern)
|
||
- Pool: 1-10 koneksi (ThreadedConnectionPool)
|
||
- Auto-reconnect jika putus
|
||
- Context manager support
|
||
"""
|
||
```
|
||
|
||
`DatabaseConnection` menerapkan pola *singleton* yang *thread-safe* — hanya satu instance yang pernah dibuat selama proses berjalan. Akses ke database dilakukan melalui *context manager* (`with db.get_cursor() as cur`) sehingga koneksi selalu dikembalikan ke pool setelah selesai.
|
||
|
||
### Konfigurasi
|
||
|
||
```
|
||
DB_HOST=localhost
|
||
DB_PORT=5432
|
||
DB_NAME=trading_db
|
||
DB_USER=trading_bot
|
||
DB_PASSWORD=trading_bot_2026
|
||
```
|
||
|
||
### Penggunaan
|
||
|
||
```python
|
||
from src.db import get_db, init_db
|
||
|
||
# Initialize
|
||
if init_db():
|
||
db = get_db()
|
||
|
||
# Query dengan context manager
|
||
with db.get_cursor() as cur:
|
||
cur.execute("SELECT * FROM trades WHERE profit_usd > 0")
|
||
rows = cur.fetchall()
|
||
|
||
# Simple execute
|
||
result = db.execute("SELECT count(*) FROM trades", fetch=True)
|
||
```
|
||
|
||
---
|
||
|
||
## 6 *Repository*
|
||
|
||
Setiap *repository* bertanggung jawab atas satu tabel dan menyediakan method khusus untuk operasi CRUD.
|
||
|
||
### 1. TradeRepository
|
||
|
||
| Method | Fungsi |
|
||
|--------|--------|
|
||
| `insert_trade()` | Insert trade baru (saat open) |
|
||
| `update_trade_close()` | Update exit data (saat close) |
|
||
| `get_trade_by_ticket()` | Cari trade per ticket |
|
||
| `get_open_trades()` | Trade yang belum ditutup |
|
||
| `get_recent_trades(100)` | 100 trade terakhir |
|
||
| `get_trades_for_training(30)` | Trade 30 hari untuk ML |
|
||
| `get_daily_stats(date)` | Statistik per hari |
|
||
| `get_session_stats("London", 30)` | Statistik per sesi |
|
||
| `get_smc_pattern_stats(30)` | Performa per pola SMC |
|
||
|
||
### 2. TrainingRepository
|
||
|
||
| Method | Fungsi |
|
||
|--------|--------|
|
||
| `insert_training_run()` | Catat mulai training |
|
||
| `update_training_complete()` | Update hasil training |
|
||
| `mark_rollback()` | Tandai model di-rollback |
|
||
| `get_latest_successful()` | Training sukses terakhir |
|
||
| `get_training_history(20)` | 20 training terakhir |
|
||
|
||
### 3. SignalRepository
|
||
|
||
| Method | Fungsi |
|
||
|--------|--------|
|
||
| `insert_signal()` | Catat sinyal yang dihasilkan |
|
||
| `mark_executed()` | Tandai sinyal yang dieksekusi |
|
||
| `get_recent_signals(100)` | 100 sinyal terakhir |
|
||
| `get_signal_stats(24)` | Statistik 24 jam |
|
||
|
||
### 4. MarketSnapshotRepository
|
||
|
||
| Method | Fungsi |
|
||
|--------|--------|
|
||
| `insert_snapshot()` | Simpan snapshot pasar |
|
||
| `get_recent_snapshots(60)` | Snapshot 60 menit terakhir |
|
||
|
||
### 5. BotStatusRepository
|
||
|
||
| Method | Fungsi |
|
||
|--------|--------|
|
||
| `insert_status()` | Catat status bot |
|
||
| `get_latest_status()` | Status terbaru |
|
||
|
||
### 6. DailySummaryRepository
|
||
|
||
| Method | Fungsi |
|
||
|--------|--------|
|
||
| `upsert_summary()` | Insert/update ringkasan harian |
|
||
| `get_summary(date)` | Ringkasan per tanggal |
|
||
| `get_recent_summaries(30)` | 30 hari terakhir |
|
||
|
||
---
|
||
|
||
## Tabel Database
|
||
|
||
### Entity-Relationship Diagram
|
||
|
||
```mermaid
|
||
erDiagram
|
||
trades {
|
||
bigint ticket PK
|
||
varchar symbol
|
||
varchar direction
|
||
float entry_price
|
||
float exit_price
|
||
float stop_loss
|
||
float take_profit
|
||
float lot_size
|
||
float profit_usd
|
||
float profit_pips
|
||
timestamp opened_at
|
||
timestamp closed_at
|
||
int duration_seconds
|
||
varchar entry_regime
|
||
float entry_volatility
|
||
varchar entry_session
|
||
varchar smc_signal
|
||
float smc_confidence
|
||
text smc_reason
|
||
bool smc_fvg_detected
|
||
bool smc_ob_detected
|
||
bool smc_bos_detected
|
||
bool smc_choch_detected
|
||
varchar ml_signal
|
||
float ml_confidence
|
||
varchar market_quality
|
||
float market_score
|
||
float dynamic_threshold
|
||
varchar exit_reason
|
||
varchar exit_regime
|
||
varchar exit_ml_signal
|
||
float balance_before
|
||
float balance_after
|
||
float equity_at_entry
|
||
json features_entry
|
||
json features_exit
|
||
varchar bot_version
|
||
varchar trade_mode
|
||
}
|
||
|
||
training_runs {
|
||
serial id PK
|
||
varchar training_type
|
||
int bars_used
|
||
int num_boost_rounds
|
||
bool hmm_trained
|
||
int hmm_n_regimes
|
||
bool xgb_trained
|
||
float train_auc
|
||
float test_auc
|
||
float train_accuracy
|
||
float test_accuracy
|
||
varchar model_path
|
||
varchar backup_path
|
||
bool success
|
||
text error_message
|
||
timestamp started_at
|
||
timestamp completed_at
|
||
int duration_seconds
|
||
bool rolled_back
|
||
text rollback_reason
|
||
timestamp rollback_at
|
||
}
|
||
|
||
signals {
|
||
serial id PK
|
||
timestamp signal_time
|
||
varchar symbol
|
||
float price
|
||
varchar signal_type
|
||
varchar signal_source
|
||
float combined_confidence
|
||
varchar regime
|
||
varchar session
|
||
float volatility
|
||
float market_score
|
||
bool executed
|
||
text execution_reason
|
||
bigint trade_ticket FK
|
||
}
|
||
|
||
market_snapshots {
|
||
serial id PK
|
||
timestamp snapshot_time
|
||
varchar symbol
|
||
float price
|
||
float open
|
||
float high
|
||
float low
|
||
float close
|
||
varchar regime
|
||
float volatility
|
||
varchar session
|
||
float atr
|
||
float spread
|
||
varchar ml_signal
|
||
float ml_confidence
|
||
varchar smc_signal
|
||
float smc_confidence
|
||
int open_positions
|
||
float floating_pnl
|
||
json features
|
||
}
|
||
|
||
bot_status {
|
||
serial id PK
|
||
timestamp status_time
|
||
bool is_running
|
||
varchar status
|
||
int loop_count
|
||
float avg_execution_ms
|
||
int uptime_seconds
|
||
float balance
|
||
float equity
|
||
float margin_used
|
||
int open_positions
|
||
float floating_pnl
|
||
float daily_pnl
|
||
varchar risk_mode
|
||
varchar current_session
|
||
bool is_golden_time
|
||
}
|
||
|
||
daily_summaries {
|
||
date summary_date PK
|
||
int total_trades
|
||
int winning_trades
|
||
int losing_trades
|
||
int breakeven_trades
|
||
float gross_profit
|
||
float gross_loss
|
||
float net_profit
|
||
float start_balance
|
||
float end_balance
|
||
float win_rate
|
||
float profit_factor
|
||
float avg_win
|
||
float avg_loss
|
||
int sydney_trades
|
||
int tokyo_trades
|
||
int london_trades
|
||
int ny_trades
|
||
int golden_trades
|
||
int fvg_trades
|
||
int fvg_wins
|
||
int ob_trades
|
||
int ob_wins
|
||
}
|
||
|
||
trades ||--o{ signals : "trade_ticket"
|
||
daily_summaries ||--o{ trades : "summary_date covers opened_at"
|
||
```
|
||
|
||
### trades
|
||
|
||
```sql
|
||
├── ticket, symbol, direction
|
||
├── entry_price, exit_price, stop_loss, take_profit
|
||
├── lot_size, profit_usd, profit_pips
|
||
├── opened_at, closed_at, duration_seconds
|
||
├── entry_regime, entry_volatility, entry_session
|
||
├── smc_signal, smc_confidence, smc_reason
|
||
├── smc_fvg_detected, smc_ob_detected, smc_bos_detected, smc_choch_detected
|
||
├── ml_signal, ml_confidence
|
||
├── market_quality, market_score, dynamic_threshold
|
||
├── exit_reason, exit_regime, exit_ml_signal
|
||
├── balance_before, balance_after, equity_at_entry
|
||
├── features_entry (JSON), features_exit (JSON)
|
||
└── bot_version, trade_mode
|
||
```
|
||
|
||
### training_runs
|
||
|
||
```sql
|
||
├── training_type, bars_used, num_boost_rounds
|
||
├── hmm_trained, hmm_n_regimes
|
||
├── xgb_trained, train_auc, test_auc
|
||
├── train_accuracy, test_accuracy
|
||
├── model_path, backup_path
|
||
├── success, error_message
|
||
├── started_at, completed_at, duration_seconds
|
||
└── rolled_back, rollback_reason, rollback_at
|
||
```
|
||
|
||
### signals
|
||
|
||
```sql
|
||
├── signal_time, symbol, price
|
||
├── signal_type, signal_source, combined_confidence
|
||
├── smc_*, ml_*
|
||
├── regime, session, volatility, market_score
|
||
└── executed, execution_reason, trade_ticket
|
||
```
|
||
|
||
### market_snapshots
|
||
|
||
```sql
|
||
├── snapshot_time, symbol, price, OHLC
|
||
├── regime, volatility, session, ATR, spread
|
||
├── ml_signal, ml_confidence, smc_signal, smc_confidence
|
||
└── open_positions, floating_pnl, features (JSON)
|
||
```
|
||
|
||
### bot_status
|
||
|
||
```sql
|
||
├── status_time, is_running, status
|
||
├── loop_count, avg_execution_ms, uptime_seconds
|
||
├── balance, equity, margin_used
|
||
├── open_positions, floating_pnl, daily_pnl
|
||
└── risk_mode, current_session, is_golden_time
|
||
```
|
||
|
||
### daily_summaries
|
||
|
||
```sql
|
||
├── summary_date
|
||
├── total/winning/losing/breakeven_trades
|
||
├── gross_profit, gross_loss, net_profit
|
||
├── start_balance, end_balance
|
||
├── win_rate, profit_factor, avg win/loss
|
||
├── trades per session (sydney/tokyo/london/ny/golden)
|
||
└── SMC pattern stats (fvg/ob trades & wins)
|
||
```
|
||
|
||
---
|
||
|
||
## *Graceful Degradation*
|
||
|
||
```
|
||
PostgreSQL tersedia?
|
||
├── Ya → Gunakan DB + CSV backup
|
||
└── Tidak → CSV saja (semua tetap berjalan)
|
||
|
||
Bot TIDAK pernah crash karena database.
|
||
```
|
||
|
||
*Graceful degradation* memastikan bot tetap beroperasi penuh meskipun *PostgreSQL* tidak tersedia. Semua operasi database dibungkus dengan `try/except` — jika koneksi gagal, data ditulis ke CSV sebagai fallback. Saat database kembali online, bot otomatis menggunakan koneksi pool kembali tanpa restart.
|