Sistem bot trading berbasis Python yang modular, real-time, dan production-ready untuk Bybit Perpetual Futures.
Bybit (WebSocket/REST)
│
▼
data_stream.py ← OrderBook, Funding Rate, Heartbeat
│
├─[DATA_MODE="tick"]──► data_resampler.py ← Susun candle dari tick mentah
│
└─[DATA_MODE="kline"]─► candle_stream.py ← Candle instan Bybit Kline WS
│
▼
strategy.py ← USER EDITS HERE ONLY
│
▼
execution.py ← Order placement (paper/live)
│
▼
position_manager.py ← Realtime PnL (bid/ask based)
│
▼
trade_logger.py ← CSV logging (trades + equity)
│
▼
dashboard.py ← Streamlit monitoring dashboard
pip install -r requirements.txtBuat file .env di folder utama (copy dari .env.example) dan isi kunci API Anda:
BYBIT_LIVE_API_KEY="api_key_live_kamu"
BYBIT_LIVE_API_SECRET="secret_live_kamu"
BYBIT_DEMO_API_KEY="api_key_demo_kamu"
BYBIT_DEMO_API_SECRET="secret_demo_kamu"Lalu edit konfigurasi tambahan di config.py:
SYMBOL = "DOGEUSDT" MODE = "paper" # "paper" | "demo" | "live"
DATA_MODE = "kline"
TIMEFRAMES = { "1m": (60, 200), # 1 menit, simpan 200 candle "15m": (900, 50), # 15 menit, simpan 50 candle # "1h": (3600, 30), # aktifkan dengan hapus tanda # }
### 3. Jalankan test suite (opsional, sangat cepat — ~2 detik)
```bash
pip install pytest pytest-cov pytest-asyncio # sekali install saja
python -m pytest # 65 test, ~2 detik
python -m pytest --cov # plus coverage report
Test cover: PnL math, signal generation, engine orchestration, monitoring. Berguna setelah refactor untuk pastikan tidak ada regresi.
python preflight_check.pyIni akan menjalankan 16 pengecekan otomatis terhadap strategy.py, terbagi dua level:
| Level | Contoh | Efek |
|---|---|---|
| Error Fatal | Syntax error, on_tick() tidak ada, time.sleep() di generate_signal |
Bot DIBLOKIR |
| Saran | HTTP request di tiap tick, file I/O, data parsial | Bot tetap bisa jalan, hanya diingatkan |
Validasi ini juga tersedia langsung di halaman ⚙️ Control Panel — klik saja tombol
▶️ Start Bot dan sistem akan memvalidasi otomatis sebelum bot dinyalakan.
python main.py
main.pyotomatis menjalankan pre-flight check saat startup. Jikastrategy.pypunya error fatal, bot akan berhenti dan tampilkan pesan errornya. Saran (warning) tetap ditampilkan tapi tidak menghentikan bot.
Untuk backtest:
streamlit run dashboard.py
# lalu buka menu 🔬 Backtest di sidebarpython -m streamlit run dashboard.pyThen open: http://localhost:8501
Jika Anda men-duplikasi folder bot untuk menjalankan strategi/koin berbeda (Misal: Bot_DOGE, Bot_BTC), Anda TIDAK PERLU menjalankan banyak dashboard.
Cukup buka 1 halaman Streamlit, lalu pada kolom teks Sidebar, masukkan path folder-folder bot Anda (setiap path beda baris). Aplikasi secara ajaib akan membaca rekaman mereka serentak dan menggambar 1 Portofolio Gabungan untuk seluruh kekayaan bot Anda!
| Paper | Demo | Live | |
|---|---|---|---|
| API Key | Tidak perlu | DEMO_API_KEY | API_KEY |
| Order | Simulasi lokal | Masuk server Bybit Demo | Uang nyata |
| PnL/Balance | Hitung lokal | Fetch dari Bybit tiap 2s | Fetch dari Bybit tiap 2s |
| Reset saldo | Restart bot | UI Bybit Demo | - |
| Cocok untuk | Dev & debug strategi | Validasi eksekusi API | Trading nyata |
- Login Bybit → Trade → Demo Trading
- Buat API Key: Account → API Management (pilih System-generated)
- Isi
config.py:
MODE = "demo"
DEMO_API_KEY = "api_key_dari_akun_demo"
DEMO_API_SECRET = "secret_dari_akun_demo"Kamu HANYA perlu edit strategy.py.
Strategi bebas menggunakan Machine Learning atau indikator teknikal biasa — tidak ada kewajiban. Yang penting, fungsi generate_signal() harus ada dan return format yang benar.
| Fungsi | Deskripsi |
|---|---|
generate_signal(data) |
SATU-SATUNYA fungsi yang wajib. Analisa data dan return sinyal. |
🎉 Sejak refactor strategy_runtime: Anda TIDAK PERLU menulis
on_tick(),execute_trade(), ataumanage_position(). Engine otomatis panggilgenerate_signal()setiap tick → catat ke dashboard → forward keexecution.place_order()jika action ≠ hold.
# generate_signal() HARUS return dict dengan key "action"
{"action": "buy" | "sell" | "close" | "hold", "reason": "alasan (opsional)"}Pre-flight check akan menjalankan
generate_signal()dengan data dummy saat startup. Jika return formatnya salah atau ada error, bot tidak akan jalan dan tampilkan pesan error.
def generate_signal(data):
candles = list(data["candles"].values())[0] # ambil timeframe apapun
if len(candles) < 20:
return {"action": "hold", "reason": "Data belum cukup"}
closes = [c["close"] for c in candles]
sma_fast = sum(closes[-5:]) / 5
sma_slow = sum(closes[-20:]) / 20
if sma_fast > sma_slow:
return {"action": "buy", "reason": "SMA5 cross above SMA20"}
return {"action": "hold", "reason": "Tidak ada sinyal"}Itu saja. Tidak perlu import execution, bot_monitor, atau menulis on_tick. Engine handle semuanya.
Hanya kalau Anda butuh kontrol penuh — misal sync state custom dengan position_manager seperti di strategy_ml.py (Random Forest + Triple Barrier). Jika on_tick() didefinisikan, engine bypass orkestrasi default dan serahkan eksekusi ke Anda. Lihat strategy_ml.py sebagai referensi.
def on_tick(data):
import execution, bot_monitor
signal = generate_signal(data)
bot_monitor.record_tick(signal, data=data) # WAJIB di mode advanced
if signal["action"] != "hold":
execution.place_order(signal)| Key | Isi |
|---|---|
data["candles"]["1m"] |
List candle 1m tertutup |
data["current"]["1m"] |
Candle 1m live (update tiap tick) |
data["candles"]["15m"] |
List candle 15m tertutup |
data["current"]["15m"] |
Candle 15m live (update tiap tick) |
data["best_bid"] / data["best_ask"] |
{"price": float, "qty": float} |
data["bid_ask_spread"] |
ask - bid |
data["orderbook_imbalance"] |
-1.0 (sell) to +1.0 (buy) |
data["volume_delta"] |
buy_vol - sell_vol (50 tick terakhir) |
data["funding_rate"] |
Funding rate saat ini |
data["latest_tick"] |
Tick terakhir {timestamp, price, qty, side} |
data["is_warmup"] |
True saat preload historis berlangsung — strategi tidak boleh order |
Label
"1m","15m"dst sesuai key yang kamu isi diTIMEFRAMESdalamconfig.py.
Saat startup, main.py mengambil candle historis via Bybit REST API (/v5/market/kline) untuk semua timeframe ≥ 1m dan mengisi buffer resampler secara langsung. Selama proses ini data["is_warmup"] = True — strategi otomatis return hold dan tidak akan generate order. Setelah selesai, flag di-set False dan bot masuk mode live.
Pilihan mode diatur via config.py → DATA_MODE:
DATA_MODE = "kline" (Default) |
DATA_MODE = "tick" |
|
|---|---|---|
| Sumber | Bybit Kline WebSocket | Bybit publicTrade WebSocket |
| RAM | Ringan | Berat (ribuan tick/menit) |
| Sinkronisasi TV | 100% sama | Bisa beda (repainting) |
| Volume Delta | Tidak tersedia | Tersedia |
| Cocok untuk | SMA, BB, RSI, MACD | Footprint, Order Flow |
candle_stream.py (kline mode): menerima update candle live dari Bybit.
Field "confirm": true = candle resmi ditutup → disimpan ke buffer historis.
data_resampler.py (tick mode): mengkonversi setiap tick menjadi candle OHLCV
sesuai timeframe yang dikonfigurasi di TIMEFRAMES.
BUY → entry @ ASK, exit @ BID
SELL → entry @ BID, exit @ ASK
Slippage tolerance configurable. Retry 3x dengan delay ms.
# LONG
unrealized_pnl = (bid_price - entry_price) * qty
# SHORT
unrealized_pnl = (entry_price - ask_price) * qty
equity = balance + unrealized_pnlheartbeat.json diupdate setiap detik. Dashboard baca file ini:
- ONLINE jika
time.time() - last_update < 5 - OFFLINE jika tidak diupdate lebih dari 5 detik
| File | Isi |
|---|---|
trade_history.csv |
Semua trade: entry/exit price, qty, PnL, alasan |
equity_curve.csv |
Snapshot balance/equity/unrealized tiap tick |
heartbeat.json |
Timestamp terakhir bot aktif |
| Risiko | Mitigasi |
|---|---|
| Latency | Gunakan VPS di region Bybit server (Singapore) |
| Slippage | SLIPPAGE_TOLERANCE di config.py |
| Market Volatility | Set TARGET_SL_PCT dan TARGET_TP_PCT di bagian paling atas strategy.py |
| Disconnect | Auto-reconnect WebSocket dengan exponential backoff |
| Partial Fill | Retry otomatis atau cancel (via CANCEL_ON_PARTIAL) |
# Install Python 3.10+
sudo apt update && sudo apt install python3.10 python3-pip -y
# Clone / upload project
cd /your/project
# Install deps
pip install -r requirements.txt
# Run bot in background
nohup python main.py > bot.log 2>&1 &
# Run dashboard
python -m streamlit run dashboard.pybot/
├── main.py ← Entry point (jalankan pre-flight check otomatis)
├── preflight_check.py ← Validator strategy.py (16 cek: error + warning)
├── config.py ← Konfigurasi semua parameter (termasuk DATA_MODE)
├── ft_types.py ← Pusat definisi tipe data (TypedDict: Candle, Signal, dll)
├── ccxt_client.py ← Wrapper CCXT Pro (init exchange, fetch market info, close)
├── .env.example ← Template API Key — copy ke .env dan isi
├── data_stream.py ← WebSocket orderbook + funding rate + heartbeat
├── candle_stream.py ← Bybit Kline WebSocket (aktif jika DATA_MODE="kline")
├── data_resampler.py ← Tick → candle realtime (aktif jika DATA_MODE="tick")
├── strategy.py ← USER EDIT DI SINI (cukup tulis generate_signal)
├── strategy_runtime.py ← Engine orkestrator (signal → record → execute)
├── tests/ ← pytest suite (65 test, coverage 72%) — `python -m pytest`
├── pytest.ini ← Konfigurasi pytest
├── strategy_sqz_backup.py← Backup strategi Squeeze Momentum asli
├── strategy_ml.py ← Variant ML (Random Forest + Triple Barrier) — referensi mode advanced
├── execution.py ← Order execution (paper / live)
├── position_manager.py ← PnL tracking
├── bot_monitor.py ← Health monitor: watchdog, error rate, data quality
├── trade_logger.py ← CSV logging (non-blocking)
├── dashboard.py ← Streamlit: Live Monitor Main Page
├── pages/ ← Streamlit: Menu tambahan (Multi-Page App)
│ ├── 1_backtest.py ← Simulasi backtest (Mode Colab & Mode Simulasi Live)
│ └── 2_control_panel.py← Start/Stop bot + validasi strategy sebelum run
├── trading_model_15m.pkl ← Model ML (opsional — jika tidak ada, strategy jalan tanpa ML)
├── trading_scaler_15m.pkl← Scaler ML (opsional)
├── requirements.txt
├── heartbeat.json ← Auto-generated
├── bot_health.json ← Auto-generated (health monitor metrics)
├── trade_history.csv ← Auto-generated
└── equity_curve.csv ← Auto-generated
Seluruh engine inti telah di-refactor dengan Mypy-compliant strict typing (Mei 2026). Tidak ada logika bisnis, formula matematika, atau integrasi API yang diubah — hanya anotasi tipe yang ditambahkan.
Semua struktur data kompleks didefinisikan sebagai TypedDict di satu tempat:
| TypedDict | Dipakai oleh |
|---|---|
Candle |
data_resampler, candle_stream, strategy |
MarketDataSnapshot |
Return type get_live_data() — kontrak antar semua modul |
Signal |
strategy → execution |
OrderResult |
execution |
PositionState |
position_manager |
PnlSummary |
position_manager → strategy → dashboard |
TradeLogRow / EquityLogRow |
trade_logger |
BotState |
strategy (state Triple Barrier) |
python -m mypy ft_types.py data_stream.py data_resampler.py execution.py \
strategy.py position_manager.py main.py trade_logger.py \
candle_stream.py --ignore-missing-imports --no-strict-optional
| File | Status |
|---|---|
ft_types.py |
0 error |
data_stream.py |
0 error |
data_resampler.py |
0 error |
execution.py |
0 error |
strategy.py |
0 error |
position_manager.py |
0 error |
main.py |
0 error |
trade_logger.py |
0 error |
candle_stream.py |
0 error |
bot_monitor.py |
Belum (monitoring only, tidak kritis) |
preflight_check.py |
Belum (dynamic import pattern, false positives) |
Typing berada di Level 3 (Pragmatic Strict): semua function signature dan variabel lokal dianotasi, menggunakan
TypedDictterpusat. Tidak menggunakanmypy --strictatau Pydantic karena data WebSocket dari Bybit bersifat dynamic JSON yang tidak bisa diverifikasi sepenuhnya saat compile time. link flowchart mermaid. short: https://h1.nu/1pCx7