tradingkit 0.1.0

Exchange-agnostic trading library for equities and crypto
Documentation
//! Write-side trading operations for exchange adapters.

use std::error::Error;

use crate::model::{CanceledOrderResponse, Order, OrderRequest, ReplaceOrderRequest};

/// Write-only trading surface for submitting, replacing, and canceling orders.
///
/// # Examples
///
/// ```rust,no_run
/// use tradingkit::exchange::alpaca::{Alpaca, AlpacaCredentials};
/// use tradingkit::model::{
///     AssetClass, OrderClass, OrderRequest, OrderSide, OrderType, PositionIntent,
///     ReplaceOrderRequest, TimeInForce,
/// };
/// use tradingkit::trading::TradingApi;
///
/// async fn example() -> Result<(), Box<dyn std::error::Error>> {
///     let api = Alpaca::paper(AlpacaCredentials::new(
///         "your-key".to_string(),
///         "your-secret".to_string(),
///     ));
///
///     let request = OrderRequest {
///         symbol: Some("AAPL240119C00190000".to_string()),
///         asset_class: Some(AssetClass::UsOption),
///         qty: Some("1".to_string()),
///         notional: None,
///         side: Some(OrderSide::Buy),
///         order_type: OrderType::Limit,
///         time_in_force: TimeInForce::Day,
///         order_class: Some(OrderClass::Simple),
///         limit_price: Some("200".to_string()),
///         stop_price: None,
///         trail_price: None,
///         trail_percent: None,
///         client_order_id: Some("example-order".to_string()),
///         extended_hours: Some(false),
///         position_intent: Some(PositionIntent::BuyToOpen),
///         legs: None,
///     };
///
///     let _submitted = api.submit(&request).await?;
///
///     let replace = ReplaceOrderRequest {
///         qty: Some("2".to_string()),
///         time_in_force: Some(TimeInForce::Gtc),
///         limit_price: Some("201".to_string()),
///         stop_price: None,
///         trail: None,
///         client_order_id: Some("example-order-replaced".to_string()),
///     };
///
///     let _replaced = api.replace("order-id", &replace).await?;
///     api.cancel("order-id").await?;
///     Ok(())
/// }
/// ```
#[allow(async_fn_in_trait)]
pub trait TradingApi {
    /// Submits a new order.
    async fn submit(&self, order: &OrderRequest) -> Result<Order, Box<dyn Error>>;

    /// Replaces an open order with new parameters.
    async fn replace(
        &self,
        order_id: &str,
        request: &ReplaceOrderRequest,
    ) -> Result<Order, Box<dyn Error>>;

    /// Cancels a single open order.
    async fn cancel(&self, order_id: &str) -> Result<(), Box<dyn Error>>;

    /// Attempts to cancel all open orders.
    async fn cancel_all(&self) -> Result<Vec<CanceledOrderResponse>, Box<dyn Error>>;
}