1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
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};

/// Parse Instrument Meta Error.
#[derive(Debug, Error)]
pub enum InstrumentMetaError<E> {
    /// Parse num error.
    #[error("parse num error: {0}")]
    FromStrError(#[from] E),

    /// Missing fields.
    #[error("missing fields")]
    MissingFields,
}

/// Instrument Meta.
#[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.
    name: Str,
    /// Instrument.
    inst: Instrument,
    /// Attributes.
    #[serde(flatten)]
    attrs: Attributes<Num>,
    /// Is live for trading.
    #[serde(default = "live")]
    live: bool,
    /// Expire time.
    #[serde(default)]
    #[serde(with = "time::serde::rfc3339::option")]
    expire: Option<time::OffsetDateTime>,
}

fn live() -> bool {
    true
}

/// Instrument Meta.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(bound = "Num: num_traits::Zero + Serialize + for<'a> Deserialize<'a>")]
pub struct Attributes<Num> {
    /// Reversed.
    pub reversed: bool,
    /// Unit.
    pub unit: Num,
    /// Price min tick.
    pub price_tick: Num,
    /// Size min tick.
    pub size_tick: Num,
    /// Min trade size.
    pub min_size: Num,
    /// Min value.
    #[serde(default = "num_traits::Zero::zero")]
    pub min_value: Num,
}

impl<Num> InstrumentMeta<Num> {
    /// Create a new [`InstrumentMeta`].
    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, &quote)
            .expect("symbol must be valid")
            .prefer_reversed(attrs.reversed);
        Self {
            name: Str::new(name),
            inst,
            attrs,
            live: true,
            expire: None,
        }
    }

    /// Get the instrument name from the exchange.
    pub fn name(&self) -> &str {
        &self.name
    }

    /// Get name of inner type.
    pub fn smol_name(&self) -> &Str {
        &self.name
    }

    /// Get instrument.
    pub fn instrument(&self) -> &Instrument {
        &self.inst
    }

    /// Get attributes.
    pub fn attrs(&self) -> &Attributes<Num> {
        &self.attrs
    }

    /// Get if the instrument is live for trading.
    pub fn is_live(&self) -> bool {
        self.live
    }

    /// Get the expire time.
    pub fn expire(&self) -> Option<&time::OffsetDateTime> {
        self.expire.as_ref()
    }

    /// Set whether the instrument is live for trading.
    pub fn with_live(mut self, live: bool) -> Self {
        self.live = live;
        self
    }

    /// Set the expire time.
    pub fn with_expire(mut self, expire: impl Into<Option<time::OffsetDateTime>>) -> Self {
        self.expire = expire.into();
        self
    }
}

/// Instrument Stream.
pub type InstrumentStream = BoxStream<'static, Result<InstrumentMeta<Decimal>, ExchangeError>>;

/// Subscribe instruments.
#[derive(Debug, Clone)]
pub struct SubscribeInstruments {
    /// Tag.
    pub tag: Str,
}

impl SubscribeInstruments {
    /// Create a new [`SubscribeInstruments`] request.
    pub fn new(tag: impl AsRef<str>) -> Self {
        Self { tag: Str::new(tag) }
    }
}

/// Fetch instruments.
#[derive(Debug, Clone)]
pub struct FetchInstruments {
    /// Tag.
    pub tag: Str,
}

impl FetchInstruments {
    /// Create a new [`FetchInstruments`] request.
    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;
}