use crate::common::client::{base_url, RestClient};
use crate::error::AlpacaError;
use crate::trading::models::*;
use crate::trading::requests::*;
use uuid::Uuid;
#[derive(Clone)]
pub struct TradingClient {
client: RestClient,
}
impl TradingClient {
pub fn new(api_key: &str, secret_key: &str, paper: bool) -> Result<Self, AlpacaError> {
let url = if paper {
base_url::TRADING_PAPER
} else {
base_url::TRADING_LIVE
};
Ok(Self {
client: RestClient::new(
Some(api_key.to_string()),
Some(secret_key.to_string()),
None,
url.to_string(),
"v2".to_string(),
false,
)?,
})
}
#[doc(hidden)]
pub fn new_with_url(api_key: &str, secret_key: &str, base_url: &str) -> Result<Self, AlpacaError> {
Ok(Self {
client: RestClient::new(
Some(api_key.to_string()),
Some(secret_key.to_string()),
None,
base_url.to_string(),
"v2".to_string(),
false,
)?,
})
}
pub fn with_oauth(oauth_token: &str, paper: bool) -> Result<Self, AlpacaError> {
let url = if paper {
base_url::TRADING_PAPER
} else {
base_url::TRADING_LIVE
};
Ok(Self {
client: RestClient::new(
None,
None,
Some(oauth_token.to_string()),
url.to_string(),
"v2".to_string(),
false,
)?,
})
}
pub async fn get_account(&self) -> Result<TradeAccount, AlpacaError> {
self.client.get("/account", None::<&()>).await
}
pub async fn get_account_configurations(&self) -> Result<AccountConfiguration, AlpacaError> {
self.client.get("/account/configurations", None::<&()>).await
}
pub async fn set_account_configurations(
&self,
config: &AccountConfiguration,
) -> Result<AccountConfiguration, AlpacaError> {
self.client.patch("/account/configurations", Some(config)).await
}
pub async fn get_portfolio_history(
&self,
filter: Option<&GetPortfolioHistoryRequest>,
) -> Result<PortfolioHistory, AlpacaError> {
self.client.get("/account/portfolio/history", filter).await
}
pub async fn get_account_activities(
&self,
filter: Option<&GetAccountActivitiesRequest>,
) -> Result<Vec<serde_json::Value>, AlpacaError> {
self.client.get("/account/activities", filter).await
}
pub async fn submit_order(&self, order: &OrderRequest) -> Result<Order, AlpacaError> {
self.client.post("/orders", Some(order)).await
}
pub async fn get_orders(
&self,
filter: Option<&GetOrdersRequest>,
) -> Result<Vec<Order>, AlpacaError> {
self.client.get("/orders", filter).await
}
pub async fn get_order_by_id(
&self,
order_id: &Uuid,
filter: Option<&GetOrderByIdRequest>,
) -> Result<Order, AlpacaError> {
self.client
.get(&format!("/orders/{}", order_id), filter)
.await
}
pub async fn get_order_by_client_id(&self, client_id: &str) -> Result<Order, AlpacaError> {
#[derive(serde::Serialize)]
struct Params<'a> {
client_order_id: &'a str,
}
self.client
.get("/orders:by_client_order_id", Some(&Params { client_order_id: client_id }))
.await
}
pub async fn replace_order_by_id(
&self,
order_id: &Uuid,
data: &ReplaceOrderRequest,
) -> Result<Order, AlpacaError> {
self.client
.patch(&format!("/orders/{}", order_id), Some(data))
.await
}
pub async fn cancel_orders(&self) -> Result<Vec<CancelOrderResponse>, AlpacaError> {
self.client.delete("/orders", None::<&()>).await
}
pub async fn cancel_order_by_id(&self, order_id: &Uuid) -> Result<(), AlpacaError> {
self.client
.delete_void(&format!("/orders/{}", order_id), None::<&()>)
.await
}
pub async fn get_all_positions(&self) -> Result<Vec<Position>, AlpacaError> {
self.client.get("/positions", None::<&()>).await
}
pub async fn get_open_position(
&self,
symbol_or_asset_id: &str,
) -> Result<Position, AlpacaError> {
self.client
.get(&format!("/positions/{}", symbol_or_asset_id), None::<&()>)
.await
}
pub async fn close_all_positions(
&self,
cancel_orders: Option<bool>,
) -> Result<Vec<ClosePositionResponse>, AlpacaError> {
#[derive(serde::Serialize)]
struct Params {
#[serde(skip_serializing_if = "Option::is_none")]
cancel_orders: Option<bool>,
}
self.client
.delete("/positions", Some(&Params { cancel_orders }))
.await
}
pub async fn close_position(
&self,
symbol_or_asset_id: &str,
close_options: Option<&ClosePositionRequest>,
) -> Result<Order, AlpacaError> {
self.client
.delete_with_body(&format!("/positions/{}", symbol_or_asset_id), close_options)
.await
}
pub async fn exercise_options_position(
&self,
symbol_or_contract_id: &str,
) -> Result<(), AlpacaError> {
self.client
.post_void(
&format!("/positions/{}/exercise", symbol_or_contract_id),
None::<&()>,
)
.await
}
pub async fn get_all_assets(
&self,
filter: Option<&GetAssetsRequest>,
) -> Result<Vec<Asset>, AlpacaError> {
self.client.get("/assets", filter).await
}
pub async fn get_asset(&self, symbol_or_asset_id: &str) -> Result<Asset, AlpacaError> {
self.client
.get(&format!("/assets/{}", symbol_or_asset_id), None::<&()>)
.await
}
pub async fn get_clock(&self) -> Result<Clock, AlpacaError> {
self.client.get("/clock", None::<&()>).await
}
pub async fn get_calendar(
&self,
filters: Option<&GetCalendarRequest>,
) -> Result<Vec<Calendar>, AlpacaError> {
self.client.get("/calendar", filters).await
}
pub async fn get_watchlists(&self) -> Result<Vec<Watchlist>, AlpacaError> {
self.client.get("/watchlists", None::<&()>).await
}
pub async fn get_watchlist_by_id(&self, watchlist_id: &Uuid) -> Result<Watchlist, AlpacaError> {
self.client
.get(&format!("/watchlists/{}", watchlist_id), None::<&()>)
.await
}
pub async fn create_watchlist(
&self,
data: &CreateWatchlistRequest,
) -> Result<Watchlist, AlpacaError> {
self.client.post("/watchlists", Some(data)).await
}
pub async fn update_watchlist_by_id(
&self,
watchlist_id: &Uuid,
data: &UpdateWatchlistRequest,
) -> Result<Watchlist, AlpacaError> {
self.client
.put(&format!("/watchlists/{}", watchlist_id), Some(data))
.await
}
pub async fn add_asset_to_watchlist_by_id(
&self,
watchlist_id: &Uuid,
symbol: &str,
) -> Result<Watchlist, AlpacaError> {
let body = AddSymbolToWatchlistRequest { symbol: symbol.to_string() };
self.client
.post(&format!("/watchlists/{}", watchlist_id), Some(&body))
.await
}
pub async fn delete_watchlist_by_id(&self, watchlist_id: &Uuid) -> Result<(), AlpacaError> {
self.client
.delete_void(&format!("/watchlists/{}", watchlist_id), None::<&()>)
.await
}
pub async fn remove_asset_from_watchlist_by_id(
&self,
watchlist_id: &Uuid,
symbol: &str,
) -> Result<Watchlist, AlpacaError> {
self.client
.delete(&format!("/watchlists/{}/{}", watchlist_id, symbol), None::<&()>)
.await
}
pub async fn get_corporate_announcements(
&self,
filter: &GetCorporateAnnouncementsRequest,
) -> Result<Vec<CorporateActionAnnouncement>, AlpacaError> {
self.client
.get("/corporate_actions/announcements", Some(filter))
.await
}
pub async fn get_corporate_announcement_by_id(
&self,
id: &str,
) -> Result<CorporateActionAnnouncement, AlpacaError> {
self.client
.get(&format!("/corporate_actions/announcements/{}", id), None::<&()>)
.await
}
pub async fn get_option_contracts(
&self,
request: &GetOptionContractsRequest,
) -> Result<OptionContractsResponse, AlpacaError> {
self.client.get("/options/contracts", Some(request)).await
}
pub async fn get_option_contract(
&self,
symbol_or_id: &str,
) -> Result<OptionContract, AlpacaError> {
self.client
.get(&format!("/options/contracts/{}", symbol_or_id), None::<&()>)
.await
}
}