use crate::{
config::Common,
protocol::{
limits::{LimitScope, LimitSet},
orderflow::{
AberrantFill, ChanId, FillId, NormalFill, Order, OrderId, OrderState,
},
Account, Dir,
},
symbology::TradableProduct,
};
use anyhow::{bail, Result};
use enumflags2::BitFlags;
use netidx::{
chars::Chars, pack::Pack, pool::Pooled, protocol::value::Value, utils::pack,
};
use netidx_protocols::{call_rpc, rpc::client::Proc};
use rust_decimal::Decimal;
use std::result;
pub struct OmsQueryApi {
get_order_state: Proc,
get_channel_id: Proc,
list_open: Proc,
get_reject_reason: Proc,
get_order_details: Proc,
list_fills: Proc,
get_fill_details: Proc,
send_limit_order: Proc,
cancel_order: Proc,
}
impl OmsQueryApi {
pub async fn new(common: &Common) -> Result<Self> {
let base = common.paths.core_flow();
let subscriber = &common.subscriber;
Ok(Self {
get_order_state: Proc::new(subscriber, base.append("get-order-state"))
.await?,
list_open: Proc::new(subscriber, base.append("list-open")).await?,
get_reject_reason: Proc::new(subscriber, base.append("get-reject-reason"))
.await?,
get_order_details: Proc::new(subscriber, base.append("get-order-details"))
.await?,
list_fills: Proc::new(subscriber, base.append("list-fills")).await?,
get_fill_details: Proc::new(subscriber, base.append("get-fill-details"))
.await?,
send_limit_order: Proc::new(subscriber, base.append("send-limit-order"))
.await?,
get_channel_id: Proc::new(subscriber, base.append("get-channel-id")).await?,
cancel_order: Proc::new(subscriber, base.append("cancel-order")).await?,
})
}
pub async fn get_order_state(
&self,
ids: &Pooled<Vec<OrderId>>,
) -> Result<Pooled<Vec<BitFlags<OrderState>>>> {
let ids = Value::Bytes(pack(ids)?.freeze());
let res = call_rpc!(&self.get_order_state, ids: ids).await?;
match res {
Value::Error(e) => bail!(e.to_string()),
Value::Bytes(b) => Ok(Pack::decode(&mut &*b)?),
_ => bail!("unexpected response"),
}
}
pub async fn list_open(
&self,
set: LimitSet,
scope: LimitScope,
) -> Result<Pooled<Vec<OrderId>>> {
let res = call_rpc!(&self.list_open, set: set, scope: scope).await?;
match res {
Value::Error(e) => bail!(e.to_string()),
Value::Bytes(b) => Ok(Pack::decode(&mut &*b)?),
_ => bail!("unexpected reponse"),
}
}
pub async fn get_reject_reason(
&self,
ids: &Pooled<Vec<OrderId>>,
) -> Result<Pooled<Vec<Option<Chars>>>> {
let ids = Value::Bytes(pack(ids)?.freeze());
let res = call_rpc!(&self.get_reject_reason, ids: ids).await?;
match res {
Value::Error(e) => bail!(e.to_string()),
Value::Bytes(b) => Ok(Pack::decode(&mut &*b)?),
_ => bail!("unexpected response"),
}
}
pub async fn get_order_details(
&self,
ids: &Pooled<Vec<OrderId>>,
) -> Result<Pooled<Vec<Order>>> {
let ids = Value::Bytes(pack(ids)?.freeze());
let res = call_rpc!(&self.get_order_details, ids: ids).await?;
match res {
Value::Error(e) => bail!(e.to_string()),
Value::Bytes(b) => Ok(Pack::decode(&mut &*b)?),
_ => bail!("unexpected response"),
}
}
pub async fn list_fills(
&self,
set: LimitSet,
scope: LimitScope,
) -> Result<Pooled<Vec<(OrderId, FillId)>>> {
let res = call_rpc!(&self.list_fills, set: set, scope: scope).await?;
match res {
Value::Error(e) => bail!(e.to_string()),
Value::Bytes(b) => Ok(Pack::decode(&mut &*b)?),
_ => bail!("unexpected response"),
}
}
pub async fn get_fill_details(
&self,
ids: &Pooled<Vec<FillId>>,
) -> Result<Pooled<Vec<result::Result<NormalFill, AberrantFill>>>> {
let ids = Value::Bytes(pack(ids)?.freeze());
let res = call_rpc!(&self.get_fill_details, ids: ids).await?;
match res {
Value::Error(e) => bail!(e.to_string()),
Value::Bytes(b) => Ok(Pack::decode(&mut &*b)?),
_ => bail!("unexpected response"),
}
}
pub async fn send_limit_order(
&self,
target: TradableProduct,
account: Account,
dir: Dir,
price: Decimal,
quantity: Decimal,
) -> Result<OrderId> {
let res = call_rpc!(
&self.send_limit_order,
target: target,
account: account,
dir: dir,
price: price,
quantity: quantity
)
.await?;
match res {
Value::Error(e) => bail!(e.to_string()),
v => Ok(v.cast_to()?),
}
}
pub async fn cancel_order(&self, id: OrderId) -> Result<()> {
let res = call_rpc!(&self.cancel_order, id: id).await?;
match res {
Value::Error(e) => bail!(e.to_string()),
Value::Ok => Ok(()),
_ => bail!("unexpected response"),
}
}
pub async fn get_channel_id(&self) -> Result<ChanId> {
let args: [(&'static str, Value); 0] = [];
let res = self.get_channel_id.call(args).await?;
match res {
Value::Error(e) => bail!(e.to_string()),
v => Ok(v.cast_to()?),
}
}
}