use derive_more::Display;
use futures::stream::BoxStream;
use positions::Instrument;
use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};
use thiserror::Error;
use crate::{symbol::ExcSymbol, Str};
use exc_service::{ExchangeError, Request};
#[derive(Debug, Error)]
pub enum InstrumentMetaError<E> {
#[error("parse num error: {0}")]
FromStrError(#[from] E),
#[error("missing fields")]
MissingFields,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Display)]
#[display(bound = "Num: std::fmt::Display")]
#[display(
fmt = "name={name} inst={inst} rev={} unit={} pt={} st={} ms={} mv={} live={live} will_expire={}",
"inst.is_prefer_reversed()",
"attrs.unit",
"attrs.price_tick",
"attrs.size_tick",
"attrs.min_size",
"attrs.min_value",
"expire.is_some()"
)]
#[serde(bound = "Num: num_traits::Zero + Serialize + for<'a> Deserialize<'a>")]
pub struct InstrumentMeta<Num> {
name: Str,
inst: Instrument,
#[serde(flatten)]
attrs: Attributes<Num>,
#[serde(default = "live")]
live: bool,
#[serde(default)]
#[serde(with = "time::serde::rfc3339::option")]
expire: Option<time::OffsetDateTime>,
}
fn live() -> bool {
true
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(bound = "Num: num_traits::Zero + Serialize + for<'a> Deserialize<'a>")]
pub struct Attributes<Num> {
pub reversed: bool,
pub unit: Num,
pub price_tick: Num,
pub size_tick: Num,
pub min_size: Num,
#[serde(default = "num_traits::Zero::zero")]
pub min_value: Num,
}
impl<Num> InstrumentMeta<Num> {
pub fn new(name: impl AsRef<str>, symbol: ExcSymbol, attrs: Attributes<Num>) -> Self {
let (base, quote, _) = symbol.to_parts();
let inst = Instrument::try_with_symbol(symbol.into(), &base, "e)
.expect("symbol must be valid")
.prefer_reversed(attrs.reversed);
Self {
name: Str::new(name),
inst,
attrs,
live: true,
expire: None,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn smol_name(&self) -> &Str {
&self.name
}
pub fn instrument(&self) -> &Instrument {
&self.inst
}
pub fn attrs(&self) -> &Attributes<Num> {
&self.attrs
}
pub fn is_live(&self) -> bool {
self.live
}
pub fn expire(&self) -> Option<&time::OffsetDateTime> {
self.expire.as_ref()
}
pub fn with_live(mut self, live: bool) -> Self {
self.live = live;
self
}
pub fn with_expire(mut self, expire: impl Into<Option<time::OffsetDateTime>>) -> Self {
self.expire = expire.into();
self
}
}
pub type InstrumentStream = BoxStream<'static, Result<InstrumentMeta<Decimal>, ExchangeError>>;
#[derive(Debug, Clone)]
pub struct SubscribeInstruments {
pub tag: Str,
}
impl SubscribeInstruments {
pub fn new(tag: impl AsRef<str>) -> Self {
Self { tag: Str::new(tag) }
}
}
#[derive(Debug, Clone)]
pub struct FetchInstruments {
pub tag: Str,
}
impl FetchInstruments {
pub fn new(tag: impl AsRef<str>) -> Self {
Self { tag: Str::new(tag) }
}
}
impl Request for SubscribeInstruments {
type Response = InstrumentStream;
}
impl Request for FetchInstruments {
type Response = InstrumentStream;
}