1use super::*;
2use crate::SequenceIdAndNumber;
3use chrono::{DateTime, Utc};
4use derive::grpc;
5use schemars::JsonSchema;
6use serde::{Deserialize, Serialize};
7use serde_with::skip_serializing_none;
8use std::collections::{BTreeMap, BTreeSet};
9
10#[grpc(package = "json.architect")]
12#[grpc(service = "Symbology", name = "symbols", response = "SymbolsResponse")]
13#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
14pub struct SymbolsRequest {}
15
16#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
17pub struct SymbolsResponse {
18 pub symbols: Vec<String>,
19}
20
21#[grpc(package = "json.architect")]
22#[grpc(
23 service = "Symbology",
24 name = "execution_info",
25 response = "ExecutionInfoResponse"
26)]
27#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
28pub struct ExecutionInfoRequest {
29 pub symbol: String,
30 pub execution_venue: Option<ExecutionVenue>,
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
34pub struct ExecutionInfoResponse {
35 pub execution_info: BTreeMap<ExecutionVenue, ExecutionInfo>,
36}
37
38#[grpc(package = "json.architect")]
39#[grpc(
40 service = "Symbology",
41 name = "futures_series",
42 response = "FuturesSeriesResponse"
43)]
44#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
45pub struct FuturesSeriesRequest {
46 pub series_symbol: String,
47 #[serde(default)]
48 pub include_expired: bool,
49}
50
51#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
52pub struct FuturesSeriesResponse {
53 pub futures: Vec<Product>,
54}
55
56#[grpc(package = "json.architect")]
57#[grpc(service = "Symbology", name = "symbology", response = "SymbologySnapshot")]
58#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
59pub struct SymbologyRequest {}
60
61#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema)]
62pub struct SymbologySnapshot {
63 #[serde(flatten)]
64 pub sequence: SequenceIdAndNumber,
65 pub products: BTreeMap<Product, ProductInfo>,
66 #[serde(default)]
67 pub product_aliases: BTreeMap<AliasKind, BTreeMap<String, Product>>,
68 #[serde(default)]
69 pub product_catalog: BTreeMap<ExecutionVenue, BTreeMap<String, ProductCatalogInfo>>,
70 pub options_series: BTreeMap<OptionsSeries, OptionsSeriesInfo>,
71 pub execution_info:
72 BTreeMap<TradableProduct, BTreeMap<ExecutionVenue, ExecutionInfo>>,
73}
74
75impl SymbologySnapshot {
76 pub fn exchange_symbols(
77 &self,
78 venue: &ExecutionVenue,
79 ) -> BTreeMap<TradableProduct, String> {
80 let mut map = BTreeMap::new();
81 for (symbol, infos) in &self.execution_info {
82 if let Some(exchange_symbol) =
83 infos.get(venue).and_then(|info| info.exchange_symbol.as_ref())
84 {
85 map.insert(symbol.clone(), exchange_symbol.clone());
86 }
87 }
88 map
89 }
90
91 pub fn exchange_symbol(
92 &self,
93 venue: &str,
94 symbol: &TradableProduct,
95 ) -> Option<&String> {
96 self.execution_info.get(symbol).and_then(|infos| {
97 infos.get(venue).and_then(|info| info.exchange_symbol.as_ref())
98 })
99 }
100
101 pub fn filter_venue(mut self, venue: &ExecutionVenue) -> Self {
102 let mut out = Self::default();
103 let mut products = BTreeSet::default();
104 for (symbol, infos) in self.execution_info {
105 for (venue_key, info) in infos {
106 if &venue_key != venue {
107 continue;
108 }
109 out.execution_info
110 .entry(symbol.clone())
111 .or_default()
112 .insert(venue.clone(), info);
113 products.insert(symbol.base());
114 if let Some(quote) = symbol.quote() {
115 products.insert(quote);
116 }
117 }
118 }
119 for (alias_kind, alias_map) in self.product_aliases {
120 for (alias, product) in alias_map {
121 if products.contains(&product) {
122 out.product_aliases
123 .entry(alias_kind)
124 .or_default()
125 .insert(alias, product);
126 }
127 }
128 }
129 for product in products {
130 if let Some(info) = self.products.remove(&product) {
131 out.products.insert(product, info);
132 }
133 }
134 out
135 }
136}
137
138#[skip_serializing_none]
139#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema)]
140pub struct SymbologyUpdate {
141 #[serde(flatten)]
142 pub sequence: SequenceIdAndNumber,
143 #[serde(default)]
144 pub products: Option<SnapshotOrUpdate<Product, ProductInfo>>,
145 #[serde(default)]
146 pub product_aliases:
147 Option<SnapshotOrUpdate<AliasKind, SnapshotOrUpdate<String, Product>>>,
148 #[serde(default)]
149 pub product_catalog: Option<
150 SnapshotOrUpdate<ExecutionVenue, SnapshotOrUpdate<String, ProductCatalogInfo>>,
151 >,
152 #[serde(default)]
153 pub options_series: Option<SnapshotOrUpdate<OptionsSeries, OptionsSeriesInfo>>,
154 #[serde(default)]
155 pub execution_info: Option<
156 SnapshotOrUpdate<
157 TradableProduct,
158 SnapshotOrUpdate<ExecutionVenue, ExecutionInfo>,
159 >,
160 >,
161}
162
163#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
164#[serde(untagged)]
165pub enum SnapshotOrUpdate<K: Eq + Ord, V> {
166 Snapshot { snapshot: BTreeMap<K, V> },
167 Update { updates: Vec<(K, Option<V>)> },
168}
169
170impl<K: Eq + Ord, V> From<BTreeMap<K, V>> for SnapshotOrUpdate<K, V> {
171 fn from(map: BTreeMap<K, V>) -> Self {
172 SnapshotOrUpdate::Snapshot { snapshot: map }
173 }
174}
175
176impl<K: Eq + Ord, V> SnapshotOrUpdate<K, V> {
177 pub fn apply(self, map: &mut BTreeMap<K, V>) {
178 match self {
179 Self::Snapshot { snapshot } => {
180 *map = snapshot;
181 }
182 Self::Update { updates } => {
183 for (k, v) in updates {
184 if let Some(v) = v {
185 map.insert(k, v);
186 } else {
187 map.remove(&k);
188 }
189 }
190 }
191 }
192 }
193}
194
195impl<K0: Eq + Ord, K1: Eq + Ord, V> From<BTreeMap<K0, BTreeMap<K1, V>>>
196 for SnapshotOrUpdate<K0, SnapshotOrUpdate<K1, V>>
197{
198 fn from(map: BTreeMap<K0, BTreeMap<K1, V>>) -> Self {
199 SnapshotOrUpdate::Snapshot {
200 snapshot: map
201 .into_iter()
202 .map(|(k, v)| (k, SnapshotOrUpdate::Snapshot { snapshot: v }))
203 .collect(),
204 }
205 }
206}
207
208impl<K0: Eq + Ord, K1: Eq + Ord, V> SnapshotOrUpdate<K0, SnapshotOrUpdate<K1, V>> {
209 pub fn apply2(self, map: &mut BTreeMap<K0, BTreeMap<K1, V>>) {
210 match self {
211 Self::Snapshot { snapshot } => {
212 map.clear();
213 for (k, t) in snapshot {
214 match t {
215 SnapshotOrUpdate::Snapshot { snapshot } => {
216 map.insert(k, snapshot);
217 }
218 u @ SnapshotOrUpdate::Update { .. } => {
219 let mut v = BTreeMap::new();
220 u.apply(&mut v);
221 map.insert(k, v);
222 }
223 }
224 }
225 }
226 Self::Update { updates } => {
227 for (k, t) in updates {
228 match t {
229 Some(SnapshotOrUpdate::Snapshot { snapshot }) => {
230 map.insert(k, snapshot);
231 }
232 Some(u @ SnapshotOrUpdate::Update { .. }) => {
233 let v = map.entry(k).or_default();
234 u.apply(v);
235 }
236 None => {
237 map.remove(&k);
238 }
239 }
240 }
241 }
242 }
243 }
244}
245
246#[grpc(package = "json.architect")]
247#[grpc(
248 service = "Symbology",
249 name = "subscribe_symbology",
250 response = "SymbologyUpdate",
251 server_streaming
252)]
253#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
254pub struct SubscribeSymbology {}
255
256#[grpc(package = "json.architect")]
257#[grpc(
258 service = "Symbology",
259 name = "upload_symbology",
260 response = "UploadSymbologyResponse"
261)]
262#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
263pub struct UploadSymbologyRequest {
264 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
265 pub products: BTreeMap<Product, ProductInfo>,
266 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
267 pub product_aliases: BTreeMap<AliasKind, BTreeMap<String, Product>>,
268 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
269 pub options_series: BTreeMap<OptionsSeries, OptionsSeriesInfo>,
270 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
271 pub execution_info:
272 BTreeMap<TradableProduct, BTreeMap<ExecutionVenue, ExecutionInfo>>,
273}
274
275#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
276pub struct UploadSymbologyResponse {}
277
278#[grpc(package = "json.architect")]
280#[grpc(
281 service = "Symbology",
282 name = "prune_expired_symbols",
283 response = "PruneExpiredSymbolsResponse"
284)]
285#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
286pub struct PruneExpiredSymbolsRequest {
287 pub cutoff: Option<i64>,
290}
291
292impl PruneExpiredSymbolsRequest {
293 pub fn new(cutoff: Option<DateTime<Utc>>) -> Self {
294 Self { cutoff: cutoff.map(|dt| dt.timestamp()) }
295 }
296}
297
298#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
299pub struct PruneExpiredSymbolsResponse {}
300
301#[grpc(package = "json.architect")]
302#[grpc(
303 service = "Symbology",
304 name = "upload_product_catalog",
305 response = "UploadProductCatalogResponse"
306)]
307#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
308pub struct UploadProductCatalogRequest {
309 pub exchange: ExecutionVenue,
310 pub product_catalog: Vec<ProductCatalogInfo>,
311}
312
313#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
314pub struct UploadProductCatalogResponse {}
315
316#[grpc(package = "json.architect")]
317#[grpc(
318 service = "Symbology",
319 name = "download_product_catalog",
320 response = "DownloadProductCatalogResponse"
321)]
322#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
323pub struct DownloadProductCatalogRequest {
324 pub exchange: ExecutionVenue,
325}
326
327#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
328pub struct DownloadProductCatalogResponse {
329 pub product_catalog: Vec<ProductCatalogInfo>,
330}