pub mod place;
pub mod order;
use std::{collections::BTreeMap, fmt, sync::Arc};
use exc_service::{ExchangeError, Request};
use futures::{future::BoxFuture, stream::BoxStream};
use indicator::{Tick, TickValue, Tickable};
pub use order::{Order, OrderId, OrderKind, OrderState, OrderStatus, OrderTrade, TimeInForce};
pub use place::Place;
use positions::Asset;
use time::OffsetDateTime;
use crate::Str;
#[derive(Debug, Clone)]
pub struct PlaceOrderOptions {
instrument: Str,
client_id: Option<Str>,
margin: Option<Asset>,
custom: BTreeMap<Str, Str>,
}
impl PlaceOrderOptions {
pub fn new(inst: impl AsRef<str>) -> Self {
Self {
instrument: Str::new(inst),
client_id: None,
margin: None,
custom: BTreeMap::default(),
}
}
pub fn with_client_id(&mut self, id: Option<impl AsRef<str>>) -> &mut Self {
self.client_id = id.map(Str::new);
self
}
pub fn with_margin(&mut self, currency: &Asset) -> &mut Self {
self.margin = Some(currency.clone());
self
}
pub fn insert<K, V>(&mut self, key: K, value: V) -> &mut Self
where
K: AsRef<str>,
V: AsRef<str>,
{
self.custom
.insert(Str::new(key.as_ref()), Str::new(value.as_ref()));
self
}
pub fn instrument(&self) -> &str {
&self.instrument
}
pub fn client_id(&self) -> Option<&str> {
self.client_id.as_deref()
}
pub fn margin(&self) -> Option<&str> {
self.margin.as_deref()
}
pub fn custom(&self) -> &BTreeMap<Str, Str> {
&self.custom
}
}
#[derive(Debug, Clone)]
pub struct PlaceOrder {
pub place: Place,
pub opts: Arc<PlaceOrderOptions>,
}
impl PlaceOrder {
pub fn new(place: Place, opts: &PlaceOrderOptions) -> Self {
Self {
place,
opts: Arc::new(opts.clone()),
}
}
}
#[derive(Clone)]
pub struct Placed {
pub id: OrderId,
pub order: Option<Order>,
pub ts: OffsetDateTime,
}
impl fmt::Debug for Placed {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Placed")
.field("ts", &self.ts.to_string())
.field("id", &self.id.as_str())
.field("order", &self.order)
.finish()
}
}
impl Request for PlaceOrder {
type Response = BoxFuture<'static, Result<Placed, ExchangeError>>;
}
#[derive(Debug, Clone)]
pub struct CancelOrder {
pub instrument: Str,
pub id: OrderId,
}
impl CancelOrder {
pub fn new(inst: impl AsRef<str>, id: OrderId) -> Self {
Self {
instrument: Str::new(inst),
id,
}
}
}
#[derive(Clone)]
pub struct Canceled {
pub order: Option<Order>,
pub ts: OffsetDateTime,
}
impl fmt::Debug for Canceled {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Cancelled")
.field("ts", &self.ts.to_string())
.field("order", &self.order)
.finish()
}
}
impl Request for CancelOrder {
type Response = BoxFuture<'static, Result<Canceled, ExchangeError>>;
}
#[derive(Debug, Clone)]
pub struct GetOrder {
pub instrument: Str,
pub id: OrderId,
}
impl GetOrder {
pub fn new(inst: impl AsRef<str>, id: OrderId) -> Self {
Self {
instrument: Str::new(inst),
id,
}
}
}
#[derive(Clone)]
pub struct OrderUpdate {
pub ts: OffsetDateTime,
pub order: Order,
}
impl fmt::Debug for OrderUpdate {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OrderUpdate")
.field("ts", &self.ts.to_string())
.field("order", &self.order)
.finish()
}
}
impl Tickable for OrderUpdate {
type Value = Order;
fn tick(&self) -> Tick {
Tick::new(self.ts)
}
fn value(&self) -> &Self::Value {
&self.order
}
fn into_tick_value(self) -> TickValue<Self::Value> {
TickValue::new(self.ts, self.order)
}
}
impl Request for GetOrder {
type Response = BoxFuture<'static, Result<OrderUpdate, ExchangeError>>;
}
pub type OrderStream = BoxStream<'static, Result<OrderUpdate, ExchangeError>>;
#[derive(Debug, Clone)]
pub struct SubscribeOrders {
pub instrument: Str,
}
impl SubscribeOrders {
pub fn new(inst: impl AsRef<str>) -> Self {
Self {
instrument: Str::new(inst),
}
}
}
impl Request for SubscribeOrders {
type Response = OrderStream;
}