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
impl Client
Sourcepub async fn account_logout(
&self,
ctid_trader_account_id: i64,
) -> Result<ProtoOaAccountLogoutRes, Error>
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).
Sourcepub async fn get_accounts_by_access_token(
&self,
access_token: &str,
) -> Result<ProtoOaGetAccountListByAccessTokenRes, Error>
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?
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}Sourcepub async fn get_trader(
&self,
ctid_trader_account_id: i64,
) -> Result<ProtoOaTraderRes, Error>
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?
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
impl Client
Sourcepub async fn asset_list(
&self,
ctid_trader_account_id: i64,
) -> Result<ProtoOaSymbolsListRes, Error>
pub async fn asset_list( &self, ctid_trader_account_id: i64, ) -> Result<ProtoOaSymbolsListRes, Error>
List all assets for the given account.
Mirrors ProtoOASymbolsListReq.
Sourcepub async fn asset_class_list(
&self,
ctid_trader_account_id: i64,
) -> Result<ProtoOaAssetClassListRes, Error>
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
impl Client
Sourcepub async fn application_auth(&self) -> Result<(), Error>
pub async fn application_auth(&self) -> Result<(), Error>
Application auth
Sourcepub async fn account_auth(
&self,
ctid_trader_account_id: i64,
access_token: &str,
) -> Result<ProtoOaAccountAuthRes, Error>
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?
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
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}Sourcepub async fn refresh_token(
&self,
refresh_token: &str,
) -> Result<ProtoOaRefreshTokenRes, Error>
pub async fn refresh_token( &self, refresh_token: &str, ) -> Result<ProtoOaRefreshTokenRes, Error>
Refresh an expired access token.
Source§impl Client
impl Client
Sourcepub async fn start(config: Config) -> Result<Self, Error>
pub async fn start(config: Config) -> Result<Self, Error>
Connect, authenticate the application, and start the keepalive task.
Examples found in repository?
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
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}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}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}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}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}Sourcepub async fn start_with_handler(
config: Config,
handler: Option<impl Fn(ProtoMessage) + Send + Sync + 'static>,
) -> Result<Self, Error>
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.
Sourcepub async fn command<Q, R>(
&self,
req_type: u32,
req: Q,
res_type: u32,
) -> Result<R, Error>
pub async fn command<Q, R>( &self, req_type: u32, req: Q, res_type: u32, ) -> Result<R, Error>
Encode req, send it, await the response envelope whose payloadType
matches res_type, and decode it as R.
Sourcepub async fn version(&self) -> Result<ProtoOaVersionRes, Error>
pub async fn version(&self) -> Result<ProtoOaVersionRes, Error>
Get the API version from the server.
Examples found in repository?
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
impl Client
Sourcepub async fn deal_list(
&self,
ctid_trader_account_id: i64,
from_timestamp: i64,
to_timestamp: i64,
max_rows: Option<i32>,
) -> Result<ProtoOaDealListRes, Error>
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.
Sourcepub 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>
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.
Sourcepub async fn deal_offset_list(
&self,
ctid_trader_account_id: i64,
deal_id: i64,
) -> Result<ProtoOaDealOffsetListRes, Error>
pub async fn deal_offset_list( &self, ctid_trader_account_id: i64, deal_id: i64, ) -> Result<ProtoOaDealOffsetListRes, Error>
Source§impl Client
impl Client
Sourcepub async fn get_margin_call_list(
&self,
ctid_trader_account_id: i64,
) -> Result<ProtoOaMarginCallListRes, Error>
pub async fn get_margin_call_list( &self, ctid_trader_account_id: i64, ) -> Result<ProtoOaMarginCallListRes, Error>
Get active margin calls for the account.
Sourcepub async fn get_expected_margin(
&self,
ctid_trader_account_id: i64,
symbol_id: i64,
volume: Vec<i64>,
) -> Result<ProtoOaExpectedMarginRes, Error>
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
impl Client
Sourcepub async fn get_cash_flow_history(
&self,
ctid_trader_account_id: i64,
from_timestamp: i64,
to_timestamp: i64,
) -> Result<ProtoOaCashFlowHistoryListRes, Error>
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.
Sourcepub async fn get_dynamic_leverage(
&self,
ctid_trader_account_id: i64,
leverage_id: i64,
) -> Result<ProtoOaGetDynamicLeverageByIdRes, Error>
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
impl Client
Sourcepub async fn new_market_order(
&self,
ctid_trader_account_id: i64,
symbol_id: i64,
trade_side: ProtoOaTradeSide,
volume: i64,
) -> Result<ProtoOaExecutionEvent, Error>
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?
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}Sourcepub 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>
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.
Sourcepub 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>
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).
Sourcepub 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>
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.
Sourcepub 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>
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.
Sourcepub 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>
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.
Sourcepub 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>
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.
Sourcepub async fn cancel_order(
&self,
ctid_trader_account_id: i64,
order_id: i64,
) -> Result<ProtoOaExecutionEvent, Error>
pub async fn cancel_order( &self, ctid_trader_account_id: i64, order_id: i64, ) -> Result<ProtoOaExecutionEvent, Error>
Cancel an existing pending order.
Sourcepub 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>
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.
Sourcepub async fn reconcile(
&self,
ctid_trader_account_id: i64,
return_protection_orders: bool,
) -> Result<ProtoOaReconcileRes, Error>
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.
Sourcepub async fn order_list(
&self,
ctid_trader_account_id: i64,
from_timestamp: Option<i64>,
to_timestamp: Option<i64>,
) -> Result<ProtoOaOrderListRes, Error>
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.
Sourcepub async fn order_details(
&self,
ctid_trader_account_id: i64,
order_id: i64,
) -> Result<ProtoOaOrderDetailsRes, Error>
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§impl Client
impl Client
Sourcepub async fn close_position(
&self,
ctid_trader_account_id: i64,
position_id: i64,
volume: i64,
) -> Result<ProtoOaExecutionEvent, Error>
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.
Sourcepub 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>
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.
Sourcepub async fn position_unrealized_pnl(
&self,
ctid_trader_account_id: i64,
) -> Result<ProtoOaGetPositionUnrealizedPnLRes, Error>
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?
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
impl Client
Sourcepub async fn symbols_list(
&self,
ctid_trader_account_id: i64,
include_archived: bool,
) -> Result<ProtoOaSymbolsListRes, Error>
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?
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}Sourcepub async fn subscribe_symbol(
&self,
symbol_id: Vec<i64>,
ctid_trader_account_id: i64,
) -> Result<ProtoOaSubscribeSpotsRes, Error>
pub async fn subscribe_symbol( &self, symbol_id: Vec<i64>, ctid_trader_account_id: i64, ) -> Result<ProtoOaSubscribeSpotsRes, Error>
Examples found in repository?
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}