ctrader-rs 0.1.2

Rust SDK for the cTrader Open API
Documentation

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.rsClient 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+
  • protoc protobuf 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.