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;
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(service = "Symbology", name = "symbology", response = "SymbologySnapshot")]
23#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
24pub struct SymbologyRequest {}
25
26#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema)]
27pub struct SymbologySnapshot {
28 #[serde(flatten)]
29 pub sequence: SequenceIdAndNumber,
30 pub products: BTreeMap<Product, ProductInfo>,
31 #[serde(default)]
32 pub product_aliases: BTreeMap<AliasKind, BTreeMap<String, Product>>,
33 pub options_series: BTreeMap<OptionsSeries, OptionsSeriesInfo>,
34 pub execution_info:
35 BTreeMap<TradableProduct, BTreeMap<ExecutionVenue, ExecutionInfo>>,
36}
37
38impl SymbologySnapshot {
39 pub fn exchange_symbols(
40 &self,
41 venue: &ExecutionVenue,
42 ) -> BTreeMap<TradableProduct, String> {
43 let mut map = BTreeMap::new();
44 for (symbol, infos) in &self.execution_info {
45 if let Some(exchange_symbol) =
46 infos.get(venue).and_then(|info| info.exchange_symbol.as_ref())
47 {
48 map.insert(symbol.clone(), exchange_symbol.clone());
49 }
50 }
51 map
52 }
53}
54
55#[skip_serializing_none]
56#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema)]
57pub struct SymbologyUpdate {
58 #[serde(flatten)]
59 pub sequence: SequenceIdAndNumber,
60 #[serde(default)]
61 pub products: Option<SnapshotOrUpdate<Product, ProductInfo>>,
62 #[serde(default)]
63 pub product_aliases:
64 Option<SnapshotOrUpdate<AliasKind, SnapshotOrUpdate<String, Product>>>,
65 #[serde(default)]
66 pub options_series: Option<SnapshotOrUpdate<OptionsSeries, OptionsSeriesInfo>>,
67 #[serde(default)]
68 pub execution_info: Option<
69 SnapshotOrUpdate<
70 TradableProduct,
71 SnapshotOrUpdate<ExecutionVenue, ExecutionInfo>,
72 >,
73 >,
74}
75
76#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
77#[serde(untagged)]
78pub enum SnapshotOrUpdate<K: Eq + Ord, V> {
79 Snapshot { snapshot: BTreeMap<K, V> },
80 Update { updates: Vec<(K, Option<V>)> },
81}
82
83impl<K: Eq + Ord, V> From<BTreeMap<K, V>> for SnapshotOrUpdate<K, V> {
84 fn from(map: BTreeMap<K, V>) -> Self {
85 SnapshotOrUpdate::Snapshot { snapshot: map }
86 }
87}
88
89impl<K: Eq + Ord, V> SnapshotOrUpdate<K, V> {
90 pub fn apply(self, map: &mut BTreeMap<K, V>) {
91 match self {
92 Self::Snapshot { snapshot } => {
93 *map = snapshot;
94 }
95 Self::Update { updates } => {
96 for (k, v) in updates {
97 if let Some(v) = v {
98 map.insert(k, v);
99 } else {
100 map.remove(&k);
101 }
102 }
103 }
104 }
105 }
106}
107
108impl<K0: Eq + Ord, K1: Eq + Ord, V> From<BTreeMap<K0, BTreeMap<K1, V>>>
109 for SnapshotOrUpdate<K0, SnapshotOrUpdate<K1, V>>
110{
111 fn from(map: BTreeMap<K0, BTreeMap<K1, V>>) -> Self {
112 SnapshotOrUpdate::Snapshot {
113 snapshot: map
114 .into_iter()
115 .map(|(k, v)| (k, SnapshotOrUpdate::Snapshot { snapshot: v }))
116 .collect(),
117 }
118 }
119}
120
121impl<K0: Eq + Ord, K1: Eq + Ord, V> SnapshotOrUpdate<K0, SnapshotOrUpdate<K1, V>> {
122 pub fn apply2(self, map: &mut BTreeMap<K0, BTreeMap<K1, V>>) {
123 match self {
124 Self::Snapshot { snapshot } => {
125 map.clear();
126 for (k, t) in snapshot {
127 match t {
128 SnapshotOrUpdate::Snapshot { snapshot } => {
129 map.insert(k, snapshot);
130 }
131 u @ SnapshotOrUpdate::Update { .. } => {
132 let mut v = BTreeMap::new();
133 u.apply(&mut v);
134 map.insert(k, v);
135 }
136 }
137 }
138 }
139 Self::Update { updates } => {
140 for (k, t) in updates {
141 match t {
142 Some(SnapshotOrUpdate::Snapshot { snapshot }) => {
143 map.insert(k, snapshot);
144 }
145 Some(u @ SnapshotOrUpdate::Update { .. }) => {
146 let v = map.entry(k).or_default();
147 u.apply(v);
148 }
149 None => {
150 map.remove(&k);
151 }
152 }
153 }
154 }
155 }
156 }
157}
158
159#[grpc(package = "json.architect")]
160#[grpc(
161 service = "Symbology",
162 name = "subscribe_symbology",
163 response = "SymbologyUpdate",
164 server_streaming
165)]
166#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
167pub struct SubscribeSymbology {}
168
169#[grpc(package = "json.architect")]
170#[grpc(
171 service = "Symbology",
172 name = "upload_symbology",
173 response = "UploadSymbologyResponse"
174)]
175#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
176pub struct UploadSymbologyRequest {
177 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
178 pub products: BTreeMap<Product, ProductInfo>,
179 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
180 pub product_aliases: BTreeMap<AliasKind, BTreeMap<String, Product>>,
181 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
182 pub options_series: BTreeMap<OptionsSeries, OptionsSeriesInfo>,
183 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
184 pub execution_info:
185 BTreeMap<TradableProduct, BTreeMap<ExecutionVenue, ExecutionInfo>>,
186}
187
188#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
189pub struct UploadSymbologyResponse {}
190
191#[grpc(package = "json.architect")]
193#[grpc(
194 service = "Symbology",
195 name = "prune_expired_symbols",
196 response = "PruneExpiredSymbolsResponse"
197)]
198#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
199pub struct PruneExpiredSymbolsRequest {
200 pub cutoff: Option<i64>,
203}
204
205impl PruneExpiredSymbolsRequest {
206 pub fn new(cutoff: Option<DateTime<Utc>>) -> Self {
207 Self { cutoff: cutoff.map(|dt| dt.timestamp()) }
208 }
209}
210
211#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
212pub struct PruneExpiredSymbolsResponse {}