rusty_feeder/exchange/coinbase/data/
orderbook.rs1use rust_decimal::Decimal;
2use serde::{Deserialize, Serialize};
3use smallvec::SmallVec;
4use smartstring::alias::String;
5
6type PriceLevel = [String; 2]; #[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct Level2Snapshot {
11 #[serde(rename = "type")]
13 pub message_type: String,
14 pub product_id: String,
16 pub bids: SmallVec<[PriceLevel; 32]>,
18 pub asks: SmallVec<[PriceLevel; 32]>,
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct Level2Update {
25 #[serde(rename = "type")]
27 pub message_type: String,
28 pub product_id: String,
30 pub time: String,
32 pub changes: SmallVec<[Level2Change; 32]>,
34}
35
36pub type Level2Change = [String; 3];
38
39#[derive(Debug, Clone)]
41pub struct ParsedLevel2Update {
42 pub product_id: String,
44 pub time: String,
46 pub bids: SmallVec<[(Decimal, Decimal); 32]>,
48 pub asks: SmallVec<[(Decimal, Decimal); 32]>,
50}
51
52impl ParsedLevel2Update {
53 #[must_use]
55 pub fn from_update(update: Level2Update) -> Self {
56 let mut bids = SmallVec::with_capacity(20);
57 let mut asks = SmallVec::with_capacity(20);
58
59 for change in update.changes {
60 if change.len() != 3 {
61 continue;
62 }
63
64 let side = &change[0];
65 let price = match change[1].parse::<Decimal>() {
66 Ok(p) => p,
67 Err(_) => continue,
68 };
69 let size = match change[2].parse::<Decimal>() {
70 Ok(s) => s,
71 Err(_) => continue,
72 };
73
74 match side.as_str() {
75 "buy" => bids.push((price, size)),
76 "sell" => asks.push((price, size)),
77 _ => continue,
78 }
79 }
80
81 Self {
82 product_id: update.product_id,
83 time: update.time,
84 bids,
85 asks,
86 }
87 }
88}
89
90#[derive(Debug, Clone)]
92pub struct ParsedLevel2Snapshot {
93 pub product_id: String,
95 pub bids: SmallVec<[(Decimal, Decimal); 32]>,
97 pub asks: SmallVec<[(Decimal, Decimal); 32]>,
99}
100
101impl ParsedLevel2Snapshot {
102 #[must_use]
104 pub fn from_snapshot(snapshot: Level2Snapshot) -> Self {
105 let bids = snapshot
106 .bids
107 .iter()
108 .filter_map(|level| {
109 if level.len() != 2 {
110 return None;
111 }
112 let price = level[0].parse::<Decimal>().ok()?;
113 let size = level[1].parse::<Decimal>().ok()?;
114 Some((price, size))
115 })
116 .collect();
117
118 let asks = snapshot
119 .asks
120 .iter()
121 .filter_map(|level| {
122 if level.len() != 2 {
123 return None;
124 }
125 let price = level[0].parse::<Decimal>().ok()?;
126 let size = level[1].parse::<Decimal>().ok()?;
127 Some((price, size))
128 })
129 .collect();
130
131 Self {
132 product_id: snapshot.product_id,
133 bids,
134 asks,
135 }
136 }
137}