# cTrader Open API Python quickstart

Independent and unofficial. Not affiliated with or endorsed by any broker or platform named here. Educational only: nothing here is advice, and nothing here recommends a broker or a trade.

This is the markdown version of https://openbrokerapi.com/platforms/ctrader/quickstart, written from the same records as that page.

Risk warning: CFDs and spread bets are complex instruments and come with a high risk of losing money rapidly due to leverage. You can lose money on these products, and each provider publishes its own loss figure under FCA rules. You should consider whether you understand how they work and whether you can afford to take the high risk of losing your money. Automated and API trading can amplify losses through bugs, connectivity failures and runaway orders.

cTrader Open API in Python: register an app, get a token by OAuth or the Playground, install OpenApiPy and list your accounts on the demo host.

- Checked: 2026-09-18

Unverified: the code on this page was written from the documentation and has not yet been run on a demo account.

Demo accounts only. Credentials are read from environment variables on your own machine. No field on this site asks for a key, a username or a password.

## Steps

### 1. Register an app

Register at the cTrader Open API Portal (openapi.ctrader.com) with a cTID. Describe your use case in detail and give a valid redirect URL. Spotware reviews new apps and you need its approval before you start coding.

Status: verified. Source: [help.ctrader.com](https://help.ctrader.com/open-api/creating-new-app/), checked 2026-09-18.

### 2. Get a test token from the Playground

Once approved, the Playground button on your Applications page gives an access token for your own cTID, so you can skip building the OAuth flow while you test.

Status: verified. Source: [help.ctrader.com](https://help.ctrader.com/open-api/account-authentication/), checked 2026-09-18.

### 3. Or run the OAuth flow

Send the user to id.ctrader.com with client_id, redirect_uri, scope and product=web. Ask for scope accounts (view only), not trading. The code lasts one minute; exchange it at openapi.ctrader.com/apps/token for an access token (about 30 days) and a refresh token that does not expire but works once.

Python:

```python
import os
from ctrader_open_api import Auth

# App credentials from openapi.ctrader.com, kept in environment variables
auth = Auth(os.environ["CTRADER_CLIENT_ID"],
            os.environ["CTRADER_CLIENT_SECRET"],
            os.environ["CTRADER_REDIRECT_URI"])
print("Open this URL and approve the accounts scope:")
print(auth.getAuthUri())
# After approval, copy the code from the redirect within one minute, then:
# token = auth.getToken(os.environ["CTRADER_AUTH_CODE"])
# Store token values in your own secret store, not in code.
```

JavaScript:

```javascript
// Node 18 or later. Builds the authorisation URL; the user approves in a browser.
const params = new URLSearchParams({
  client_id: process.env.CTRADER_CLIENT_ID,
  redirect_uri: process.env.CTRADER_REDIRECT_URI,
  scope: "accounts",  // view only; do not request trading yet
  product: "web"
});
console.log(`https://id.ctrader.com/my/settings/openapi/grantingaccess/?${params}`);
```

curl:

```bash
# Exchange the one minute authorisation code for tokens (values from env vars)
curl -X GET "https://openapi.ctrader.com/apps/token?grant_type=authorization_code&code=$CTRADER_AUTH_CODE&redirect_uri=$CTRADER_REDIRECT_URI&client_id=$CTRADER_CLIENT_ID&client_secret=$CTRADER_CLIENT_SECRET"
```

Status: verified. Source: [help.ctrader.com](https://help.ctrader.com/open-api/account-authentication/), checked 2026-09-18.

### 4. Install OpenApiPy

Spotware's Python package is ctrader-open-api on PyPI, version 0.9.2 from 26 Jun 2024, for Python 3.8 or later. It is asynchronous, built on Twisted, and methods return Twisted deferreds. MIT licence.

Python:

```python
pip install ctrader-open-api
```

JavaScript:

```javascript
// The Open API runs over TCP or WebSocket with Protobuf or JSON messages,
// not REST. Use the Python tab (OpenApiPy) or Spotware's C# package.
```

curl:

```bash
# The Open API is not a REST API, so there is no curl call for this step.
# Use the Python tab.
```

Status: verified. Source: [pypi.org](https://pypi.org/project/ctrader-open-api/), checked 2026-09-18.

### 5. Connect to demo

Demo is demo.ctraderapi.com and live is live.ctraderapi.com, port 5035 for Protobuf and 5036 for JSON. The environments are fully separated: demo accounts cannot be used on the live host.

Status: verified. Source: [help.ctrader.com](https://help.ctrader.com/open-api/proxies-endpoints/), checked 2026-09-18.

### 6. First call: list your accounts

Authorise the app with ProtoOAApplicationAuthReq (client ID and secret), then send ProtoOAGetAccountListByAccessTokenReq with the access token. Each account comes back with ctidTraderAccountId, isLive and brokerTitleShort. ProtoOAAccountAuthReq comes next, before any account data.

Python:

```python
import os
from twisted.internet import reactor
from ctrader_open_api import Client, Protobuf, TcpProtocol, EndPoints
from ctrader_open_api.messages.OpenApiMessages_pb2 import (
    ProtoOAApplicationAuthReq, ProtoOAGetAccountListByAccessTokenReq)

# Demo host only. Read only: no order messages in this script.
client = Client(EndPoints.PROTOBUF_DEMO_HOST, EndPoints.PROTOBUF_PORT, TcpProtocol)

def on_accounts(message):
    res = Protobuf.extract(message)
    for acc in res.ctidTraderAccount:
        print(acc.ctidTraderAccountId, "live" if acc.isLive else "demo", acc.brokerTitleShort)
    reactor.stop()

def on_app_auth(_):
    req = ProtoOAGetAccountListByAccessTokenReq()
    req.accessToken = os.environ["CTRADER_ACCESS_TOKEN"]
    client.send(req).addCallbacks(on_accounts, on_error)

def on_error(failure):
    print("Error:", failure)
    reactor.stop()

def connected(_):
    req = ProtoOAApplicationAuthReq()
    req.clientId = os.environ["CTRADER_CLIENT_ID"]
    req.clientSecret = os.environ["CTRADER_CLIENT_SECRET"]
    client.send(req).addCallbacks(on_app_auth, on_error)

client.setConnectedCallback(connected)
client.startService()
reactor.run()
```

JavaScript:

```javascript
// The Open API runs over TCP or WebSocket with Protobuf or JSON messages,
// not REST. Use the Python tab (OpenApiPy) or Spotware's C# package.
```

curl:

```bash
# The Open API is not a REST API, so there is no curl call for this step.
# Use the Python tab.
```

Status: verified. Source: [help.ctrader.com](https://help.ctrader.com/open-api/account-authentication/), checked 2026-09-18.

### 7. Stay under the limits

Spotware allows 50 requests per second per connection, and 5 per second for historical data. Going over returns REQUEST_FREQUENCY_EXCEEDED (108).

Status: verified. Source: [help.ctrader.com](https://help.ctrader.com/open-api/), checked 2026-09-18.

## Sources

- Status: verified. Source: [cTrader Open API](https://help.ctrader.com/open-api/), checked 2026-09-18.
- Status: verified. Source: [Creating a new application](https://help.ctrader.com/open-api/creating-new-app/), checked 2026-09-18.
- Status: verified. Source: [Account authentication](https://help.ctrader.com/open-api/account-authentication/), checked 2026-09-18.
- Status: verified. Source: [Proxies and endpoints](https://help.ctrader.com/open-api/proxies-endpoints/), checked 2026-09-18.
- Status: verified. Source: [Messages](https://help.ctrader.com/open-api/messages/), checked 2026-09-18.
- Status: verified. Source: [Model messages](https://help.ctrader.com/open-api/model-messages/), checked 2026-09-18.
- Status: verified. Source: [GitHub: spotware/OpenApiPy](https://github.com/spotware/OpenApiPy), checked 2026-09-18.
- Status: verified. Source: [OpenApiPy docs](https://spotware.github.io/OpenApiPy/), checked 2026-09-18.
- Status: verified. Source: [OpenApiPy docs: authentication](https://spotware.github.io/OpenApiPy/authentication/), checked 2026-09-18.
- Status: verified. Source: [PyPI: ctrader-open-api](https://pypi.org/project/ctrader-open-api/), checked 2026-09-18.

## cTrader Open API limits to pace against

- Requests a second, not historical data: 50 requests per second
  - Scope: Per connection, requests that are not for historical data
  - Status: verified. Source: [help.ctrader.com](https://help.ctrader.com/open-api/), checked 2026-10-12.
  - Note: Historical data requests have their own lower limit, held in a separate record.
- Requests a second, historical data: 5 requests per second
  - Scope: Per connection, historical data requests only
  - Status: verified. Source: [help.ctrader.com](https://help.ctrader.com/open-api/), checked 2026-10-12.

## Next on the cTrader API

- [cTrader API error codes](https://openbrokerapi.com/errors/ctrader): 53 decoded, each with what it means, and the fix where the source gives one.
- [cTrader messages](https://openbrokerapi.com/platforms/ctrader/messages): 49 documented, each with its fields and source.
- [cTrader API page](https://openbrokerapi.com/platforms/ctrader): The full record: access, authentication, limits and the source for each.
- [cTrader Open API with Python](https://openbrokerapi.com/guides/ctrader-open-api-python): Guide

## Licence and how to cite

The records behind this page are all rights reserved. This file is the page itself, at its own address, in another format. It is not part of the CC BY 4.0 downloads listed at https://openbrokerapi.com/data. Quote from it with a link to the page.

Cite as: cTrader Open API Python quickstart. Broker API Hub, https://openbrokerapi.com/platforms/ctrader/quickstart, newest check 2026-09-18.

Where you rely on a single figure, cite the source and the checked date printed beside it as well. Where this page and a broker's own documentation differ, the documentation wins.
