Deriv Python SDK
Stable release tag: v1.0.0
Python package version: 1.0.0
The Deriv Python SDK is an asynchronous Python client for the Deriv WebSocket
API. It provides a high-level DerivClient, typed market and trading models,
request middleware, streaming subscriptions, retries, rate limiting, circuit
breakers, health snapshots, metrics, and secure structured logging.
The SDK is designed for market-data tools, dashboards, diagnostics, and applications that need a stable async interface to Deriv. Live integration tests and examples are non-trading by default. This repository does not place live trades during normal tests.
Supported Python Versions
- Python 3.12
- Python 3.13
- Python 3.14
Features
- Async WebSocket client
- High-level
DerivClient - Auth service
- Market service for active symbols, tick history, trading times, contracts, and tick subscriptions
- Trading service wrappers for proposal, buy, balance, contract, and transaction APIs
- Typed response models
- Request middleware pipeline
- Configurable retry policy
- Circuit breaker support
- Async token-bucket rate limiter
- Request health and metrics snapshots
- Structured logging with recursive redaction
- Idempotent startup and shutdown
Installation
Install from PyPI:
pip install deriv-sdk
Install from source:
git clone https://github.com/Sarahsam01/deriv-python-sdk.git
cd deriv-python-sdk
python -m venv venv
venv\Scripts\python.exe -m pip install -e ".[dev]"
On macOS or Linux, replace venv\Scripts\python.exe with
venv/bin/python.
Quick Start
import asyncio
from deriv_sdk import DerivClient
async def main() -> None:
client = DerivClient(
app_id="1089",
api_token="YOUR_TOKEN",
)
try:
await client.start()
symbols = await client.market.active_symbols()
print(f"Loaded {len(symbols)} active symbols")
finally:
await client.close()
asyncio.run(main())
Authentication
app_id identifies your Deriv application. Use Deriv's public app id for
testing, or your own registered app id for production.
api_token authorizes account-specific calls. Keep tokens out of source code.
The SDK redacts token-like fields from logs, but your application should still
load tokens from environment variables or a secret manager.
Common environment variables:
$env:DERIV_APP_ID="1089"
$env:DERIV_API_TOKEN="YOUR_TOKEN"
Virtual accounts are recommended while developing. Use a virtual account token for account-specific examples and avoid running buy flows unless you explicitly intend to trade.
Manual authorization:
client = DerivClient(app_id="1089")
await client.start()
authorize_response = await client.auth.authorize("YOUR_TOKEN")
print(authorize_response["msg_type"])
Client Lifecycle
Start and close explicitly:
client = DerivClient(app_id="1089", api_token="YOUR_TOKEN")
await client.start()
await client.close()
Use an async context manager for automatic cleanup:
async with DerivClient(app_id="1089", api_token="YOUR_TOKEN") as client:
symbols = await client.market.active_symbols()
start() connects the WebSocket transport and authorizes when api_token is
configured. close() is idempotent and closes the transport, heartbeat,
receiver task, and pending requests.
Market Service
Active symbols:
symbols = await client.market.active_symbols(brief=False)
Tick history:
history = await client.market.ticks_history("R_100", count=100)
Candle history:
candles = await client.market.ticks_history(
"R_100",
count=60,
granularity=60,
style="candles",
)
Trading times:
times = await client.market.trading_times()
Contracts for a symbol:
contracts = await client.market.contracts_for("R_100", currency="USD")
Tick subscription:
subscription = await client.market.subscribe_ticks("R_100")
try:
tick = await subscription.__anext__()
print(tick.quote)
finally:
await subscription.unsubscribe()
Trading Services
The stable release exposes safe wrappers for proposal, buy, balance, contract, and transaction requests.
Proposal quote, which does not place a trade:
quote = await client.proposal.request(
symbol="R_100",
contract_type="CALL",
amount=1.0,
basis="stake",
currency="USD",
duration=5,
duration_unit="t",
)
print(quote.id)
Buy is available as client.buy.buy(...), but it places a real contract
purchase when used with an authorized real account. Do not run buy examples
against a real account unless you deliberately intend to trade:
# Trading example only. Do not run against a real account by accident.
# result = await client.buy.buy(proposal_id=quote.id, price=quote.ask_price)
Balance:
balance = await client.balance.get()
print(balance.balance, balance.currency)
Contract details:
contract = await client.contract.get(contract_id=123456789)
Transaction details:
transaction = await client.transaction.get(transaction_id=123456789)
Portfolio and profit table services are not exposed as public v1.0.0
service APIs. Use only documented public services unless a future release adds
those endpoints.
Streaming
subscribe_ticks() returns an async subscription. Iterate over it with
async for, and unsubscribe when finished:
subscription = await client.market.subscribe_ticks("R_100")
try:
async for tick in subscription:
print(tick.symbol, tick.quote)
break
finally:
await subscription.unsubscribe()
The WebSocket receiver is the only component that calls recv(). Streaming
messages are dispatched from the receiver to the market subscription manager.
Middleware
Requests pass through the middleware pipeline in this order by default:
LoggingMiddleware
ValidationMiddleware
RetryMiddleware
Request flow:
before_request: first to last
transport call
after_response: last to first
on_exception: last to first
LoggingMiddleware records structured request events and redacts sensitive
fields recursively. ValidationMiddleware checks response message type.
RetryMiddleware decides whether a failed attempt is eligible for another
try; RequestEngine performs the retry loop and sleeps.
Retry
Configure retry behavior with RetryPolicy:
from deriv_sdk.request.retry_policy import RetryPolicy
policy = RetryPolicy(
enabled=True,
max_attempts=2,
initial_delay=0.25,
backoff_multiplier=2.0,
max_delay=2.0,
jitter=True,
)
response = await client.request_engine.send(
{"ping": 1},
retry_policy=policy,
)
max_attempts means retries after the initial attempt. API, validation,
client-closed, and circuit-open errors are not retried by default.
Circuit Breaker
Use CircuitBreaker to reject calls after repeated failures:
from deriv_sdk.resilience import CircuitBreaker
breaker = CircuitBreaker(
failure_threshold=5,
recovery_timeout=30.0,
)
await client.request_engine.send(
{"ping": 1},
circuit_breaker=breaker,
)
States:
CLOSED: requests are allowed.OPEN: requests are rejected withCircuitOpenError.HALF_OPEN: limited probe requests are allowed to test recovery.
Rate Limiting
Use AsyncRateLimiter to limit request bursts:
from deriv_sdk.resilience import AsyncRateLimiter
limiter = AsyncRateLimiter(rate=10, burst=20)
await client.request_engine.send(
{"ping": 1},
rate_limiter=limiter,
)
Create separate limiter instances for per-endpoint buckets.
Health and Metrics
health = client.health()
metrics = client.metrics()
print(health.connected)
print(health.pending_requests)
print(metrics.total_requests)
print(metrics.average_latency)
client.reset_metrics()
Snapshots are typed and do not contain raw payloads or secrets.
Exceptions
All public SDK exceptions inherit from DerivError:
DerivError
├── ConfigurationError
├── TransportError
│ ├── ConnectionError
│ ├── TimeoutError
│ ├── RequestCancelledError
│ ├── ClientClosedError
│ ├── ReconnectError
│ └── MessageRouterError
├── ValidationError
├── APIError
│ ├── AuthenticationError
│ ├── AuthorizationError
│ ├── ProposalError
│ ├── BuyError
│ ├── ContractError
│ ├── BalanceError
│ └── RateLimitError
├── CircuitOpenError
├── RetryExhaustedError
├── SubscriptionError
└── ParsingError
Examples
The examples/ directory contains:
examples/live_smoke_test.py: opt-in live, non-trading smoke test for connection, market data, and tick streaming.examples/active_symbols_diagnostic.py: opt-in diagnostic script for comparing active-symbols request variants.
Run the live smoke test:
$env:DERIV_APP_ID="1089"
$env:DERIV_API_TOKEN="YOUR_TOKEN"
venv\Scripts\python.exe examples\live_smoke_test.py
DERIV_API_TOKEN is optional for public market-data checks.
Known live-environment limitation: active_symbols may return an empty array
for some configured app or account environments without an API error.
Testing
Run non-live tests:
venv\Scripts\python.exe -m pytest -v
Run quality gates:
venv\Scripts\python.exe -m compileall deriv_sdk tests examples
venv\Scripts\python.exe -m ruff format --check .
venv\Scripts\python.exe -m ruff check .
venv\Scripts\python.exe -m mypy deriv_sdk
venv\Scripts\python.exe -m pytest -v
venv\Scripts\python.exe -m build
venv\Scripts\python.exe -m twine check dist\*
Live integration tests are marked with integration and skipped by default:
venv\Scripts\python.exe -m pytest -m integration -v
Contributing
- Create a virtual environment.
- Install with development dependencies:
pip install -e ".[dev]". - Keep public APIs stable unless a change is intentional and documented.
- Add or update tests for behavior changes.
- Run the full quality gate before opening a pull request.
- Never commit API tokens, account identifiers, or
.envfiles.
API and Architecture Documentation
License
MIT. See LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file deriv_sdk-1.0.0.tar.gz.
File metadata
- Download URL: deriv_sdk-1.0.0.tar.gz
- Upload date:
- Size: 55.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bad11cd342609feb873b65260e8f7fa9b65e379a2704c3e92c58ff7b1271ffd0
|
|
| MD5 |
dcfdbb312c93e2ab421b8d0a4f0bf4c4
|
|
| BLAKE2b-256 |
2c315669a2c9509fb0d75d4a893e6e961c50d8fcadc4793385a3cfc86ada7eb8
|
File details
Details for the file deriv_sdk-1.0.0-py3-none-any.whl.
File metadata
- Download URL: deriv_sdk-1.0.0-py3-none-any.whl
- Upload date:
- Size: 74.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
82f0aa9d1f22064d0df8b75c6c70acacfd2e30c03045836b905456b1d1c33791
|
|
| MD5 |
742b6b8805dc93e1b964dd5ea27be92d
|
|
| BLAKE2b-256 |
e5d7507627d58b92150dd404a46de1e01a2791d0d31c3c29b215facf087504e2
|