pub struct Client { /* private fields */ }Expand description
An asynchronous OANDA v20 API client.
The client is cheap to clone (all clones share one connection pool and
one rate limiter) and is Send + Sync, so a single instance can be
shared freely between concurrent tokio tasks:
use oanda_rs::{Client, Environment};
let client = Client::new(Environment::Practice, "my-token");
let for_task = client.clone(); // shares pool + rate limiterRate limiting is built in and enabled by default (100 REST requests/s,
2 stream connections/s — under OANDA’s 120/s and 2/s caps). See
Client::builder for tuning.
Implementations§
Source§impl Client
impl Client
Sourcepub fn new(environment: Environment, token: impl Into<String>) -> Client
pub fn new(environment: Environment, token: impl Into<String>) -> Client
Creates a client for environment authenticating with the given
personal access token, using default settings.
Use Client::builder to customize the datetime format, rate
limits, or the underlying HTTP client.
§Panics
Panics if the system TLS backend cannot be initialized (same
condition as reqwest::Client::new).
Sourcepub fn builder() -> ClientBuilder
pub fn builder() -> ClientBuilder
Starts building a client with custom configuration.
Sourcepub fn datetime_format(&self) -> AcceptDatetimeFormat
pub fn datetime_format(&self) -> AcceptDatetimeFormat
The datetime wire format this client requests via the
Accept-Datetime-Format header.
Source§impl Client
impl Client
Sourcepub async fn account(
&self,
account_id: impl Into<AccountId>,
) -> Result<AccountResponse, Error>
pub async fn account( &self, account_id: impl Into<AccountId>, ) -> Result<AccountResponse, Error>
Get the full details for a single account, including a full list of its open trades, open positions, and pending orders.
GET /v3/accounts/{accountID}
Sourcepub fn account_changes(
&self,
account_id: impl Into<AccountId>,
) -> AccountChangesRequest
pub fn account_changes( &self, account_id: impl Into<AccountId>, ) -> AccountChangesRequest
Poll an account for its current state and changes since a specified transaction ID.
This is OANDA’s recommended pattern for tracking account state:
fetch Client::account once, then poll this endpoint with the
last seen transaction ID and apply the returned
AccountChanges to your snapshot.
GET /v3/accounts/{accountID}/changes
Sourcepub async fn list_accounts(&self) -> Result<ListAccountsResponse, Error>
pub async fn list_accounts(&self) -> Result<ListAccountsResponse, Error>
Get a list of all accounts authorized for the provided token.
GET /v3/accounts
§Examples
for account in client.list_accounts().await?.accounts {
println!("{:?}", account.id);
}Sourcepub async fn account_summary(
&self,
account_id: impl Into<AccountId>,
) -> Result<AccountSummaryResponse, Error>
pub async fn account_summary( &self, account_id: impl Into<AccountId>, ) -> Result<AccountSummaryResponse, Error>
Get a summary for a single account.
GET /v3/accounts/{accountID}/summary
§Examples
let summary = client.account_summary("101-004-1234567-001").await?.account;
println!("balance: {:?}", summary.balance);Sourcepub fn account_instruments(
&self,
account_id: impl Into<AccountId>,
) -> AccountInstrumentsRequest
pub fn account_instruments( &self, account_id: impl Into<AccountId>, ) -> AccountInstrumentsRequest
Get the list of tradeable instruments for the given account. The list of tradeable instruments is dependent on the regulatory division that the account is located in.
GET /v3/accounts/{accountID}/instruments
§Examples
use oanda_rs::models::InstrumentName;
// All instruments:
let all = client.account_instruments("101-004-1234567-001").send().await?;
// Or a specific subset:
let some = client
.account_instruments("101-004-1234567-001")
.instruments([InstrumentName::EurUsd, InstrumentName::XauUsd])
.send()
.await?;Sourcepub fn configure_account(
&self,
account_id: impl Into<AccountId>,
) -> ConfigureAccountRequest
pub fn configure_account( &self, account_id: impl Into<AccountId>, ) -> ConfigureAccountRequest
Set client-configurable properties of the account: its alias and margin rate.
PATCH /v3/accounts/{accountID}/configuration
§Errors
Rejections (HTTP 400/403) carry a
ClientConfigureRejectTransaction; recover it with
ApiErrorBody::details::<ConfigureAccountRejectBody>.
§Examples
use oanda_rs::models::DecimalNumber;
client
.configure_account("101-004-1234567-001")
.alias("my-strategy-account")
.margin_rate("0.02".parse::<DecimalNumber>().unwrap())
.send()
.await?;Source§impl Client
impl Client
Sourcepub fn candles(&self, instrument: impl Into<InstrumentName>) -> CandlesRequest
pub fn candles(&self, instrument: impl Into<InstrumentName>) -> CandlesRequest
Fetch candlestick data for an instrument.
GET /v3/instruments/{instrument}/candles
§Examples
use oanda_rs::models::CandlestickGranularity;
let candles = client
.candles("EUR_USD")
.granularity(CandlestickGranularity::H1)
.count(500)
.send()
.await?;
println!("got {} candles", candles.candles.len());Sourcepub fn account_candles(
&self,
account_id: impl Into<AccountId>,
instrument: impl Into<InstrumentName>,
) -> CandlesRequest
pub fn account_candles( &self, account_id: impl Into<AccountId>, instrument: impl Into<InstrumentName>, ) -> CandlesRequest
Fetch candlestick data for an instrument, scoped to an account: the
data matches what the account would see, and volume-weighted average
prices can be requested via
units.
GET /v3/accounts/{accountID}/instruments/{instrument}/candles
Sourcepub fn latest_candles(
&self,
account_id: impl Into<AccountId>,
specifications: impl IntoIterator<Item = CandleSpecification>,
) -> LatestCandlesRequest
pub fn latest_candles( &self, account_id: impl Into<AccountId>, specifications: impl IntoIterator<Item = CandleSpecification>, ) -> LatestCandlesRequest
Get the most recently completed candles within an account for the specified combinations of instrument, granularity, and price component.
GET /v3/accounts/{accountID}/candles/latest
§Examples
use oanda_rs::models::{CandleSpecification, CandlestickGranularity, PricingComponent};
let latest = client
.latest_candles(
"101-004-1234567-001",
[CandleSpecification::new("EUR_USD", CandlestickGranularity::S10)
.price(PricingComponent::BID.with_mid())],
)
.send()
.await?;Sourcepub fn instrument_order_book(
&self,
instrument: impl Into<InstrumentName>,
) -> OrderBookRequest
pub fn instrument_order_book( &self, instrument: impl Into<InstrumentName>, ) -> OrderBookRequest
Fetch an order book for an instrument.
GET /v3/instruments/{instrument}/orderBook
Sourcepub fn instrument_position_book(
&self,
instrument: impl Into<InstrumentName>,
) -> PositionBookRequest
pub fn instrument_position_book( &self, instrument: impl Into<InstrumentName>, ) -> PositionBookRequest
Fetch a position book for an instrument.
GET /v3/instruments/{instrument}/positionBook
Source§impl Client
impl Client
Sourcepub async fn create_order(
&self,
account_id: impl Into<AccountId>,
order: impl Into<OrderRequest>,
) -> Result<CreateOrderResponse, Error>
pub async fn create_order( &self, account_id: impl Into<AccountId>, order: impl Into<OrderRequest>, ) -> Result<CreateOrderResponse, Error>
Create an order for an account.
POST /v3/accounts/{accountID}/orders
§Errors
Rejections (HTTP 400/404) carry an orderRejectTransaction; recover
it with
ApiErrorBody::details::<CreateOrderRejectBody>.
§Examples
use oanda_rs::models::{MarketOrderRequest, StopLossDetails, TakeProfitDetails};
let response = client
.create_order(
"101-004-1234567-001",
MarketOrderRequest::new("EUR_USD", 100)
.take_profit_on_fill(TakeProfitDetails::at_price("1.1050".parse().unwrap()))
.stop_loss_on_fill(StopLossDetails::at_distance("0.0050".parse().unwrap())),
)
.await?;
println!("created: {:?}", response.order_create_transaction.id());Sourcepub fn list_orders(&self, account_id: impl Into<AccountId>) -> ListOrdersRequest
pub fn list_orders(&self, account_id: impl Into<AccountId>) -> ListOrdersRequest
Get a list of orders for an account.
GET /v3/accounts/{accountID}/orders
Sourcepub async fn list_pending_orders(
&self,
account_id: impl Into<AccountId>,
) -> Result<ListOrdersResponse, Error>
pub async fn list_pending_orders( &self, account_id: impl Into<AccountId>, ) -> Result<ListOrdersResponse, Error>
List all pending orders in an account.
GET /v3/accounts/{accountID}/pendingOrders
Sourcepub async fn order(
&self,
account_id: impl Into<AccountId>,
order: impl Into<OrderSpecifier>,
) -> Result<OrderResponse, Error>
pub async fn order( &self, account_id: impl Into<AccountId>, order: impl Into<OrderSpecifier>, ) -> Result<OrderResponse, Error>
Get details for a single order in an account.
GET /v3/accounts/{accountID}/orders/{orderSpecifier}
Sourcepub async fn replace_order(
&self,
account_id: impl Into<AccountId>,
order: impl Into<OrderSpecifier>,
replacement: impl Into<OrderRequest>,
) -> Result<ReplaceOrderResponse, Error>
pub async fn replace_order( &self, account_id: impl Into<AccountId>, order: impl Into<OrderSpecifier>, replacement: impl Into<OrderRequest>, ) -> Result<ReplaceOrderResponse, Error>
Replace an order in an account by simultaneously cancelling it and creating a replacement.
PUT /v3/accounts/{accountID}/orders/{orderSpecifier}
Sourcepub async fn cancel_order(
&self,
account_id: impl Into<AccountId>,
order: impl Into<OrderSpecifier>,
) -> Result<CancelOrderResponse, Error>
pub async fn cancel_order( &self, account_id: impl Into<AccountId>, order: impl Into<OrderSpecifier>, ) -> Result<CancelOrderResponse, Error>
Cancel a pending order in an account.
PUT /v3/accounts/{accountID}/orders/{orderSpecifier}/cancel
§Errors
A failed cancellation (HTTP 404) carries an
orderCancelRejectTransaction; recover it with
ApiErrorBody::details::<CancelOrderRejectBody>.
Sourcepub fn set_order_client_extensions(
&self,
account_id: impl Into<AccountId>,
order: impl Into<OrderSpecifier>,
) -> SetOrderClientExtensionsRequest
pub fn set_order_client_extensions( &self, account_id: impl Into<AccountId>, order: impl Into<OrderSpecifier>, ) -> SetOrderClientExtensionsRequest
Update the client extensions for an order in an account.
Do not set, modify, or delete client_extensions if the account
is associated with MT4.
PUT /v3/accounts/{accountID}/orders/{orderSpecifier}/clientExtensions
Source§impl Client
impl Client
Sourcepub async fn list_positions(
&self,
account_id: impl Into<AccountId>,
) -> Result<ListPositionsResponse, Error>
pub async fn list_positions( &self, account_id: impl Into<AccountId>, ) -> Result<ListPositionsResponse, Error>
List all positions for an account. The positions returned are for every instrument that has had a position during the lifetime of the account.
GET /v3/accounts/{accountID}/positions
Sourcepub async fn list_open_positions(
&self,
account_id: impl Into<AccountId>,
) -> Result<ListPositionsResponse, Error>
pub async fn list_open_positions( &self, account_id: impl Into<AccountId>, ) -> Result<ListPositionsResponse, Error>
List all open positions for an account. An open position is a position that currently has a trade open.
GET /v3/accounts/{accountID}/openPositions
Sourcepub async fn position(
&self,
account_id: impl Into<AccountId>,
instrument: impl Into<InstrumentName>,
) -> Result<PositionResponse, Error>
pub async fn position( &self, account_id: impl Into<AccountId>, instrument: impl Into<InstrumentName>, ) -> Result<PositionResponse, Error>
Get the details of a single instrument’s position in an account.
GET /v3/accounts/{accountID}/positions/{instrument}
Sourcepub fn close_position(
&self,
account_id: impl Into<AccountId>,
instrument: impl Into<InstrumentName>,
) -> ClosePositionRequest
pub fn close_position( &self, account_id: impl Into<AccountId>, instrument: impl Into<InstrumentName>, ) -> ClosePositionRequest
Close a position for a specific instrument.
At least one of long_units /
short_units should be set;
OANDA defaults both to ALL when omitted.
PUT /v3/accounts/{accountID}/positions/{instrument}/close
§Examples
// Close the whole long side of the EUR_USD position:
client
.close_position("101-004-1234567-001", "EUR_USD")
.long_units("ALL")
.send()
.await?;Source§impl Client
impl Client
Sourcepub fn prices<I>(
&self,
account_id: impl Into<AccountId>,
instruments: I,
) -> PricesRequest
pub fn prices<I>( &self, account_id: impl Into<AccountId>, instruments: I, ) -> PricesRequest
Get pricing information for a list of instruments within an account.
GET /v3/accounts/{accountID}/pricing
§Examples
let pricing = client
.prices("101-004-1234567-001", ["EUR_USD", "USD_JPY"])
.send()
.await?;
for price in pricing.prices {
println!("{:?}: {:?}", price.instrument, price.closeout_bid);
}Sourcepub fn pricing_stream<I>(
&self,
account_id: impl Into<AccountId>,
instruments: I,
) -> PricingStreamRequest
pub fn pricing_stream<I>( &self, account_id: impl Into<AccountId>, instruments: I, ) -> PricingStreamRequest
Open a stream of price updates (plus a heartbeat every 5 seconds) for the given instruments.
The returned PricingStream manages its own connection: it
detects stale connections via the heartbeat, reconnects with capped
exponential backoff, and requests a fresh price snapshot on every
reconnect. See crate::streaming for details and tuning.
Connects to the streaming host
(stream-fxpractice/stream-fxtrade). OANDA allows at most 20
active streams per IP; prices are throttled to at most 4 updates
per second per instrument.
GET /v3/accounts/{accountID}/pricing/stream
§Examples
use futures_util::StreamExt;
use oanda_rs::models::PriceStreamItem;
let mut stream = client
.pricing_stream("101-004-1234567-001", ["EUR_USD"])
.send()
.await?;
while let Some(item) = stream.next().await {
match item? {
PriceStreamItem::Price(price) => println!("{:?}", price.closeout_bid),
PriceStreamItem::Heartbeat(_) => {}
_ => {}
}
}Source§impl Client
impl Client
Sourcepub fn list_trades(&self, account_id: impl Into<AccountId>) -> ListTradesRequest
pub fn list_trades(&self, account_id: impl Into<AccountId>) -> ListTradesRequest
Get a list of trades for an account.
GET /v3/accounts/{accountID}/trades
Sourcepub async fn list_open_trades(
&self,
account_id: impl Into<AccountId>,
) -> Result<ListTradesResponse, Error>
pub async fn list_open_trades( &self, account_id: impl Into<AccountId>, ) -> Result<ListTradesResponse, Error>
Get the list of open trades for an account.
GET /v3/accounts/{accountID}/openTrades
Sourcepub async fn trade(
&self,
account_id: impl Into<AccountId>,
trade: impl Into<TradeSpecifier>,
) -> Result<TradeResponse, Error>
pub async fn trade( &self, account_id: impl Into<AccountId>, trade: impl Into<TradeSpecifier>, ) -> Result<TradeResponse, Error>
Get the details of a specific trade in an account.
GET /v3/accounts/{accountID}/trades/{tradeSpecifier}
Sourcepub fn close_trade(
&self,
account_id: impl Into<AccountId>,
trade: impl Into<TradeSpecifier>,
) -> CloseTradeRequest
pub fn close_trade( &self, account_id: impl Into<AccountId>, trade: impl Into<TradeSpecifier>, ) -> CloseTradeRequest
Close (partially or fully) a specific open trade in an account.
PUT /v3/accounts/{accountID}/trades/{tradeSpecifier}/close
§Examples
// Close a trade fully (the default) ...
client.close_trade("101-004-1234567-001", "6543").send().await?;
// ... or partially:
client
.close_trade("101-004-1234567-001", "6543")
.units("50")
.send()
.await?;Sourcepub async fn set_trade_client_extensions(
&self,
account_id: impl Into<AccountId>,
trade: impl Into<TradeSpecifier>,
extensions: ClientExtensions,
) -> Result<SetTradeClientExtensionsResponse, Error>
pub async fn set_trade_client_extensions( &self, account_id: impl Into<AccountId>, trade: impl Into<TradeSpecifier>, extensions: ClientExtensions, ) -> Result<SetTradeClientExtensionsResponse, Error>
Update the client extensions for a trade.
Do not add, update, or delete the client extensions if your account is associated with MT4.
PUT /v3/accounts/{accountID}/trades/{tradeSpecifier}/clientExtensions
Sourcepub fn set_trade_dependent_orders(
&self,
account_id: impl Into<AccountId>,
trade: impl Into<TradeSpecifier>,
) -> SetTradeDependentOrdersRequest
pub fn set_trade_dependent_orders( &self, account_id: impl Into<AccountId>, trade: impl Into<TradeSpecifier>, ) -> SetTradeDependentOrdersRequest
Create, replace and cancel the dependent orders (take-profit, stop-loss and trailing stop-loss) of a trade.
Setting a detail replaces the existing dependent order (or creates one); setting it to “cancel” removes it. Details not set are left unmodified.
PUT /v3/accounts/{accountID}/trades/{tradeSpecifier}/orders
Source§impl Client
impl Client
Sourcepub fn list_transactions(
&self,
account_id: impl Into<AccountId>,
) -> ListTransactionsRequest
pub fn list_transactions( &self, account_id: impl Into<AccountId>, ) -> ListTransactionsRequest
Get a list of transaction pages that satisfy a time-based
transaction query. The response contains page URLs, not
transactions; fetch pages via
Client::transactions_id_range.
GET /v3/accounts/{accountID}/transactions
Sourcepub async fn transaction(
&self,
account_id: impl Into<AccountId>,
transaction_id: impl Into<TransactionId>,
) -> Result<TransactionResponse, Error>
pub async fn transaction( &self, account_id: impl Into<AccountId>, transaction_id: impl Into<TransactionId>, ) -> Result<TransactionResponse, Error>
Get the details of a single account transaction.
GET /v3/accounts/{accountID}/transactions/{transactionID}
Sourcepub fn transactions_id_range(
&self,
account_id: impl Into<AccountId>,
from: impl Into<TransactionId>,
to: impl Into<TransactionId>,
) -> TransactionsIdRangeRequest
pub fn transactions_id_range( &self, account_id: impl Into<AccountId>, from: impl Into<TransactionId>, to: impl Into<TransactionId>, ) -> TransactionsIdRangeRequest
Get a range of transactions for an account based on transaction IDs.
GET /v3/accounts/{accountID}/transactions/idrange
Sourcepub fn transaction_stream(
&self,
account_id: impl Into<AccountId>,
) -> TransactionStreamRequest
pub fn transaction_stream( &self, account_id: impl Into<AccountId>, ) -> TransactionStreamRequest
Open a stream of the account’s transactions (plus a heartbeat every 5 seconds).
The returned TransactionStream manages its own connection: it
detects stale connections via the heartbeat, reconnects with capped
exponential backoff, and back-fills transactions missed while
disconnected via Client::transactions_since_id, deduplicating
by transaction ID. See crate::streaming for details and tuning.
Connects to the streaming host
(stream-fxpractice/stream-fxtrade). OANDA allows at most 20
active streams per IP.
GET /v3/accounts/{accountID}/transactions/stream
§Examples
use futures_util::StreamExt;
use oanda_rs::models::transaction::TransactionStreamItem;
let mut stream = client
.transaction_stream("101-004-1234567-001")
.send()
.await?;
while let Some(item) = stream.next().await {
if let TransactionStreamItem::Transaction(tx) = item? {
println!("{:?}: {:?}", tx.type_name(), tx.id());
}
}Sourcepub async fn transactions_since_id(
&self,
account_id: impl Into<AccountId>,
id: impl Into<TransactionId>,
) -> Result<TransactionsResponse, Error>
pub async fn transactions_since_id( &self, account_id: impl Into<AccountId>, id: impl Into<TransactionId>, ) -> Result<TransactionsResponse, Error>
Get a range of transactions for an account starting at (but not including) a provided transaction ID.
This is the canonical way to back-fill transactions missed while a transaction stream was disconnected.
GET /v3/accounts/{accountID}/transactions/sinceid