use crate::authentication::TokenResponse;
use crate::error::{Error, ErrorType};
use crate::orders::create::{CreateOrderParams, CreateOrderResponse};
use crate::orders::get::{ListOrdersParams, ListOrdersResponse};
use crate::orders::update::UpdateOrderRequestBody;
use crate::orders::Order;
use crate::positions::{ListPositionsResponse, Position};
use reqwest::header::{ACCEPT, AUTHORIZATION, CONTENT_TYPE};
use serde::{Deserialize, Serialize};
use std::any::Any;
use std::fmt::{Debug, Display};
#[cfg(feature = "async")]
pub mod async_client;
#[cfg(feature = "sync")]
pub mod sync_client;
pub trait ClearstreetClient: Send + Sync {
fn set_token(&mut self, token: &str);
}
pub fn build_headers(token: &str) -> Result<reqwest::header::HeaderMap, Error> {
let mut headers = reqwest::header::HeaderMap::new();
let auth_header = format!("Bearer {}", token);
let bearer_token = reqwest::header::HeaderValue::from_str(&auth_header)
.map_err(|e| Error::new(ErrorType::SerializationError, &e.to_string()))?;
headers.insert(AUTHORIZATION, bearer_token);
headers.insert(CONTENT_TYPE, "application/json".parse()?);
headers.insert(ACCEPT, "application/json".parse()?);
Ok(headers)
}
#[derive(Clone, Serialize, Deserialize)]
pub struct ClientOptions {
pub api_url: String,
pub websocket_url: String,
pub client_id: String,
pub client_secret: String,
pub account_id: String,
}
impl Display for ClientOptions {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"ClientOptions {{ api_url: {}, websocket_url: {}, client_id: {}, client_secret: **REDACTED** }}",
self.api_url, self.websocket_url, self.client_id
)
}
}
impl Debug for ClientOptions {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"ClientOptions {{ api_url: {}, websocket_url: {}, client_id: {}, client_secret: **REDACTED** }}",
self.api_url, self.websocket_url, self.client_id
)
}
}
impl Default for ClientOptions {
fn default() -> Self {
Self {
api_url: "https://api.clearstreet.io".to_string(),
websocket_url: "wss://api.clearstreet.io/studio/v2/ws".to_string(),
client_id: "<your_client_id>".to_string(),
client_secret: "<your_client_secret>".to_string(),
account_id: "<your_account_id>".to_string(),
}
}
}
#[cfg(feature = "async")]
use async_trait::async_trait;
use tokio_tungstenite::WebSocketStream;
#[cfg(feature = "async")]
#[async_trait]
pub trait AsyncClearstreetClient: Send + Sync {
fn set_token(&mut self, token: &str);
fn as_any(&self) -> &dyn Any;
fn get_account_id(&self) -> String;
async fn fetch_new_token(&self) -> Result<TokenResponse, Error>;
async fn create_order(
&self,
params: CreateOrderParams,
) -> Result<CreateOrderResponse, Error>;
async fn get_order(&self, order_id: &str) -> Result<Order, Error>;
async fn update_order(
&self,
order_id: &str,
params: UpdateOrderRequestBody,
) -> Result<(), Error>;
async fn delete_order(&self, order_id: &str) -> Result<(), Error>;
async fn delete_all_orders(&self, symbol: Option<&str>) -> Result<(), Error>;
async fn list_orders(
&self,
params: ListOrdersParams,
) -> Result<ListOrdersResponse, Error>;
async fn get_position(&self, symbol: &str) -> Result<Position, Error>;
async fn list_positions(&self) -> Result<ListPositionsResponse, Error>;
async fn connect_websocket(&self) -> Result<WebSocketStream<tokio_tungstenite::MaybeTlsStream<tokio::net::TcpStream>>, Error>;
}
#[cfg(feature = "sync")]
pub trait SyncClearstreetClient: Send + Sync {
fn as_any(&self) -> &dyn Any;
fn set_token(&mut self, token: &str);
fn fetch_new_token(&self) -> Result<crate::authentication::TokenResponse, Error>;
fn get_account_id(&self) -> String;
fn create_order(&self, params: CreateOrderParams) -> Result<CreateOrderResponse, Error>;
fn get_order(&self, order_id: &str) -> Result<Order, Error>;
fn update_order(&self, order_id: &str, params: UpdateOrderRequestBody) -> Result<(), Error>;
fn list_orders(&self, params: ListOrdersParams) -> Result<ListOrdersResponse, Error>;
fn delete_order(&self, order_id: &str) -> Result<(), Error>;
fn delete_all_orders(&self, symbol: Option<&str>) -> Result<(), Error>;
fn get_position(&self, symbol: &str) -> Result<Position, Error>;
fn list_positions(&self) -> Result<ListPositionsResponse, Error>;
fn connect_websocket(&self) -> Result<tungstenite::protocol::WebSocket<tungstenite::stream::MaybeTlsStream<std::net::TcpStream>>, Error>;
}