Why this tutorial exists (and what it is not): Deriv has a genuinely public API and a well-documented WebSocket, which is rare among platforms in this segment. It is excellent material for learning to program bots — authentication, data streaming, asynchronous processing. This page teaches the technology. It does not recommend trading Deriv's synthetic indices or fixed-odds contracts — those products are not regulated by Brazil's securities regulator (CVM) and carry the risks typical of the segment. Use the WebSocket knowledge you pick up here to connect to any platform with an API.
01Why study the Deriv API
Three reasons it makes a good technical case study: public, clear documentation, a free sandbox/demo for testing (with no deposit required), and the WebSocket protocol — which is exactly what you will need to understand in order to connect to any modern crypto exchange, to MT5 via a bridge, or to any platform with real-time data streaming. What you learn here transfers directly to Binance, Bybit and Deribit.
02Setting up the environment
You need Python 3.11+, a virtualenv and two libraries. In the terminal:
# Create the project and an isolated environment mkdir bot-deriv && cd bot-deriv python -m venv venv source venv/bin/activate # Linux/Mac # venv\Scripts\activate # Windows # Install dependencies pip install websockets asyncio python-dotenv
Next, create a demo account on Deriv (free, no deposit) just to get an API token with read-only scope. You do not need to deposit or trade.
- Go to
app.deriv.comand create a demo account - Go to Settings → API tokens
- Create a token with the
Read(read-only) scope for this tutorial - Copy the token and store it in a
.envfile in the project:
# .env DERIV_TOKEN=seu_token_aqui DERIV_APP_ID=1089 # public test app_id
03Hello World: connecting to the WebSocket
Deriv's server uses WebSocket at wss://ws.derivws.com/websockets/v3. All communication is asynchronous — you send a JSON message and the server replies in JSON too, possibly as a stream. First contact:
# conectar.py import asyncio, json, os import websockets from dotenv import load_dotenv load_dotenv() APP_ID = os.getenv("DERIV_APP_ID") URL = f"wss://ws.derivws.com/websockets/v3?app_id={APP_ID}" async def ping(): async with websockets.connect(URL) as ws: await ws.send(json.dumps({"ping": 1})) resposta = await ws.recv() print("Servidor respondeu:", resposta) asyncio.run(ping())
Run it with python conectar.py. You should see {"echo_req": {"ping": 1}, "msg_type": "pong", "ping": "pong"}. If you did, congratulations — you are connected. If not, check your firewall or proxy.
04Authentication
After the handshake, you authorize with the token:
# autenticar.py async def autenticar(): token = os.getenv("DERIV_TOKEN") async with websockets.connect(URL) as ws: await ws.send(json.dumps({"authorize": token})) resp = json.loads(await ws.recv()) if "error" in resp: print("Falha:", resp["error"]["message"]) else: print("Conta:", resp["authorize"]["loginid"]) print("Saldo:", resp["authorize"]["balance"])
Security best practice: never commit the token to Git. Always use .env + .gitignore. For production, use secret vaults (AWS Secrets Manager, HashiCorp Vault).
05Streaming candles in real time
This is where WebSocket shines. Instead of polling a REST endpoint every second, you subscribe to a stream and the server pushes updates on its own:
# candles.py async def stream_candles(symbol="frxEURUSD", granularity=60): async with websockets.connect(URL) as ws: await ws.send(json.dumps({ "ticks_history": symbol, "adjust_start_time": 1, "count": 100, "end": "latest", "style": "candles", "granularity": granularity, "subscribe": 1 })) while True: msg = json.loads(await ws.recv()) if msg.get("msg_type") == "ohlc": c = msg["ohlc"] print(f"{c['epoch']} O:{c['open']} H:{c['high']} L:{c['low']} C:{c['close']}") asyncio.run(stream_candles())
The subscribe: 1 parameter is the magic — it keeps the connection open and pushes every new candle. You do not have to ask again.
06Structuring it like a real bot
The example above is for teaching. A real bot has three separate layers: connection (automatic reconnection, heartbeat), strategy (pure, testable rules), and execution (sending orders, managing state). Recommended skeleton:
# structure/ # ├── client.py # WebSocket + reconnect + heartbeat # ├── strategy.py # Pure functions: given a DataFrame, returns a signal # ├── executor.py # Sends orders, tracks the open position # ├── risk.py # Stop loss, take profit, position sizing # └── main.py # Glues it all together # strategy.py - exemplo: cruzamento de médias import pandas as pd def calcular_sinal(df: pd.DataFrame) -> str: df["ma_curta"] = df["close"].rolling(9).mean() df["ma_longa"] = df["close"].rolling(21).mean() ultima = df.iloc[-1] anterior = df.iloc[-2] # Cross up if anterior["ma_curta"] < anterior["ma_longa"] and ultima["ma_curta"] > ultima["ma_longa"]: return "compra" # Cross down if anterior["ma_curta"] > anterior["ma_longa"] and ultima["ma_curta"] < ultima["ma_longa"]: return "venda" return "hold"
The separation matters: a strategy written as a pure function is testable with pytest in seconds, without connecting to anything. You run a backtest with 5 years of data, validate it, and only then plug it into the real executor.
07Error handling and reconnection
A WebSocket in production will drop. Servers restart, networks wobble, timeouts expire. A bot that does not reconnect is a useless bot. Recommended pattern:
async def conectar_com_retry(): backoff = 1 while True: try: async with websockets.connect(URL, ping_interval=20) as ws: print("Conectado") backoff = 1 # reset await rotina_principal(ws) except (websockets.ConnectionClosed, OSError) as e: print(f"Conexão caiu: {e}. Reconectando em {backoff}s") await asyncio.sleep(backoff) backoff = min(backoff * 2, 60) # exponential, capped at 60s
08Where to apply this knowledge
The WebSocket + asyncio pattern you have learned works on almost every modern platform with streaming. Where it takes you:
- Binance / Bybit — similar APIs, identical philosophy.
websockets+ authentication + candle stream. The code barely changes. - MT5 via the Python library — it is not pure WebSocket, but the "strategy as a pure function + executor" structure applies directly.
- TradingView Webhooks — you are on the other side: you receive alerts over HTTP and use this pattern to process them.
- Regulated market (Brazil's B3 exchange) — Brazilian brokers offer proprietary APIs; the streaming logic and the separation of layers still apply.
Want the complete bot skeleton?
Download our sample project on GitHub — code commented line by line, with tests and a clean architecture.
Download the free bot →