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