1use crate::static_data::CachedSecurityInfo;
2
3use super::{
4 LV2_ORDER_US_FUTURE, Lv2OrderSubDescriptor, QOT_MARKET_CC_SECURITY, QOT_RIGHT_BMP,
5 QOT_RIGHT_LEVEL1, QOT_RIGHT_LEVEL2, QOT_RIGHT_LEVEL3, QOT_RIGHT_NO, QOT_RIGHT_SF,
6 QOT_RIGHT_UNKNOWN, QotRightData, SECURITY_TYPE_CRYPTO, SECURITY_TYPE_DRVT,
7 SECURITY_TYPE_FUTURE, SECURITY_TYPE_INDEX, SG_LV2_ORDER_STOCK, SG_LV2_ORDER_STOCK_ODD_LOT,
8 US_LV2_ORDER_ARCA, US_LV2_ORDER_NASDAQ_TV, US_LV2_ORDER_OVERNIGHT,
9};
10
11fn is_hk_future_market(info: &CachedSecurityInfo) -> bool {
12 info.sec_type == SECURITY_TYPE_FUTURE && matches!(info.mkt_id, 5 | 6 | 110..=119)
13}
14
15fn is_us_future_market(info: &CachedSecurityInfo) -> bool {
16 info.sec_type == SECURITY_TYPE_FUTURE && (60..=109).contains(&info.mkt_id)
17}
18
19fn is_sg_future_market(info: &CachedSecurityInfo) -> bool {
20 info.sec_type == SECURITY_TYPE_FUTURE && (160..=179).contains(&info.mkt_id)
21}
22
23fn is_sg_security_market(info: &CachedSecurityInfo) -> bool {
24 (180..=184).contains(&info.mkt_id)
25 || (info.market == 31
26 && info.sec_type != SECURITY_TYPE_FUTURE
27 && info.sec_type != SECURITY_TYPE_DRVT)
28}
29
30fn is_jp_future_market(info: &CachedSecurityInfo) -> bool {
31 info.sec_type == SECURITY_TYPE_FUTURE && (185..=194).contains(&info.mkt_id)
32}
33
34fn is_jp_security_market(info: &CachedSecurityInfo) -> bool {
35 (830..=849).contains(&info.mkt_id)
36 || (info.market == 41
37 && info.sec_type != SECURITY_TYPE_FUTURE
38 && info.sec_type != SECURITY_TYPE_DRVT
39 && !is_jp_future_market(info)
40 && !(800..=829).contains(&info.mkt_id))
41}
42
43fn is_my_security_market(info: &CachedSecurityInfo) -> bool {
44 (1350..=1399).contains(&info.mkt_id)
45 || (info.market == 61
46 && info.sec_type != SECURITY_TYPE_FUTURE
47 && info.sec_type != SECURITY_TYPE_DRVT)
48}
49
50fn is_hk_option_market(info: &CachedSecurityInfo) -> bool {
51 info.sec_type == SECURITY_TYPE_DRVT && matches!(info.mkt_id, 7 | 8 | 570..=579)
52}
53
54fn is_us_option_market(info: &CachedSecurityInfo) -> bool {
55 info.sec_type == SECURITY_TYPE_DRVT && (41..=49).contains(&info.mkt_id)
56}
57
58fn is_hk_security_market(info: &CachedSecurityInfo) -> bool {
59 matches!(info.mkt_id, 1..=4 | 1000..=1049)
60 || (info.market == 1
61 && !is_hk_future_market(info)
62 && !is_hk_option_market(info)
63 && info.sec_type != SECURITY_TYPE_FUTURE
64 && info.sec_type != SECURITY_TYPE_DRVT)
65}
66
67pub fn snapshot_masks_hk_bmp_bid_ask(info: &CachedSecurityInfo, qr: &QotRightData) -> bool {
72 let is_hk = matches!(info.market, 1 | 2);
73 if !is_hk {
74 return false;
75 }
76
77 if is_hk_option_market(info) {
78 return qr.hk_option_qot_right == QOT_RIGHT_BMP;
79 }
80 if is_hk_future_market(info) {
81 return qr.hk_future_qot_right == QOT_RIGHT_BMP;
82 }
83 is_hk_security_market(info) && qr.hk_qot_right == QOT_RIGHT_BMP
84}
85
86fn is_us_security_market(info: &CachedSecurityInfo) -> bool {
87 matches!(info.mkt_id, 10..=29 | 1200..=1249)
88 || (info.market == 11
89 && !is_us_future_market(info)
90 && !is_us_option_market(info)
91 && info.sec_type != SECURITY_TYPE_FUTURE
92 && info.sec_type != SECURITY_TYPE_DRVT)
93}
94
95pub fn is_crypto_market(info: &CachedSecurityInfo) -> bool {
101 info.sec_type == SECURITY_TYPE_CRYPTO
102 || info.market == QOT_MARKET_CC_SECURITY
103 || (360..=459).contains(&info.mkt_id)
104}
105
106pub fn basic_qot_uses_us_pre_after_detail(info: &CachedSecurityInfo) -> bool {
114 matches!(info.mkt_id, 10..=29 | 41..=45 | 60..=109 | 1200..=1249) || info.market == 11
115}
116
117fn is_sh_market(info: &CachedSecurityInfo) -> bool {
118 matches!(info.mkt_id, 30 | 32 | 33 | 34 | 36..=40) || info.market == 21
119}
120
121fn is_sz_market(info: &CachedSecurityInfo) -> bool {
122 matches!(info.mkt_id, 31 | 35) || info.market == 22
123}
124
125fn us_future_right_for_market(qr: &QotRightData, mkt_id: u32) -> i32 {
126 match mkt_id {
127 60..=69 => qr.us_nymex_future_qot_right,
128 70..=79 => qr.us_comex_future_qot_right,
129 80..=89 => qr.us_cbot_future_qot_right,
130 90..=99 => qr.us_cme_future_qot_right,
131 100..=109 => qr.us_cboe_future_qot_right,
132 _ => QOT_RIGHT_UNKNOWN,
133 }
134}
135
136pub fn merged_lv2_order_subs_for_security(
137 info: &CachedSecurityInfo,
138 qr: &QotRightData,
139 _extended_time: bool,
140) -> Vec<Lv2OrderSubDescriptor> {
141 if is_us_future_market(info) {
142 if us_future_right_for_market(qr, info.mkt_id) == QOT_RIGHT_LEVEL2 {
143 return vec![Lv2OrderSubDescriptor {
144 lv2_type: LV2_ORDER_US_FUTURE,
145 level: 60,
146 prob2_v2: true,
147 }];
148 }
149 return vec![];
150 }
151
152 if is_sg_security_market(info) {
153 if qr.sg_stock_qot_right == QOT_RIGHT_LEVEL2 {
154 return vec![
158 Lv2OrderSubDescriptor {
159 lv2_type: SG_LV2_ORDER_STOCK,
160 level: 40,
161 prob2_v2: true,
162 },
163 Lv2OrderSubDescriptor {
164 lv2_type: SG_LV2_ORDER_STOCK_ODD_LOT,
165 level: 40,
166 prob2_v2: true,
167 },
168 ];
169 }
170 return vec![];
171 }
172
173 if !is_us_security_market(info) || info.sec_type == SECURITY_TYPE_INDEX {
174 return vec![];
175 }
176 if !matches!(qr.us_qot_right, QOT_RIGHT_LEVEL1 | QOT_RIGHT_LEVEL2) {
177 return vec![];
178 }
179
180 let mut subs = Vec::new();
181 if qr.us_lv2_arca_qot_right || qr.us_lv2_nyse_qot_right || qr.us_lv2_nasdaq_totalview_qot_right
185 {
186 subs.push(Lv2OrderSubDescriptor {
187 lv2_type: US_LV2_ORDER_OVERNIGHT,
188 level: 60,
189 prob2_v2: true,
190 });
191 }
192 if qr.us_lv2_nasdaq_totalview_qot_right {
193 subs.push(Lv2OrderSubDescriptor {
194 lv2_type: US_LV2_ORDER_NASDAQ_TV,
195 level: 60,
196 prob2_v2: false,
197 });
198 }
199 if qr.us_lv2_arca_qot_right {
200 subs.push(Lv2OrderSubDescriptor {
201 lv2_type: US_LV2_ORDER_ARCA,
202 level: 60,
203 prob2_v2: false,
204 });
205 }
206 subs
207}
208
209pub fn has_merged_lv2_order_subs_for_security(
210 info: &CachedSecurityInfo,
211 qr: &QotRightData,
212) -> bool {
213 !merged_lv2_order_subs_for_security(info, qr, true).is_empty()
214}
215
216pub fn order_book_max_depth_for_security(info: &CachedSecurityInfo, qr: &QotRightData) -> usize {
231 if is_crypto_market(info) {
232 return if qr.cc_qot_right == QOT_RIGHT_LEVEL1 {
233 40
234 } else {
235 0
236 };
237 }
238
239 if is_us_option_market(info) {
240 return if qr.us_option_qot_right == QOT_RIGHT_BMP {
241 0
242 } else {
243 1
244 };
245 }
246
247 if is_us_future_market(info) {
248 return match us_future_right_for_market(qr, info.mkt_id) {
249 QOT_RIGHT_LEVEL1 => 1,
250 QOT_RIGHT_LEVEL2 => 40,
251 _ => 0,
252 };
253 }
254
255 if is_hk_option_market(info) {
256 return if qr.hk_option_qot_right == QOT_RIGHT_BMP {
257 0
258 } else {
259 qr.hk_option_orderbook_depth.unwrap_or(0) as usize
260 };
261 }
262
263 if is_hk_future_market(info) {
264 return if qr.hk_future_qot_right == QOT_RIGHT_BMP {
265 0
266 } else {
267 qr.hk_future_orderbook_depth.unwrap_or(0) as usize
268 };
269 }
270
271 if is_hk_security_market(info) {
272 return match qr.hk_qot_right {
273 QOT_RIGHT_BMP | QOT_RIGHT_NO => 0,
274 QOT_RIGHT_LEVEL1 => 1,
275 QOT_RIGHT_LEVEL2 | QOT_RIGHT_SF => 10,
276 _ => 10,
277 };
278 }
279
280 if is_us_security_market(info) {
281 return if info.sec_type == SECURITY_TYPE_INDEX || qr.us_qot_right == QOT_RIGHT_BMP {
282 0
283 } else {
284 1
285 };
286 }
287
288 if is_sh_market(info) {
289 return if qr.sh_qot_right == QOT_RIGHT_BMP {
290 0
291 } else {
292 10
293 };
294 }
295
296 if is_sz_market(info) {
297 return if qr.sz_qot_right == QOT_RIGHT_BMP {
298 0
299 } else {
300 10
301 };
302 }
303
304 if is_sg_future_market(info) {
305 return match qr.sg_future_qot_right {
306 QOT_RIGHT_LEVEL1 => 1,
307 QOT_RIGHT_LEVEL2 => 40,
308 _ => 0,
309 };
310 }
311
312 if is_jp_future_market(info) {
313 return match qr.jp_future_qot_right {
314 QOT_RIGHT_LEVEL1 => 1,
315 QOT_RIGHT_LEVEL2 => 40,
316 _ => 0,
317 };
318 }
319
320 if is_my_security_market(info) {
321 return match qr.my_stock_qot_right {
322 QOT_RIGHT_LEVEL1 => 3,
323 QOT_RIGHT_LEVEL2 => 5,
324 QOT_RIGHT_LEVEL3 => 10,
325 _ => 0,
326 };
327 }
328
329 if is_sg_security_market(info) {
330 return match qr.sg_stock_qot_right {
331 QOT_RIGHT_LEVEL1 => 1,
332 QOT_RIGHT_LEVEL2 => 40,
333 _ => 0,
334 };
335 }
336
337 if is_jp_security_market(info) {
338 return match qr.jp_stock_qot_right {
339 QOT_RIGHT_LEVEL1 => 1,
340 QOT_RIGHT_LEVEL2 => 5,
341 QOT_RIGHT_LEVEL3 => 10,
342 _ => 0,
343 };
344 }
345
346 10
347}
348
349pub fn order_book_requires_backend_full_depth(
355 info: &CachedSecurityInfo,
356 qr: &QotRightData,
357) -> bool {
358 qr.hk_qot_right == QOT_RIGHT_SF && is_hk_security_market(info)
359}
360
361pub fn order_book_uses_backend_side_count(info: &CachedSecurityInfo, qr: &QotRightData) -> bool {
362 order_book_requires_backend_full_depth(info, qr)
363}
364
365pub fn order_book_read_uses_requested_count(info: &CachedSecurityInfo, qr: &QotRightData) -> bool {
372 order_book_uses_backend_side_count(info, qr)
373 || (qr.us_lv2_nasdaq_totalview_qot_right && is_us_security_market(info))
374}
375
376pub fn order_book_requires_accepted_lv2_push(info: &CachedSecurityInfo, qr: &QotRightData) -> bool {
384 (qr.us_lv2_nasdaq_totalview_qot_right && is_us_security_market(info)) || is_crypto_market(info)
385}