3 releases
| new 0.1.2 | May 16, 2026 |
|---|---|
| 0.1.1 | Feb 10, 2026 |
| 0.1.0 | Feb 8, 2026 |
#857 in Authentication
59KB
1K
SLoC
ctrader-rs
Rust port of diegobernardes/ctrader — a strongly-typed, async client for the cTrader Open API.
Architecture
| Go module | Rust equivalent |
|---|---|
transportTCP |
src/transport.rs — async TLS TCP via tokio-native-tls |
Client struct |
src/client.rs — Client struct |
Command[A,B] |
Client::command::<Q,R>() generic method |
keepalive() goroutine |
Tokio task in client.rs |
Request registry (map[string]chan) |
HashMap<String, oneshot::Sender<ProtoMessage>> |
openapi/*.pb.go |
proto/*.proto → compiled by prost-build in build.rs |
Requirements
- Rust 1.75+
protocprotobuf compiler on$PATH
# macOS
brew install protobuf
# Ubuntu/Debian
apt install -y protobuf-compiler
Quick start
# 1. Clone / unzip the project
# 2. Fill in .env (credentials are already seeded from the Go project)
# 3. Run an example
cargo run --example get_accounts
cargo run --example symbols_list
Environment variables
| Variable | Description |
|---|---|
CTRADER_CLIENT_ID |
App client ID from openapi.ctrader.com |
CTRADER_SECRET |
App client secret |
CTRADER_TOKEN |
OAuth access token |
CTRADER_DEMO_ACCOUNT_ID |
Demo ctidTradingAccountId |
CTRADER_LIVE_ACCOUNT_ID |
Live ctidTradingAccountId |
Usage in your own code
use std::time::Duration;
use ctrader::client::{Client, Config};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
dotenvy::dotenv().ok();
let config = Config::new(
std::env::var("CTRADER_CLIENT_ID")?,
std::env::var("CTRADER_SECRET")?,
);
// Connect + authenticate application
let client = Client::start(config).await?;
// Get all accounts linked to your token
let token = std::env::var("CTRADER_TOKEN")?;
let res = client.get_accounts_by_access_token(&token).await?;
for acc in res.ctid_trader_account {
println!("{} — {}", acc.ctid_trader_account_id,
if acc.is_live.unwrap_or(false) { "live" } else { "demo" });
}
// Authenticate a specific account then list symbols
let account_id: i64 = std::env::var("CTRADER_DEMO_ACCOUNT_ID")?.parse()?;
client.account_auth(account_id, &token).await?;
let symbols = client.symbols_list(account_id, false).await?;
println!("Symbols: {}", symbols.symbol.len());
Ok(())
}
Listening to events
Pass an event handler to receive unsolicited messages (spot prices, execution events, …):
let client = Client::start_with_handler(config, Some(|msg| {
println!("event payloadType={:?}", msg.payload_type);
})).await?;
Adding more API calls
Every cTrader request follows the same pattern — add a method to Client in src/client.rs:
pub async fn my_request(&self, account_id: i64) -> Result<MyRes, Error> {
let req = MyReq {
payload_type: Some(payload::MY_REQ),
ctid_trader_account_id: account_id,
};
self.command(payload::MY_REQ, req, payload::MY_RES).await
}
Then add the corresponding message to proto/openapi.proto and build.rs will compile it automatically.
Dependencies
~15–27MB
~420K SLoC