Python + Deriv API: Cách Tạo Trading Bot Đầu Tiên Của Bạn
Đây là tutorial complete Python bot với Deriv API official. WebSocket connection, OAuth authentication, RSI strategy, và RiskManager class. Code production-ready, có thể deploy trực tiếp lên VPS.
📋 Prerequisites
1. Python 3.9+ installed
2. Tài khoản Deriv (demo enough) — sign up here
3. API token từ Deriv (tạo trong Settings)
4. Basic Python knowledge (variables, functions, async/await)
5. VS Code hoặc PyCharm editor
Tại Sao Chọn Python?
- Free và open-source: Không cần license
- Rich library ecosystem: NumPy, Pandas, TA-Lib cho analysis
- ML/AI integration: Pakai TensorFlow, scikit-learn cho predictions
- Cross-platform: Run trên Windows, Mac, Linux, VPS
- Active community: Stack Overflow, GitHub examples
- Deriv official support: SDK Python được Deriv maintain
Setup Step-by-Step
Install Python & Tools
Download Python 3.9+. Install VS Code. Verify với: python --version trong terminal.
Get Deriv API Token
Login Deriv → Account Settings → API Token. Create token với scopes: read, trade, payments. Copy token và save securely. Đây là “password” cho bot — không share.
Install Deriv Python SDK
Mở terminal trong project folder, run:
pip install python_deriv_api websocket-client pandas numpy
Create Project Structure
Tạo folder mới, files:
• bot.py — main script
• risk_manager.py — risk management class
• .env — store API token (không commit Git)
Code #1: WebSocket Connection Basic
Bước đầu — connect đến Deriv API qua WebSocket:
"""
Deriv API WebSocket Connection Test
Author: IA Trader Pro
"""
import asyncio
import json
import websockets
# === CONFIG ===
DERIV_WS_URL = "wss://ws.binaryws.com/websockets/v3?app_id=1089"
API_TOKEN = "YOUR_API_TOKEN_HERE" # Replace with your token
async def test_connection():
"""Test basic WebSocket connection to Deriv API."""
async with websockets.connect(DERIV_WS_URL) as ws:
# Authorize
auth_request = {
"authorize": API_TOKEN
}
await ws.send(json.dumps(auth_request))
response = await ws.recv()
data = json.loads(response)
if "error" in data:
print(f"✗ Auth failed: {data['error']['message']}")
return
print(f"✓ Connected as: {data['authorize']['loginid']}")
print(f" Balance: ${data['authorize']['balance']} {data['authorize']['currency']}")
print(f" Account type: {data['authorize']['account_type']}")
# Run
if __name__ == "__main__":
asyncio.run(test_connection())
Run: python connection_test.py
Expected output:
✓ Connected as: VRTC1234567 (Virtual demo account) Balance: $10000.00 USD Account type: virtual
Code #2: RiskManager Class
Heart của bot — class quản lý risk:
"""
Risk Management Class
Tracks daily losses, enforces limits, sizes positions.
"""
from datetime import datetime, date
from dataclasses import dataclass, field
@dataclass
class RiskManager:
"""Risk management for trading bot."""
# === CONFIGURATION ===
initial_balance: float = 1000.0
risk_per_trade_pct: float = 2.0 # 2% of balance
daily_loss_limit_pct: float = 5.0 # 5% daily stop
weekly_loss_limit_pct: float = 10.0 # 10% weekly stop
max_concurrent_positions: int = 3
max_trades_per_day: int = 10
cooldown_after_losses: int = 3 # consecutive losses
cooldown_minutes: int = 60
# === STATE TRACKING ===
current_balance: float = field(init=False)
daily_pnl: float = 0.0
weekly_pnl: float = 0.0
consecutive_losses: int = 0
trades_today: int = 0
open_positions: int = 0
cooldown_until: datetime = None
today_date: date = field(default_factory=date.today)
def __post_init__(self):
self.current_balance = self.initial_balance
# === CHECKS ===
def can_trade(self) -> tuple[bool, str]:
"""Check if bot is allowed to trade now."""
# Daily reset check
if date.today() != self.today_date:
self._reset_daily()
# Cooldown check
if self.cooldown_until and datetime.now() < self.cooldown_until:
mins_left = (self.cooldown_until - datetime.now()).seconds // 60
return False, f"Cooldown active ({mins_left} min left)"
# Daily loss limit
daily_loss_pct = abs(min(self.daily_pnl, 0)) / self.current_balance * 100
if daily_loss_pct >= self.daily_loss_limit_pct:
return False, f"Daily loss limit hit ({daily_loss_pct:.1f}%)"
# Weekly loss limit
weekly_loss_pct = abs(min(self.weekly_pnl, 0)) / self.current_balance * 100
if weekly_loss_pct >= self.weekly_loss_limit_pct:
return False, f"Weekly loss limit hit ({weekly_loss_pct:.1f}%)"
# Max trades per day
if self.trades_today >= self.max_trades_per_day:
return False, f"Max trades reached ({self.max_trades_per_day})"
# Max concurrent positions
if self.open_positions >= self.max_concurrent_positions:
return False, f"Max positions open ({self.open_positions})"
return True, "OK to trade"
def calculate_stake(self) -> float:
"""Calculate stake size based on 2% rule."""
return round(self.current_balance * self.risk_per_trade_pct / 100, 2)
# === UPDATES ===
def on_trade_result(self, pnl: float):
"""Update state after trade result."""
self.current_balance += pnl
self.daily_pnl += pnl
self.weekly_pnl += pnl
self.trades_today += 1
self.open_positions = max(0, self.open_positions - 1)
if pnl < 0:
self.consecutive_losses += 1
# Check cooldown trigger
if self.consecutive_losses >= self.cooldown_after_losses:
from datetime import timedelta
self.cooldown_until = datetime.now() + timedelta(minutes=self.cooldown_minutes)
print(f"⚠ Cooldown triggered: {self.cooldown_minutes} min")
self.consecutive_losses = 0 # Reset counter
else:
self.consecutive_losses = 0
def on_trade_open(self):
"""Track new open position."""
self.open_positions += 1
def _reset_daily(self):
"""Reset daily counters."""
self.daily_pnl = 0.0
self.trades_today = 0
self.today_date = date.today()
print(f"📅 Daily reset: {self.today_date}")
# === REPORTING ===
def status_summary(self) -> str:
"""Get current status summary."""
return f"""
═══════════════════════════════════════
Balance: ${self.current_balance:.2f}
Daily P/L: ${self.daily_pnl:+.2f} ({self.daily_pnl/self.current_balance*100:+.1f}%)
Weekly P/L: ${self.weekly_pnl:+.2f}
Trades today: {self.trades_today}/{self.max_trades_per_day}
Open positions: {self.open_positions}/{self.max_concurrent_positions}
Consecutive losses: {self.consecutive_losses}
Cooldown: {self.cooldown_until.strftime('%H:%M') if self.cooldown_until else 'None'}
═══════════════════════════════════════
"""
Code #3: RSI Bot Main Script
Main bot kết hợp WebSocket + RSI strategy + RiskManager:
"""
Deriv V75 RSI Trading Bot — Production Ready
Strategy: BUY CALL when RSI < 30, BUY PUT when RSI > 70
Risk: 2% stake, 5% daily loss limit
"""
import asyncio
import json
import websockets
import pandas as pd
import numpy as np
from datetime import datetime
from risk_manager import RiskManager
# === CONFIG ===
DERIV_WS_URL = "wss://ws.binaryws.com/websockets/v3?app_id=1089"
API_TOKEN = "YOUR_API_TOKEN_HERE" # From Deriv account settings
ASSET = "R_75" # Volatility 75 Index
DURATION = 5 # ticks
RSI_PERIOD = 14
RSI_OVERSOLD = 30
RSI_OVERBOUGHT = 70
# === INDICATORS ===
def calculate_rsi(prices: pd.Series, period: int = 14) -> float:
"""Calculate RSI from price series."""
delta = prices.diff()
gain = delta.where(delta > 0, 0).rolling(window=period).mean()
loss = -delta.where(delta < 0, 0).rolling(window=period).mean()
rs = gain / loss
rsi = 100 - (100 / (1 + rs))
return rsi.iloc[-1] if not rsi.empty else 50.0
# === BOT CLASS ===
class DerivBot:
def __init__(self, api_token: str):
self.api_token = api_token
self.ws = None
self.risk_mgr = RiskManager(initial_balance=10000.0)
self.candles = []
self.req_id = 0
async def connect(self):
"""Connect and authorize."""
self.ws = await websockets.connect(DERIV_WS_URL)
await self._send({"authorize": self.api_token})
response = await self._recv()
if "error" in response:
raise Exception(f"Auth failed: {response['error']['message']}")
self.risk_mgr.current_balance = float(response["authorize"]["balance"])
self.risk_mgr.initial_balance = self.risk_mgr.current_balance
print(f"✓ Connected: {response['authorize']['loginid']}")
print(f" Balance: ${self.risk_mgr.current_balance:.2f}")
async def subscribe_candles(self):
"""Subscribe to candle updates."""
await self._send({
"ticks_history": ASSET,
"adjust_start_time": 1,
"count": 100,
"end": "latest",
"start": 1,
"style": "candles",
"granularity": 60, # 1 minute candles
"subscribe": 1
})
# Get initial history
response = await self._recv()
if "candles" in response:
self.candles = [
{"close": c["close"]} for c in response["candles"]
]
print(f"📊 Loaded {len(self.candles)} historical candles")
async def place_trade(self, direction: str, stake: float):
"""Place CALL or PUT trade."""
contract_type = "CALL" if direction == "BUY" else "PUT"
await self._send({
"buy": 1,
"subscribe": 1,
"price": stake,
"parameters": {
"amount": stake,
"basis": "stake",
"contract_type": contract_type,
"currency": "USD",
"duration": DURATION,
"duration_unit": "t", # ticks
"symbol": ASSET
}
})
response = await self._recv()
if "error" in response:
print(f" ✗ Trade error: {response['error']['message']}")
return None
contract_id = response["buy"]["contract_id"]
self.risk_mgr.on_trade_open()
print(f" 📈 Trade placed: {contract_type} ID {contract_id} stake ${stake}")
# Wait for result
return await self._wait_for_result(contract_id, stake)
async def _wait_for_result(self, contract_id: int, stake: float):
"""Wait for trade to complete."""
while True:
response = await self._recv()
if response.get("proposal_open_contract", {}).get("contract_id") == contract_id:
contract = response["proposal_open_contract"]
if contract.get("is_sold"):
payout = float(contract["payout"])
pnl = payout - stake if payout > stake else -stake
self.risk_mgr.on_trade_result(pnl)
result = "WIN" if pnl > 0 else "LOSS"
print(f" {'✓' if pnl > 0 else '✗'} {result}: ${pnl:+.2f} | Balance: ${self.risk_mgr.current_balance:.2f}")
return pnl
async def run_strategy(self):
"""Main strategy loop."""
print(f"\n🤖 Bot started: V75 RSI Strategy")
print(self.risk_mgr.status_summary())
while True:
try:
response = await self._recv()
# New candle received
if "ohlc" in response:
candle = response["ohlc"]
self.candles.append({"close": float(candle["close"])})
if len(self.candles) > 100:
self.candles.pop(0)
# Need at least RSI_PERIOD candles
if len(self.candles) < RSI_PERIOD:
continue
# Risk check
can_trade, reason = self.risk_mgr.can_trade()
if not can_trade:
print(f"⏸ {reason}")
await asyncio.sleep(60)
continue
# Calculate RSI
prices = pd.Series([c["close"] for c in self.candles])
rsi = calculate_rsi(prices, RSI_PERIOD)
timestamp = datetime.now().strftime("%H:%M:%S")
print(f"\n[{timestamp}] RSI: {rsi:.1f} | Price: {prices.iloc[-1]:.2f}")
# Trading logic
stake = self.risk_mgr.calculate_stake()
if rsi < RSI_OVERSOLD:
print(f" 🟢 RSI oversold ({rsi:.1f} < {RSI_OVERSOLD}) — BUY CALL")
await self.place_trade("BUY", stake)
elif rsi > RSI_OVERBOUGHT:
print(f" 🔴 RSI overbought ({rsi:.1f} > {RSI_OVERBOUGHT}) — BUY PUT")
await self.place_trade("SELL", stake)
else:
print(f" ⏹ RSI neutral — skip")
except websockets.ConnectionClosed:
print("⚠ Connection lost, reconnecting...")
await asyncio.sleep(5)
await self.connect()
await self.subscribe_candles()
except Exception as e:
print(f"✗ Error: {e}")
await asyncio.sleep(5)
# === HELPERS ===
async def _send(self, request: dict):
"""Send request with auto req_id."""
self.req_id += 1
request["req_id"] = self.req_id
await self.ws.send(json.dumps(request))
async def _recv(self) -> dict:
"""Receive response."""
return json.loads(await self.ws.recv())
# === MAIN ===
async def main():
bot = DerivBot(API_TOKEN)
await bot.connect()
await bot.subscribe_candles()
await bot.run_strategy()
if __name__ == "__main__":
print("🚀 Starting Deriv V75 RSI Bot...")
print(" Press Ctrl+C to stop\n")
try:
asyncio.run(main())
except KeyboardInterrupt:
print("\n\n⏹ Bot stopped by user")
Cách Run Bot
- Save 2 files (
bot.py+risk_manager.py) trong cùng folder - Replace
YOUR_API_TOKEN_HEREvới token thực của bạn - Open terminal trong folder
- Run:
python bot.py - Bot sẽ connect, load 100 historical candles, và bắt đầu trade khi có signal
- Press Ctrl+C để stop bot
Expected Output
🚀 Starting Deriv V75 RSI Bot... Press Ctrl+C to stop ✓ Connected: VRTC1234567 Balance: $10000.00 📊 Loaded 100 historical candles 🤖 Bot started: V75 RSI Strategy ═══════════════════════════════════════ Balance: $10000.00 Daily P/L: $+0.00 (+0.0%) Weekly P/L: $+0.00 Trades today: 0/10 Open positions: 0/3 Consecutive losses: 0 Cooldown: None ═══════════════════════════════════════ [14:23:15] RSI: 28.4 | Price: 458.32 🟢 RSI oversold (28.4 < 30) — BUY CALL 📈 Trade placed: CALL ID 178234982 stake $200.00 ✓ WIN: $+181.00 | Balance: $10181.00 [14:24:30] RSI: 52.1 | Price: 459.41 ⏹ RSI neutral — skip [14:25:45] RSI: 73.8 | Price: 461.55 🔴 RSI overbought (73.8 > 70) — BUY PUT 📈 Trade placed: PUT ID 178234999 stake $200.00 ✗ LOSS: $-200.00 | Balance: $9981.00
Deploy lên VPS
Để bot run 24/7, deploy lên VPS:
- Rent VPS: DigitalOcean ($6/month), AWS EC2 free tier, hoặc Hetzner Cloud
- SSH vào server qua Terminal hoặc PuTTY
- Install Python:
sudo apt install python3 python3-pip - Install dependencies:
pip3 install python_deriv_api websocket-client pandas numpy - Upload code: SCP hoặc git clone
- Run với screen/tmux để bot continue khi disconnect:
# Install screen sudo apt install screen # Start new screen session screen -S derivbot # Run bot python3 bot.py # Detach: Ctrl+A then D # Re-attach later: screen -r derivbot
Improvements & Next Steps
Add Logging
- Save mỗi trade vào CSV file cho analysis sau
- Log errors riêng để debug
- Use Python’s
loggingmodule
Add Notifications
- Telegram bot cho alerts khi big wins/losses
- Email notifications khi daily limit hit
- Discord webhook cho community sharing
Multi-Asset Trading
- Run multiple symbols concurrent (V75 + V100 + Boom 500)
- Diversification reduces correlation risk
- Need separate RiskManager per asset
ML Integration
- scikit-learn cho price prediction
- TensorFlow LSTM cho sequence modeling
- Sentiment analysis từ news APIs
Common Errors & Fixes
🐛 Troubleshooting
“Authorization failed”: Token expired or invalid. Generate new từ Deriv settings.
“Connection closed unexpectedly”: Internet issue or rate limit. Bot tự reconnect.
“Insufficient balance”: Stake quá lớn cho balance hiện tại. Check 2% rule.
“Contract not found”: Trade duration expired before result. Increase wait time.
“RSI not computed”: Cần ít nhất 14 candles trước khi compute RSI.
Security Best Practices
🔐 Bảo Mật
1. Never hardcode API token trong code committed Git
2. Use environment variables hoặc .env file (gitignored)
3. Restrict token scopes: chỉ enable read + trade (không enable admin)
4. Rotate tokens monthly cho security
5. Monitor account activity daily — unusual trades = compromised
6. VPS firewall: chỉ allow SSH từ IP của bạn
🚀 Cần Deriv API token? Mở demo account miễn phí (instant access):
Mở Demo Deriv Miễn PhíBài Liên Quan
- Deriv Bot (No-Code Alternative)
- MT5 EA (MQL5 Alternative)
- Python IQ Option — Risks
- Risk Management Bots
- Real Test Bot 70% Win Rate
