Skip to main content

Client

Struct Client 

Source
pub struct Client {
    pub transport: Arc<Transport>,
    pub registry: Arc<Mutex<HashMap<String, Sender<ProtoMessage>>>>,
    pub config: Config,
    pub event_handler: Option<Arc<dyn Fn(ProtoMessage) + Send + Sync>>,
}
Expand description

The main client. Construct with Client::start.

Fields§

§transport: Arc<Transport>§registry: Arc<Mutex<HashMap<String, Sender<ProtoMessage>>>>§config: Config§event_handler: Option<Arc<dyn Fn(ProtoMessage) + Send + Sync>>

Called for every unsolicited event (spot, execution, …).

Implementations§

Source§

impl Client

Source

pub async fn account_logout( &self, ctid_trader_account_id: i64, ) -> Result<ProtoOaAccountLogoutRes, Error>

Log out a trader account (does not disconnect the TCP session).

Source

pub async fn get_accounts_by_access_token( &self, access_token: &str, ) -> Result<ProtoOaGetAccountListByAccessTokenRes, Error>

Return all trader accounts linked to the given OAuth access token.

Mirrors ProtoOAGetAccountListByAccessTokenReq.

Examples found in repository?
examples/get_accounts.rs (line 30)
11async fn main() -> Result<(), Box<dyn std::error::Error>> {
12    dotenvy::dotenv().ok();
13
14    tracing_subscriber::fmt()
15        .with_env_filter("get_accounts=debug,ctrader_rs=debug")
16        .with_line_number(true)
17        .init();
18
19    let client_id = std::env::var("CTRADER_CLIENT_ID")?;
20    let secret = std::env::var("CTRADER_SECRET")?;
21    let token = std::env::var("CTRADER_TOKEN")?;
22
23    let config = Config::new(client_id, secret).deadline(Duration::from_secs(5));
24
25    tracing::debug!("Connecting to demo.ctraderapi.com:5035 …");
26    let client = Client::start(config).await?;
27    tracing::debug!("✓ Connected and application authenticated");
28
29    // Fetch all accounts linked to the token
30    let res = client.get_accounts_by_access_token(&token).await?;
31
32    if res.ctid_trader_account.is_empty() {
33        tracing::debug!("No accounts found for this access token.");
34    } else {
35        tracing::debug!("\nFound {} account(s):\n", res.ctid_trader_account.len());
36        tracing::debug!(
37            "{:<25} {:<8} {:<15} {}",
38            "ctidTradingAccountId",
39            "Type",
40            "TraderLogin",
41            "Broker"
42        );
43        tracing::debug!("{}", "-".repeat(65));
44        for acc in &res.ctid_trader_account {
45            tracing::debug!(
46                "{:<25} {:<8} {:<15} {}",
47                acc.ctid_trader_account_id,
48                if acc.is_live.unwrap_or(false) {
49                    "live"
50                } else {
51                    "demo"
52                },
53                acc.trader_login.unwrap_or(0),
54                acc.broker_title_short.as_deref().unwrap_or(""),
55            );
56        }
57    }
58
59    Ok(())
60}
Source

pub async fn get_trader( &self, ctid_trader_account_id: i64, ) -> Result<ProtoOaTraderRes, Error>

Get full trader/account info (balance, leverage, currency, etc.).

Examples found in repository?
examples/get_trader.rs (line 28)
10async fn main() -> Result<(), Box<dyn std::error::Error>> {
11    dotenvy::dotenv().ok();
12
13    tracing_subscriber::fmt()
14        .with_env_filter("new_order=debug,ctrader_rs=debug")
15        .with_line_number(true)
16        .init();
17
18    let client_id = std::env::var("CTRADER_CLIENT_ID")?;
19    let secret = std::env::var("CTRADER_SECRET")?;
20    let account_id: i64 = std::env::var("CTRADER_ACCOUNT_ID")?.parse()?;
21
22    let config = Config::new(client_id, secret).deadline(Duration::from_secs(5));
23
24    tracing::debug!("Connecting to demo.ctraderapi.com:5035 …");
25    let client = Client::start(config).await?;
26    tracing::debug!("✓ Connected and application authenticated");
27
28    let res = client.get_trader(account_id).await?;
29
30    tracing::info!("Trader: {:?}", res);
31
32    Ok(())
33}
Source§

impl Client

Source

pub async fn asset_list( &self, ctid_trader_account_id: i64, ) -> Result<ProtoOaSymbolsListRes, Error>

List all assets for the given account.

Mirrors ProtoOASymbolsListReq.

Source

pub async fn asset_class_list( &self, ctid_trader_account_id: i64, ) -> Result<ProtoOaAssetClassListRes, Error>

List all symbols for the given account.

Mirrors ProtoOASymbolsListReq.

Source§

impl Client

Source

pub async fn application_auth(&self) -> Result<(), Error>

Application auth

Source

pub async fn account_auth( &self, ctid_trader_account_id: i64, access_token: &str, ) -> Result<ProtoOaAccountAuthRes, Error>

Authenticate a trader account. Must be called before any account-scoped request (symbols, deals, orders, …).

Mirrors ProtoOAAccountAuthReq in the Go integration test.

Examples found in repository?
examples/new_order.rs (line 30)
10async fn main() -> Result<(), Box<dyn std::error::Error>> {
11    dotenvy::dotenv().ok();
12
13    tracing_subscriber::fmt()
14        .with_env_filter("new_order=debug,ctrader_rs=debug")
15        .with_line_number(true)
16        .init();
17
18    let client_id = std::env::var("CTRADER_CLIENT_ID")?;
19    let secret = std::env::var("CTRADER_SECRET")?;
20    let token = std::env::var("CTRADER_TOKEN")?;
21    let account_id: i64 = std::env::var("CTRADER_ACCOUNT_ID")?.parse()?;
22
23    let config = Config::new(client_id, secret).deadline(Duration::from_secs(5));
24
25    tracing::debug!("Connecting to demo.ctraderapi.com:5035 …");
26    let client = Client::start(config).await?;
27    tracing::debug!("✓ Connected and application authenticated");
28
29    // Authenticate the account
30    let auth_res = client.account_auth(account_id, &token).await?;
31    assert_eq!(auth_res.ctid_trader_account_id, account_id);
32    tracing::debug!("✓ Account {account_id} authenticated");
33
34    let res = client
35        .new_market_order(account_id, 41, ProtoOaTradeSide::Buy, 100000)
36        .await?;
37
38    tracing::debug!("{:?}", res);
39
40    // let res = client
41    //     .new_limit_order(account_id, 41, ProtoOaTradeSide::Buy, 1000, 4800.00)
42    //     .await?;
43
44    // tracing::debug!("{:?}", res);
45
46    // let res = client
47    //     .new_stop_loss_take_profit_order(account_id, 41, ProtoOaTradeSide::Buy, 100_000, 500, 1000)
48    //     .await?;
49
50    // tracing::debug!("{:?}", res);
51
52    // let res = client
53    //     .new_market_range_order(account_id, 41, ProtoOaTradeSide::Buy, 1000)
54    //     .await?;
55
56    // tracing::debug!("{:?}", res);
57
58    loop {}
59}
More examples
Hide additional examples
examples/symbols_list.rs (line 31)
11async fn main() -> Result<(), Box<dyn std::error::Error>> {
12    dotenvy::dotenv().ok();
13
14    tracing_subscriber::fmt()
15        .with_env_filter("symbols_list=debug,ctrader_rs=debug")
16        .with_line_number(true)
17        .init();
18
19    let client_id = std::env::var("CTRADER_CLIENT_ID")?;
20    let secret = std::env::var("CTRADER_SECRET")?;
21    let token = std::env::var("CTRADER_TOKEN")?;
22    let account_id: i64 = std::env::var("CTRADER_ACCOUNT_ID")?.parse()?;
23
24    let config = Config::new(client_id, secret).deadline(Duration::from_secs(5));
25
26    println!("Connecting …");
27    let client = Client::start(config).await?;
28    println!("✓ Connected");
29
30    // Authenticate the account
31    let auth_res = client.account_auth(account_id, &token).await?;
32    assert_eq!(auth_res.ctid_trader_account_id, account_id);
33    println!("✓ Account {account_id} authenticated");
34
35    // Fetch symbol list
36    let res = client.symbols_list(account_id, false).await?;
37    println!("\nTotal symbols: {}", res.symbol.len());
38
39    // Verify XAUUSD is present (same assertion as the Go test)
40    let xauusd = res
41        .symbol
42        .iter()
43        .find(|s| s.symbol_name.as_deref() == Some("XAUUSD"));
44
45    match xauusd {
46        Some(sym) => println!(
47            "✓ XAUUSD found  (id={}, enabled={})",
48            sym.symbol_id,
49            sym.enabled.unwrap_or(false)
50        ),
51        None => println!("✗ XAUUSD NOT found in symbol list"),
52    }
53
54    // Print first 10 symbols
55    println!("\nFirst 10 symbols:");
56    println!("{:<10} {:<15} {}", "ID", "Name", "Enabled");
57    println!("{}", "-".repeat(35));
58    for sym in res.symbol.iter().take(10) {
59        println!(
60            "{:<10} {:<15} {}",
61            sym.symbol_id,
62            sym.symbol_name.as_deref().unwrap_or(""),
63            sym.enabled.unwrap_or(false),
64        );
65    }
66
67    Ok(())
68}
Source

pub async fn refresh_token( &self, refresh_token: &str, ) -> Result<ProtoOaRefreshTokenRes, Error>

Refresh an expired access token.

Source§

impl Client

Source

pub async fn start(config: Config) -> Result<Self, Error>

Connect, authenticate the application, and start the keepalive task.

Examples found in repository?
examples/version.rs (line 25)
11async fn main() -> Result<(), Box<dyn std::error::Error>> {
12    dotenvy::dotenv().ok();
13
14    tracing_subscriber::fmt()
15        .with_env_filter("version=debug,ctrader_rs=debug")
16        .with_line_number(true)
17        .init();
18
19    let client_id = std::env::var("CTRADER_CLIENT_ID")?;
20    let secret = std::env::var("CTRADER_SECRET")?;
21
22    let config = Config::new(client_id, secret).deadline(Duration::from_secs(5));
23
24    tracing::debug!("Connecting to demo.ctraderapi.com:5035 …");
25    let client = Client::start(config).await?;
26    tracing::debug!("✓ Connected and application authenticated");
27
28    // Fetch all accounts linked to the token
29    let res = client.version().await?;
30
31    tracing::debug!("Version: {}", res.version);
32
33    Ok(())
34}
More examples
Hide additional examples
examples/get_trader.rs (line 25)
10async fn main() -> Result<(), Box<dyn std::error::Error>> {
11    dotenvy::dotenv().ok();
12
13    tracing_subscriber::fmt()
14        .with_env_filter("new_order=debug,ctrader_rs=debug")
15        .with_line_number(true)
16        .init();
17
18    let client_id = std::env::var("CTRADER_CLIENT_ID")?;
19    let secret = std::env::var("CTRADER_SECRET")?;
20    let account_id: i64 = std::env::var("CTRADER_ACCOUNT_ID")?.parse()?;
21
22    let config = Config::new(client_id, secret).deadline(Duration::from_secs(5));
23
24    tracing::debug!("Connecting to demo.ctraderapi.com:5035 …");
25    let client = Client::start(config).await?;
26    tracing::debug!("✓ Connected and application authenticated");
27
28    let res = client.get_trader(account_id).await?;
29
30    tracing::info!("Trader: {:?}", res);
31
32    Ok(())
33}
examples/get_position_unrealized_pnl.rs (line 25)
10async fn main() -> Result<(), Box<dyn std::error::Error>> {
11    dotenvy::dotenv().ok();
12
13    tracing_subscriber::fmt()
14        .with_env_filter("new_order=debug,ctrader_rs=debug")
15        .with_line_number(true)
16        .init();
17
18    let client_id = std::env::var("CTRADER_CLIENT_ID")?;
19    let secret = std::env::var("CTRADER_SECRET")?;
20    let account_id: i64 = std::env::var("CTRADER_ACCOUNT_ID")?.parse()?;
21
22    let config = Config::new(client_id, secret).deadline(Duration::from_secs(5));
23
24    tracing::debug!("Connecting to demo.ctraderapi.com:5035 …");
25    let client = Client::start(config).await?;
26    tracing::debug!("✓ Connected and application authenticated");
27
28    let res = client.position_unrealized_pnl(account_id).await?;
29
30    tracing::info!("Position Unrealized PnL: {:?}", res);
31
32    Ok(())
33}
examples/subscribe.rs (line 26)
11async fn main() -> Result<(), Box<dyn std::error::Error>> {
12    dotenvy::dotenv().ok();
13
14    tracing_subscriber::fmt()
15        .with_env_filter("get_accounts=debug,ctrader_rs=debug")
16        .with_line_number(true)
17        .init();
18
19    let client_id = std::env::var("CTRADER_CLIENT_ID")?;
20    let secret = std::env::var("CTRADER_SECRET")?;
21    let account_id = std::env::var("CTRADER_ACCOUNT_ID")?.parse::<i64>()?;
22
23    let config = Config::new(client_id, secret).deadline(Duration::from_secs(5));
24
25    tracing::debug!("Connecting to demo.ctraderapi.com:5035 …");
26    let client = Client::start(config).await?;
27    tracing::debug!("✓ Connected and application authenticated");
28
29    // Fetch all accounts linked to the token
30    let res = client.subscribe_symbol(vec![61], account_id).await?;
31
32    println!("{:?}", res);
33
34    Ok(())
35}
examples/new_order.rs (line 26)
10async fn main() -> Result<(), Box<dyn std::error::Error>> {
11    dotenvy::dotenv().ok();
12
13    tracing_subscriber::fmt()
14        .with_env_filter("new_order=debug,ctrader_rs=debug")
15        .with_line_number(true)
16        .init();
17
18    let client_id = std::env::var("CTRADER_CLIENT_ID")?;
19    let secret = std::env::var("CTRADER_SECRET")?;
20    let token = std::env::var("CTRADER_TOKEN")?;
21    let account_id: i64 = std::env::var("CTRADER_ACCOUNT_ID")?.parse()?;
22
23    let config = Config::new(client_id, secret).deadline(Duration::from_secs(5));
24
25    tracing::debug!("Connecting to demo.ctraderapi.com:5035 …");
26    let client = Client::start(config).await?;
27    tracing::debug!("✓ Connected and application authenticated");
28
29    // Authenticate the account
30    let auth_res = client.account_auth(account_id, &token).await?;
31    assert_eq!(auth_res.ctid_trader_account_id, account_id);
32    tracing::debug!("✓ Account {account_id} authenticated");
33
34    let res = client
35        .new_market_order(account_id, 41, ProtoOaTradeSide::Buy, 100000)
36        .await?;
37
38    tracing::debug!("{:?}", res);
39
40    // let res = client
41    //     .new_limit_order(account_id, 41, ProtoOaTradeSide::Buy, 1000, 4800.00)
42    //     .await?;
43
44    // tracing::debug!("{:?}", res);
45
46    // let res = client
47    //     .new_stop_loss_take_profit_order(account_id, 41, ProtoOaTradeSide::Buy, 100_000, 500, 1000)
48    //     .await?;
49
50    // tracing::debug!("{:?}", res);
51
52    // let res = client
53    //     .new_market_range_order(account_id, 41, ProtoOaTradeSide::Buy, 1000)
54    //     .await?;
55
56    // tracing::debug!("{:?}", res);
57
58    loop {}
59}
examples/get_accounts.rs (line 26)
11async fn main() -> Result<(), Box<dyn std::error::Error>> {
12    dotenvy::dotenv().ok();
13
14    tracing_subscriber::fmt()
15        .with_env_filter("get_accounts=debug,ctrader_rs=debug")
16        .with_line_number(true)
17        .init();
18
19    let client_id = std::env::var("CTRADER_CLIENT_ID")?;
20    let secret = std::env::var("CTRADER_SECRET")?;
21    let token = std::env::var("CTRADER_TOKEN")?;
22
23    let config = Config::new(client_id, secret).deadline(Duration::from_secs(5));
24
25    tracing::debug!("Connecting to demo.ctraderapi.com:5035 …");
26    let client = Client::start(config).await?;
27    tracing::debug!("✓ Connected and application authenticated");
28
29    // Fetch all accounts linked to the token
30    let res = client.get_accounts_by_access_token(&token).await?;
31
32    if res.ctid_trader_account.is_empty() {
33        tracing::debug!("No accounts found for this access token.");
34    } else {
35        tracing::debug!("\nFound {} account(s):\n", res.ctid_trader_account.len());
36        tracing::debug!(
37            "{:<25} {:<8} {:<15} {}",
38            "ctidTradingAccountId",
39            "Type",
40            "TraderLogin",
41            "Broker"
42        );
43        tracing::debug!("{}", "-".repeat(65));
44        for acc in &res.ctid_trader_account {
45            tracing::debug!(
46                "{:<25} {:<8} {:<15} {}",
47                acc.ctid_trader_account_id,
48                if acc.is_live.unwrap_or(false) {
49                    "live"
50                } else {
51                    "demo"
52                },
53                acc.trader_login.unwrap_or(0),
54                acc.broker_title_short.as_deref().unwrap_or(""),
55            );
56        }
57    }
58
59    Ok(())
60}
Source

pub async fn start_with_handler( config: Config, handler: Option<impl Fn(ProtoMessage) + Send + Sync + 'static>, ) -> Result<Self, Error>

Same as [start] but with an event handler for unsolicited messages.

Source

pub async fn command<Q, R>( &self, req_type: u32, req: Q, res_type: u32, ) -> Result<R, Error>
where Q: Message, R: Message + Default,

Encode req, send it, await the response envelope whose payloadType matches res_type, and decode it as R.

Source

pub async fn version(&self) -> Result<ProtoOaVersionRes, Error>

Get the API version from the server.

Examples found in repository?
examples/version.rs (line 29)
11async fn main() -> Result<(), Box<dyn std::error::Error>> {
12    dotenvy::dotenv().ok();
13
14    tracing_subscriber::fmt()
15        .with_env_filter("version=debug,ctrader_rs=debug")
16        .with_line_number(true)
17        .init();
18
19    let client_id = std::env::var("CTRADER_CLIENT_ID")?;
20    let secret = std::env::var("CTRADER_SECRET")?;
21
22    let config = Config::new(client_id, secret).deadline(Duration::from_secs(5));
23
24    tracing::debug!("Connecting to demo.ctraderapi.com:5035 …");
25    let client = Client::start(config).await?;
26    tracing::debug!("✓ Connected and application authenticated");
27
28    // Fetch all accounts linked to the token
29    let res = client.version().await?;
30
31    tracing::debug!("Version: {}", res.version);
32
33    Ok(())
34}
Source§

impl Client

Source

pub async fn deal_list( &self, ctid_trader_account_id: i64, from_timestamp: i64, to_timestamp: i64, max_rows: Option<i32>, ) -> Result<ProtoOaDealListRes, Error>

List deals (filled order history) filtered by time range.

Timestamps are Unix milliseconds. max_rows caps the result set.

Source

pub async fn deal_list_by_position( &self, ctid_trader_account_id: i64, position_id: i64, from_timestamp: Option<i64>, to_timestamp: Option<i64>, ) -> Result<ProtoOaDealListByPositionIdRes, Error>

List deals associated with a specific position.

Source

pub async fn deal_offset_list( &self, ctid_trader_account_id: i64, deal_id: i64, ) -> Result<ProtoOaDealOffsetListRes, Error>

Source§

impl Client

Source

pub async fn get_margin_call_list( &self, ctid_trader_account_id: i64, ) -> Result<ProtoOaMarginCallListRes, Error>

Get active margin calls for the account.

Source

pub async fn get_expected_margin( &self, ctid_trader_account_id: i64, symbol_id: i64, volume: Vec<i64>, ) -> Result<ProtoOaExpectedMarginRes, Error>

Calculate expected margin for a list of volumes on a symbol.

Useful for pre-trade checks before placing an order. Note: moneyDigits in the response specifies the monetary scale factor.

Source§

impl Client

Source

pub async fn get_cash_flow_history( &self, ctid_trader_account_id: i64, from_timestamp: i64, to_timestamp: i64, ) -> Result<ProtoOaCashFlowHistoryListRes, Error>

Get cash flow history (deposits, withdrawals) for a time range.

Max range: 1 week (604 800 000 ms). Timestamps in Unix milliseconds.

Source

pub async fn get_dynamic_leverage( &self, ctid_trader_account_id: i64, leverage_id: i64, ) -> Result<ProtoOaGetDynamicLeverageByIdRes, Error>

Get leverage details for a given leverage ID.

Source§

impl Client

Source

pub async fn new_market_order( &self, ctid_trader_account_id: i64, symbol_id: i64, trade_side: ProtoOaTradeSide, volume: i64, ) -> Result<ProtoOaExecutionEvent, Error>

Place a market order (immediate fill at best available price).

volume is in units of 0.01 lots: 100 = 0.01 lot, 100_000 = 1 lot.

Examples found in repository?
examples/new_order.rs (line 35)
10async fn main() -> Result<(), Box<dyn std::error::Error>> {
11    dotenvy::dotenv().ok();
12
13    tracing_subscriber::fmt()
14        .with_env_filter("new_order=debug,ctrader_rs=debug")
15        .with_line_number(true)
16        .init();
17
18    let client_id = std::env::var("CTRADER_CLIENT_ID")?;
19    let secret = std::env::var("CTRADER_SECRET")?;
20    let token = std::env::var("CTRADER_TOKEN")?;
21    let account_id: i64 = std::env::var("CTRADER_ACCOUNT_ID")?.parse()?;
22
23    let config = Config::new(client_id, secret).deadline(Duration::from_secs(5));
24
25    tracing::debug!("Connecting to demo.ctraderapi.com:5035 …");
26    let client = Client::start(config).await?;
27    tracing::debug!("✓ Connected and application authenticated");
28
29    // Authenticate the account
30    let auth_res = client.account_auth(account_id, &token).await?;
31    assert_eq!(auth_res.ctid_trader_account_id, account_id);
32    tracing::debug!("✓ Account {account_id} authenticated");
33
34    let res = client
35        .new_market_order(account_id, 41, ProtoOaTradeSide::Buy, 100000)
36        .await?;
37
38    tracing::debug!("{:?}", res);
39
40    // let res = client
41    //     .new_limit_order(account_id, 41, ProtoOaTradeSide::Buy, 1000, 4800.00)
42    //     .await?;
43
44    // tracing::debug!("{:?}", res);
45
46    // let res = client
47    //     .new_stop_loss_take_profit_order(account_id, 41, ProtoOaTradeSide::Buy, 100_000, 500, 1000)
48    //     .await?;
49
50    // tracing::debug!("{:?}", res);
51
52    // let res = client
53    //     .new_market_range_order(account_id, 41, ProtoOaTradeSide::Buy, 1000)
54    //     .await?;
55
56    // tracing::debug!("{:?}", res);
57
58    loop {}
59}
Source

pub async fn new_market_order_with_sltp( &self, ctid_trader_account_id: i64, symbol_id: i64, trade_side: ProtoOaTradeSide, volume: i64, relative_stop_loss: i64, relative_take_profit: i64, ) -> Result<ProtoOaExecutionEvent, Error>

Place a market order with relative SL/TP (distance from fill price).

relative_stop_loss and relative_take_profit are in 1/100000 of a price unit. 1 pip on a 5-decimal pair = 10 points = 1000 in protocol.

For a BUY: SL = fillPrice − relSL, TP = fillPrice + relTP For a SELL: SL = fillPrice + relSL, TP = fillPrice − relTP

Helper: pips_to_points(n) converts pip count → protocol value.

Source

pub async fn new_market_order_with_trailing_sl( &self, ctid_trader_account_id: i64, symbol_id: i64, trade_side: ProtoOaTradeSide, volume: i64, relative_stop_loss: i64, ) -> Result<ProtoOaExecutionEvent, Error>

Market order with trailing stop loss (relative distance).

Source

pub async fn new_market_range_order( &self, ctid_trader_account_id: i64, symbol_id: i64, trade_side: ProtoOaTradeSide, volume: i64, base_slippage_price: f64, slippage_in_points: i32, ) -> Result<ProtoOaExecutionEvent, Error>

Market range order — fills within a slippage band around base_price.

slippage_in_points is the maximum allowed deviation in points.

Source

pub async fn new_limit_order( &self, ctid_trader_account_id: i64, symbol_id: i64, trade_side: ProtoOaTradeSide, volume: i64, limit_price: f64, stop_loss: Option<f64>, take_profit: Option<f64>, ) -> Result<ProtoOaExecutionEvent, Error>

Place a limit order (fill when price reaches limit_price or better).

stop_loss and take_profit are absolute price levels. Leave as None to omit them.

Source

pub async fn new_stop_order( &self, ctid_trader_account_id: i64, symbol_id: i64, trade_side: ProtoOaTradeSide, volume: i64, stop_price: f64, stop_loss: Option<f64>, take_profit: Option<f64>, ) -> Result<ProtoOaExecutionEvent, Error>

Place a stop order (fill when price breaks through stop_price).

stop_loss and take_profit are absolute price levels.

Source

pub async fn new_stop_limit_order( &self, ctid_trader_account_id: i64, symbol_id: i64, trade_side: ProtoOaTradeSide, volume: i64, stop_price: f64, slippage_in_points: i32, stop_loss: Option<f64>, take_profit: Option<f64>, ) -> Result<ProtoOaExecutionEvent, Error>

Place a stop-limit order (pending stop that becomes a limit on trigger).

stop_price — price level that triggers the order. slippage_in_points — max deviation from stop price for the limit fill.

Source

pub async fn cancel_order( &self, ctid_trader_account_id: i64, order_id: i64, ) -> Result<ProtoOaExecutionEvent, Error>

Cancel an existing pending order.

Source

pub async fn amend_order( &self, ctid_trader_account_id: i64, order_id: i64, volume: Option<i64>, limit_price: Option<f64>, stop_price: Option<f64>, stop_loss: Option<f64>, take_profit: Option<f64>, trailing_stop_loss: Option<bool>, expiration_timestamp: Option<i64>, ) -> Result<ProtoOaExecutionEvent, Error>

Amend an existing pending order.

Only supply the fields you want to change — all are optional except ctid_trader_account_id and order_id.

Source

pub async fn reconcile( &self, ctid_trader_account_id: i64, return_protection_orders: bool, ) -> Result<ProtoOaReconcileRes, Error>

Get open positions and pending orders (current state snapshot).

Set return_protection_orders = true to receive SL/TP as separate orders; otherwise they appear as fields on the position.

Source

pub async fn order_list( &self, ctid_trader_account_id: i64, from_timestamp: Option<i64>, to_timestamp: Option<i64>, ) -> Result<ProtoOaOrderListRes, Error>

List orders filtered by time range.

Source

pub async fn order_details( &self, ctid_trader_account_id: i64, order_id: i64, ) -> Result<ProtoOaOrderDetailsRes, Error>

Get full details for a single order by ID.

Source

pub async fn get_order_list_by_position( &self, ctid_trader_account_id: i64, position_id: i64, from_timestamp: Option<i64>, to_timestamp: Option<i64>, ) -> Result<ProtoOaOrderListByPositionIdRes, Error>

List orders associated with a specific position.

Source§

impl Client

Source

pub async fn close_position( &self, ctid_trader_account_id: i64, position_id: i64, volume: i64, ) -> Result<ProtoOaExecutionEvent, Error>

Close an open position, either fully or partially.

To close fully, pass the full position volume.

Source

pub async fn amend_position_sltp( &self, ctid_trader_account_id: i64, position_id: i64, stop_loss: Option<f64>, take_profit: Option<f64>, trailing_stop_loss: Option<bool>, ) -> Result<ProtoOaExecutionEvent, Error>

Amend the Stop Loss and/or Take Profit of an open position.

stop_loss and take_profit are absolute price levels.

Source

pub async fn position_unrealized_pnl( &self, ctid_trader_account_id: i64, ) -> Result<ProtoOaGetPositionUnrealizedPnLRes, Error>

Get unrealized P&L for all open positions.

Note: monetary values in the response are scaled by 10^moneyDigits.

Examples found in repository?
examples/get_position_unrealized_pnl.rs (line 28)
10async fn main() -> Result<(), Box<dyn std::error::Error>> {
11    dotenvy::dotenv().ok();
12
13    tracing_subscriber::fmt()
14        .with_env_filter("new_order=debug,ctrader_rs=debug")
15        .with_line_number(true)
16        .init();
17
18    let client_id = std::env::var("CTRADER_CLIENT_ID")?;
19    let secret = std::env::var("CTRADER_SECRET")?;
20    let account_id: i64 = std::env::var("CTRADER_ACCOUNT_ID")?.parse()?;
21
22    let config = Config::new(client_id, secret).deadline(Duration::from_secs(5));
23
24    tracing::debug!("Connecting to demo.ctraderapi.com:5035 …");
25    let client = Client::start(config).await?;
26    tracing::debug!("✓ Connected and application authenticated");
27
28    let res = client.position_unrealized_pnl(account_id).await?;
29
30    tracing::info!("Position Unrealized PnL: {:?}", res);
31
32    Ok(())
33}
Source§

impl Client

Source

pub async fn symbols_list( &self, ctid_trader_account_id: i64, include_archived: bool, ) -> Result<ProtoOaSymbolsListRes, Error>

List all symbols for the given account.

Mirrors ProtoOASymbolsListReq.

Examples found in repository?
examples/symbols_list.rs (line 36)
11async fn main() -> Result<(), Box<dyn std::error::Error>> {
12    dotenvy::dotenv().ok();
13
14    tracing_subscriber::fmt()
15        .with_env_filter("symbols_list=debug,ctrader_rs=debug")
16        .with_line_number(true)
17        .init();
18
19    let client_id = std::env::var("CTRADER_CLIENT_ID")?;
20    let secret = std::env::var("CTRADER_SECRET")?;
21    let token = std::env::var("CTRADER_TOKEN")?;
22    let account_id: i64 = std::env::var("CTRADER_ACCOUNT_ID")?.parse()?;
23
24    let config = Config::new(client_id, secret).deadline(Duration::from_secs(5));
25
26    println!("Connecting …");
27    let client = Client::start(config).await?;
28    println!("✓ Connected");
29
30    // Authenticate the account
31    let auth_res = client.account_auth(account_id, &token).await?;
32    assert_eq!(auth_res.ctid_trader_account_id, account_id);
33    println!("✓ Account {account_id} authenticated");
34
35    // Fetch symbol list
36    let res = client.symbols_list(account_id, false).await?;
37    println!("\nTotal symbols: {}", res.symbol.len());
38
39    // Verify XAUUSD is present (same assertion as the Go test)
40    let xauusd = res
41        .symbol
42        .iter()
43        .find(|s| s.symbol_name.as_deref() == Some("XAUUSD"));
44
45    match xauusd {
46        Some(sym) => println!(
47            "✓ XAUUSD found  (id={}, enabled={})",
48            sym.symbol_id,
49            sym.enabled.unwrap_or(false)
50        ),
51        None => println!("✗ XAUUSD NOT found in symbol list"),
52    }
53
54    // Print first 10 symbols
55    println!("\nFirst 10 symbols:");
56    println!("{:<10} {:<15} {}", "ID", "Name", "Enabled");
57    println!("{}", "-".repeat(35));
58    for sym in res.symbol.iter().take(10) {
59        println!(
60            "{:<10} {:<15} {}",
61            sym.symbol_id,
62            sym.symbol_name.as_deref().unwrap_or(""),
63            sym.enabled.unwrap_or(false),
64        );
65    }
66
67    Ok(())
68}
Source

pub async fn subscribe_symbol( &self, symbol_id: Vec<i64>, ctid_trader_account_id: i64, ) -> Result<ProtoOaSubscribeSpotsRes, Error>

Examples found in repository?
examples/subscribe.rs (line 30)
11async fn main() -> Result<(), Box<dyn std::error::Error>> {
12    dotenvy::dotenv().ok();
13
14    tracing_subscriber::fmt()
15        .with_env_filter("get_accounts=debug,ctrader_rs=debug")
16        .with_line_number(true)
17        .init();
18
19    let client_id = std::env::var("CTRADER_CLIENT_ID")?;
20    let secret = std::env::var("CTRADER_SECRET")?;
21    let account_id = std::env::var("CTRADER_ACCOUNT_ID")?.parse::<i64>()?;
22
23    let config = Config::new(client_id, secret).deadline(Duration::from_secs(5));
24
25    tracing::debug!("Connecting to demo.ctraderapi.com:5035 …");
26    let client = Client::start(config).await?;
27    tracing::debug!("✓ Connected and application authenticated");
28
29    // Fetch all accounts linked to the token
30    let res = client.subscribe_symbol(vec![61], account_id).await?;
31
32    println!("{:?}", res);
33
34    Ok(())
35}
Source

pub async fn symbol_by_id( &self, symbol_id: Vec<i64>, ctid_trader_account_id: i64, ) -> Result<ProtoOaSymbolByIdReq, Error>

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more