Skip to main content

rustrade_data/exchange/gateio/spot/
trade.rs

1use super::super::message::GateioMessage;
2use crate::{
3    Identifier,
4    event::{MarketEvent, MarketIter},
5    exchange::ExchangeSub,
6    subscription::trade::PublicTrade,
7};
8use chrono::{DateTime, Utc};
9use rustrade_instrument::{Side, exchange::ExchangeId};
10use rustrade_integration::subscription::SubscriptionId;
11use serde::{Deserialize, Serialize};
12use smol_str::format_smolstr;
13
14/// Terse type alias for an [`GateioSpot`](super::GateioSpot) real-time trades WebSocket message.
15pub type GateioSpotTrade = GateioMessage<GateioSpotTradeInner>;
16
17/// [`GateioSpot`](super::GateioSpot) real-time trade WebSocket message.
18///
19/// ### Raw Payload Examples
20/// See docs: <https://www.gate.io/docs/developers/apiv4/ws/en/#public-trades-channel>
21/// ```json
22/// {
23///   "id": 309143071,
24///   "create_time": 1606292218,
25///   "create_time_ms": "1606292218213.4578",
26///   "side": "sell",
27///   "currency_pair": "GT_USDT",
28///   "amount": "16.4700000000",
29///   "price": "0.4705000000"
30/// }
31/// ```
32#[derive(Clone, PartialEq, PartialOrd, Debug, Deserialize, Serialize)]
33pub struct GateioSpotTradeInner {
34    #[serde(rename = "currency_pair")]
35    pub market: String,
36    #[serde(
37        rename = "create_time_ms",
38        deserialize_with = "rustrade_integration::serde::de::de_str_f64_epoch_ms_as_datetime_utc"
39    )]
40    pub time: DateTime<Utc>,
41    pub id: u64,
42    #[serde(deserialize_with = "rustrade_integration::serde::de::de_str")]
43    pub price: f64,
44
45    #[serde(
46        alias = "size",
47        deserialize_with = "rustrade_integration::serde::de::de_str"
48    )]
49    pub amount: f64,
50
51    /// Taker [`Side`] of the trade.
52    pub side: Side,
53}
54
55impl Identifier<Option<SubscriptionId>> for GateioSpotTrade {
56    fn id(&self) -> Option<SubscriptionId> {
57        Some(ExchangeSub::from((&self.channel, &self.data.market)).id())
58    }
59}
60
61impl<InstrumentKey> From<(ExchangeId, InstrumentKey, GateioSpotTrade)>
62    for MarketIter<InstrumentKey, PublicTrade>
63{
64    fn from(
65        (exchange_id, instrument, trade): (ExchangeId, InstrumentKey, GateioSpotTrade),
66    ) -> Self {
67        Self(vec![Ok(MarketEvent {
68            time_exchange: trade.data.time,
69            time_received: Utc::now(),
70            exchange: exchange_id,
71            instrument,
72            kind: PublicTrade {
73                id: format_smolstr!("{}", trade.data.id),
74                price: trade.data.price,
75                amount: trade.data.amount,
76                side: trade.data.side,
77            },
78        })])
79    }
80}
81
82#[cfg(test)]
83#[allow(clippy::unwrap_used)] // Test code: panics on bad input are acceptable
84mod tests {
85    use super::*;
86
87    mod de {
88        use super::*;
89
90        #[test]
91        fn test_gateio_message_futures_trade() {
92            let input = r#"
93            {
94                "time": 1606292218,
95                "time_ms": 1606292218231,
96                "channel": "spot.trades",
97                "event": "update",
98                "result": {
99                    "id": 309143071,
100                    "create_time": 1606292218,
101                    "create_time_ms": "1606292218213.4578",
102                    "side": "sell",
103                    "currency_pair": "GT_USDT",
104                    "amount": "16.4700000000",
105                    "price": "0.4705000000"
106                }
107            }
108            "#;
109            serde_json::from_str::<GateioSpotTrade>(input).unwrap();
110        }
111    }
112}