exc_types/
instrument.rs

1use derive_more::Display;
2use futures::stream::BoxStream;
3use positions::Instrument;
4use rust_decimal::Decimal;
5use serde::{Deserialize, Serialize};
6use thiserror::Error;
7
8use crate::{symbol::ExcSymbol, Str};
9use exc_service::{ExchangeError, Request};
10
11/// Parse Instrument Meta Error.
12#[derive(Debug, Error)]
13pub enum InstrumentMetaError<E> {
14    /// Parse num error.
15    #[error("parse num error: {0}")]
16    FromStrError(#[from] E),
17
18    /// Missing fields.
19    #[error("missing fields")]
20    MissingFields,
21}
22
23/// Instrument Meta.
24#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Display)]
25#[display(bound = "Num: std::fmt::Display")]
26#[display(
27    fmt = "name={name} inst={inst} rev={} unit={} pt={} st={} ms={} mv={} live={live} will_expire={}",
28    "inst.is_prefer_reversed()",
29    "attrs.unit",
30    "attrs.price_tick",
31    "attrs.size_tick",
32    "attrs.min_size",
33    "attrs.min_value",
34    "expire.is_some()"
35)]
36#[serde(bound = "Num: num_traits::Zero + Serialize + for<'a> Deserialize<'a>")]
37pub struct InstrumentMeta<Num> {
38    /// name.
39    name: Str,
40    /// Instrument.
41    inst: Instrument,
42    /// Attributes.
43    #[serde(flatten)]
44    attrs: Attributes<Num>,
45    /// Is live for trading.
46    #[serde(default = "live")]
47    live: bool,
48    /// Expire time.
49    #[serde(default)]
50    #[serde(with = "time::serde::rfc3339::option")]
51    expire: Option<time::OffsetDateTime>,
52}
53
54fn live() -> bool {
55    true
56}
57
58/// Instrument Meta.
59#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
60#[serde(bound = "Num: num_traits::Zero + Serialize + for<'a> Deserialize<'a>")]
61pub struct Attributes<Num> {
62    /// Reversed.
63    pub reversed: bool,
64    /// Unit.
65    pub unit: Num,
66    /// Price min tick.
67    pub price_tick: Num,
68    /// Size min tick.
69    pub size_tick: Num,
70    /// Min trade size.
71    pub min_size: Num,
72    /// Min value.
73    #[serde(default = "num_traits::Zero::zero")]
74    pub min_value: Num,
75}
76
77impl<Num> InstrumentMeta<Num> {
78    /// Create a new [`InstrumentMeta`].
79    pub fn new(name: impl AsRef<str>, symbol: ExcSymbol, attrs: Attributes<Num>) -> Self {
80        let (base, quote, _) = symbol.to_parts();
81        let inst = Instrument::try_with_symbol(symbol.into(), &base, &quote)
82            .expect("symbol must be valid")
83            .prefer_reversed(attrs.reversed);
84        Self {
85            name: Str::new(name),
86            inst,
87            attrs,
88            live: true,
89            expire: None,
90        }
91    }
92
93    /// Get the instrument name from the exchange.
94    pub fn name(&self) -> &str {
95        &self.name
96    }
97
98    /// Get name of inner type.
99    pub fn smol_name(&self) -> &Str {
100        &self.name
101    }
102
103    /// Get instrument.
104    pub fn instrument(&self) -> &Instrument {
105        &self.inst
106    }
107
108    /// Get attributes.
109    pub fn attrs(&self) -> &Attributes<Num> {
110        &self.attrs
111    }
112
113    /// Get if the instrument is live for trading.
114    pub fn is_live(&self) -> bool {
115        self.live
116    }
117
118    /// Get the expire time.
119    pub fn expire(&self) -> Option<&time::OffsetDateTime> {
120        self.expire.as_ref()
121    }
122
123    /// Set whether the instrument is live for trading.
124    pub fn with_live(mut self, live: bool) -> Self {
125        self.live = live;
126        self
127    }
128
129    /// Set the expire time.
130    pub fn with_expire(mut self, expire: impl Into<Option<time::OffsetDateTime>>) -> Self {
131        self.expire = expire.into();
132        self
133    }
134}
135
136/// Instrument Stream.
137pub type InstrumentStream = BoxStream<'static, Result<InstrumentMeta<Decimal>, ExchangeError>>;
138
139/// Subscribe instruments.
140#[derive(Debug, Clone)]
141pub struct SubscribeInstruments {
142    /// Tag.
143    pub tag: Str,
144}
145
146impl SubscribeInstruments {
147    /// Create a new [`SubscribeInstruments`] request.
148    pub fn new(tag: impl AsRef<str>) -> Self {
149        Self { tag: Str::new(tag) }
150    }
151}
152
153/// Fetch instruments.
154#[derive(Debug, Clone)]
155pub struct FetchInstruments {
156    /// Tag.
157    pub tag: Str,
158}
159
160impl FetchInstruments {
161    /// Create a new [`FetchInstruments`] request.
162    pub fn new(tag: impl AsRef<str>) -> Self {
163        Self { tag: Str::new(tag) }
164    }
165}
166
167impl Request for SubscribeInstruments {
168    type Response = InstrumentStream;
169}
170
171impl Request for FetchInstruments {
172    type Response = InstrumentStream;
173}