Skip to main content

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 with CircuitOpenError.
  • 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:

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

  1. Create a virtual environment.
  2. Install with development dependencies: pip install -e ".[dev]".
  3. Keep public APIs stable unless a change is intentional and documented.
  4. Add or update tests for behavior changes.
  5. Run the full quality gate before opening a pull request.
  6. Never commit API tokens, account identifiers, or .env files.

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

deriv_sdk-1.0.0.tar.gz (55.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

deriv_sdk-1.0.0-py3-none-any.whl (74.9 kB view details)

Uploaded Python 3

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

Hashes for deriv_sdk-1.0.0.tar.gz
Algorithm Hash digest
SHA256 bad11cd342609feb873b65260e8f7fa9b65e379a2704c3e92c58ff7b1271ffd0
MD5 dcfdbb312c93e2ab421b8d0a4f0bf4c4
BLAKE2b-256 2c315669a2c9509fb0d75d4a893e6e961c50d8fcadc4793385a3cfc86ada7eb8

See more details on using hashes here.

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

Hashes for deriv_sdk-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 82f0aa9d1f22064d0df8b75c6c70acacfd2e30c03045836b905456b1d1c33791
MD5 742b6b8805dc93e1b964dd5ea27be92d
BLAKE2b-256 e5d7507627d58b92150dd404a46de1e01a2791d0d31c3c29b215facf087504e2

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page