1use crate::static_data::CachedSecurityInfo;
2
3use super::{
4 JP_LV2_ORDER_STOCK, JP_LV2_ORDER_STOCK_FULL, LV2_ORDER_US_FUTURE, Lv2OrderSubDescriptor,
5 QOT_MARKET_CC_SECURITY, QOT_RIGHT_BMP, QOT_RIGHT_LEVEL1, QOT_RIGHT_LEVEL2, QOT_RIGHT_LEVEL3,
6 QOT_RIGHT_NO, QOT_RIGHT_SF, QOT_RIGHT_UNKNOWN, QotRightData, SECURITY_TYPE_CRYPTO,
7 SECURITY_TYPE_DRVT, SECURITY_TYPE_FUTURE, SECURITY_TYPE_INDEX, SG_LV2_ORDER_STOCK,
8 SG_LV2_ORDER_STOCK_ODD_LOT, 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(super) fn snapshot_masks_hk_bmp_bid_ask_impl(
72 info: &CachedSecurityInfo,
73 qr: &QotRightData,
74) -> bool {
75 let is_hk = matches!(info.market, 1 | 2);
76 if !is_hk {
77 return false;
78 }
79
80 if is_hk_option_market(info) {
81 return qr.hk_option_qot_right == QOT_RIGHT_BMP;
82 }
83 if is_hk_future_market(info) {
84 return qr.hk_future_qot_right == QOT_RIGHT_BMP;
85 }
86 is_hk_security_market(info) && qr.hk_qot_right == QOT_RIGHT_BMP
87}
88
89pub fn snapshot_masks_hk_bmp_bid_ask(info: &CachedSecurityInfo, qr: &QotRightData) -> bool {
90 snapshot_masks_hk_bmp_bid_ask_impl(info, qr)
91}
92
93fn is_us_security_market(info: &CachedSecurityInfo) -> bool {
94 matches!(info.mkt_id, 10..=29 | 1200..=1249)
95 || (info.market == 11
96 && !is_us_future_market(info)
97 && !is_us_option_market(info)
98 && info.sec_type != SECURITY_TYPE_FUTURE
99 && info.sec_type != SECURITY_TYPE_DRVT)
100}
101
102fn is_us_stock_level2_like_cpp(info: &CachedSecurityInfo, qr: &QotRightData) -> bool {
108 is_us_security_market(info)
109 && (qr.us_lv2_nasdaq_totalview_qot_right || qr.us_lv2_arca_qot_right)
110}
111
112pub fn us_lv2_order_uses_exchange_cache(info: &CachedSecurityInfo) -> bool {
118 is_us_security_market(info) && info.sec_type != SECURITY_TYPE_INDEX
119}
120
121pub fn is_crypto_market(info: &CachedSecurityInfo) -> bool {
127 info.sec_type == SECURITY_TYPE_CRYPTO
128 || info.market == QOT_MARKET_CC_SECURITY
129 || (360..=459).contains(&info.mkt_id)
130}
131
132pub fn basic_qot_uses_us_pre_after_detail(info: &CachedSecurityInfo) -> bool {
140 matches!(info.mkt_id, 10..=29 | 41..=45 | 60..=109 | 1200..=1249) || info.market == 11
141}
142
143fn is_sh_market(info: &CachedSecurityInfo) -> bool {
144 matches!(info.mkt_id, 30 | 32 | 33 | 34 | 36..=40) || info.market == 21
145}
146
147fn is_sz_market(info: &CachedSecurityInfo) -> bool {
148 matches!(info.mkt_id, 31 | 35) || info.market == 22
149}
150
151fn us_future_right_for_market(qr: &QotRightData, mkt_id: u32) -> i32 {
152 match mkt_id {
153 60..=69 => qr.us_nymex_future_qot_right,
154 70..=79 => qr.us_comex_future_qot_right,
155 80..=89 => qr.us_cbot_future_qot_right,
156 90..=99 => qr.us_cme_future_qot_right,
157 100..=109 => qr.us_cboe_future_qot_right,
158 _ => QOT_RIGHT_UNKNOWN,
159 }
160}
161
162pub(super) fn merged_lv2_order_subs_for_security_impl(
163 info: &CachedSecurityInfo,
164 qr: &QotRightData,
165 _extended_time: bool,
166) -> Vec<Lv2OrderSubDescriptor> {
167 if is_us_future_market(info) {
168 if us_future_right_for_market(qr, info.mkt_id) == QOT_RIGHT_LEVEL2 {
169 return vec![Lv2OrderSubDescriptor {
170 lv2_type: LV2_ORDER_US_FUTURE,
171 level: 60,
172 prob2_v2: true,
173 }];
174 }
175 return vec![];
176 }
177
178 if is_sg_security_market(info) {
179 if qr.sg_stock_qot_right == QOT_RIGHT_LEVEL2 {
180 return vec![
184 Lv2OrderSubDescriptor {
185 lv2_type: SG_LV2_ORDER_STOCK,
186 level: 40,
187 prob2_v2: true,
188 },
189 Lv2OrderSubDescriptor {
190 lv2_type: SG_LV2_ORDER_STOCK_ODD_LOT,
191 level: 40,
192 prob2_v2: true,
193 },
194 ];
195 }
196 return vec![];
197 }
198
199 if is_jp_security_market(info) {
200 return match qr.jp_stock_qot_right {
201 QOT_RIGHT_LEVEL2 => {
202 vec![Lv2OrderSubDescriptor {
207 lv2_type: JP_LV2_ORDER_STOCK_FULL,
208 level: 10,
209 prob2_v2: true,
210 }]
211 }
212 QOT_RIGHT_LEVEL3 => {
213 vec![Lv2OrderSubDescriptor {
216 lv2_type: JP_LV2_ORDER_STOCK_FULL,
217 level: 40,
218 prob2_v2: true,
219 }]
220 }
221 _ => vec![],
222 };
223 }
224
225 if !us_lv2_order_uses_exchange_cache(info) {
226 return vec![];
227 }
228 if !matches!(qr.us_qot_right, QOT_RIGHT_LEVEL1 | QOT_RIGHT_LEVEL2) {
229 return vec![];
230 }
231
232 let mut subs = Vec::new();
233 if qr.us_lv2_arca_qot_right || qr.us_lv2_nyse_qot_right || qr.us_lv2_nasdaq_totalview_qot_right
237 {
238 subs.push(Lv2OrderSubDescriptor {
239 lv2_type: US_LV2_ORDER_OVERNIGHT,
240 level: 60,
241 prob2_v2: true,
242 });
243 }
244 if qr.us_lv2_nasdaq_totalview_qot_right {
245 subs.push(Lv2OrderSubDescriptor {
246 lv2_type: US_LV2_ORDER_NASDAQ_TV,
247 level: 60,
248 prob2_v2: false,
249 });
250 }
251 if qr.us_lv2_arca_qot_right {
252 subs.push(Lv2OrderSubDescriptor {
253 lv2_type: US_LV2_ORDER_ARCA,
254 level: 60,
255 prob2_v2: false,
256 });
257 }
258 subs
259}
260
261pub fn merged_lv2_order_subs_for_security(
262 info: &CachedSecurityInfo,
263 qr: &QotRightData,
264 extended_time: bool,
265) -> Vec<Lv2OrderSubDescriptor> {
266 merged_lv2_order_subs_for_security_impl(info, qr, extended_time)
267}
268
269pub fn has_merged_lv2_order_subs_for_security(
270 info: &CachedSecurityInfo,
271 qr: &QotRightData,
272) -> bool {
273 !merged_lv2_order_subs_for_security_impl(info, qr, true).is_empty()
274}
275
276pub(super) fn order_book_max_depth_for_security_impl(
291 info: &CachedSecurityInfo,
292 qr: &QotRightData,
293) -> usize {
294 if is_crypto_market(info) {
295 return if qr.cc_qot_right == QOT_RIGHT_LEVEL1 {
296 40
297 } else {
298 0
299 };
300 }
301
302 if is_us_option_market(info) {
303 return if qr.us_option_qot_right == QOT_RIGHT_BMP {
304 0
305 } else {
306 1
307 };
308 }
309
310 if is_us_future_market(info) {
311 return match us_future_right_for_market(qr, info.mkt_id) {
312 QOT_RIGHT_LEVEL1 => 1,
313 QOT_RIGHT_LEVEL2 => 40,
314 _ => 0,
315 };
316 }
317
318 if is_hk_option_market(info) {
319 return if qr.hk_option_qot_right == QOT_RIGHT_BMP {
320 0
321 } else {
322 qr.hk_option_orderbook_depth.unwrap_or(0) as usize
323 };
324 }
325
326 if is_hk_future_market(info) {
327 return if qr.hk_future_qot_right == QOT_RIGHT_BMP {
328 0
329 } else {
330 qr.hk_future_orderbook_depth.unwrap_or(0) as usize
331 };
332 }
333
334 if is_hk_security_market(info) {
335 return match qr.hk_qot_right {
336 QOT_RIGHT_BMP | QOT_RIGHT_NO => 0,
337 QOT_RIGHT_LEVEL1 => 1,
338 QOT_RIGHT_LEVEL2 | QOT_RIGHT_SF => 10,
339 _ => 10,
340 };
341 }
342
343 if is_us_security_market(info) {
344 return if info.sec_type == SECURITY_TYPE_INDEX || qr.us_qot_right == QOT_RIGHT_BMP {
345 0
346 } else {
347 1
348 };
349 }
350
351 if is_sh_market(info) {
352 return if qr.sh_qot_right == QOT_RIGHT_BMP {
353 0
354 } else {
355 10
356 };
357 }
358
359 if is_sz_market(info) {
360 return if qr.sz_qot_right == QOT_RIGHT_BMP {
361 0
362 } else {
363 10
364 };
365 }
366
367 if is_sg_future_market(info) {
368 return match qr.sg_future_qot_right {
369 QOT_RIGHT_LEVEL1 => 1,
370 QOT_RIGHT_LEVEL2 => 40,
371 _ => 0,
372 };
373 }
374
375 if is_jp_future_market(info) {
376 return match qr.jp_future_qot_right {
377 QOT_RIGHT_LEVEL1 => 1,
378 QOT_RIGHT_LEVEL2 => 40,
379 _ => 0,
380 };
381 }
382
383 if is_my_security_market(info) {
384 return match qr.my_stock_qot_right {
385 QOT_RIGHT_LEVEL1 => 3,
386 QOT_RIGHT_LEVEL2 => 5,
387 QOT_RIGHT_LEVEL3 => 10,
388 _ => 0,
389 };
390 }
391
392 if is_sg_security_market(info) {
393 return match qr.sg_stock_qot_right {
394 QOT_RIGHT_LEVEL1 => 1,
395 QOT_RIGHT_LEVEL2 => 40,
396 _ => 0,
397 };
398 }
399
400 if is_jp_security_market(info) {
401 return match qr.jp_stock_qot_right {
402 QOT_RIGHT_LEVEL1 => 1,
403 QOT_RIGHT_LEVEL2 => 10,
404 QOT_RIGHT_LEVEL3 => 40,
405 _ => 0,
406 };
407 }
408
409 10
410}
411
412pub fn order_book_max_depth_for_security(info: &CachedSecurityInfo, qr: &QotRightData) -> usize {
413 order_book_max_depth_for_security_impl(info, qr)
414}
415
416pub(super) fn order_book_requires_backend_full_depth_impl(
422 info: &CachedSecurityInfo,
423 qr: &QotRightData,
424) -> bool {
425 qr.hk_qot_right == QOT_RIGHT_SF && is_hk_security_market(info)
426}
427
428pub fn order_book_requires_backend_full_depth(
429 info: &CachedSecurityInfo,
430 qr: &QotRightData,
431) -> bool {
432 order_book_requires_backend_full_depth_impl(info, qr)
433}
434
435pub fn order_book_uses_backend_side_count(info: &CachedSecurityInfo, qr: &QotRightData) -> bool {
436 order_book_requires_backend_full_depth_impl(info, qr)
437}
438
439pub(super) fn order_book_read_uses_requested_count_impl(
446 info: &CachedSecurityInfo,
447 qr: &QotRightData,
448) -> bool {
449 order_book_requires_backend_full_depth_impl(info, qr)
450 || is_us_stock_level2_like_cpp(info, qr)
451 || (matches!(qr.jp_stock_qot_right, QOT_RIGHT_LEVEL2 | QOT_RIGHT_LEVEL3)
452 && is_jp_security_market(info))
453}
454
455pub fn order_book_read_uses_requested_count(info: &CachedSecurityInfo, qr: &QotRightData) -> bool {
456 order_book_read_uses_requested_count_impl(info, qr)
457}
458
459pub(super) fn order_book_requires_accepted_lv2_push_impl(
467 info: &CachedSecurityInfo,
468 qr: &QotRightData,
469) -> bool {
470 is_us_stock_level2_like_cpp(info, qr)
471 || (matches!(qr.jp_stock_qot_right, QOT_RIGHT_LEVEL2 | QOT_RIGHT_LEVEL3)
472 && is_jp_security_market(info))
473 || is_crypto_market(info)
474}
475
476pub fn order_book_requires_accepted_lv2_push(info: &CachedSecurityInfo, qr: &QotRightData) -> bool {
477 order_book_requires_accepted_lv2_push_impl(info, qr)
478}
479
480pub fn lv2_order_uses_sg_odd_lot_cache(info: &CachedSecurityInfo, lv2_type: i32) -> bool {
481 is_sg_security_market(info) && lv2_type == SG_LV2_ORDER_STOCK_ODD_LOT as i32
482}
483
484pub fn lv2_order_uses_jp_main_cache(info: &CachedSecurityInfo, lv2_type: i32) -> bool {
485 is_jp_security_market(info)
486 && matches!(
487 lv2_type,
488 value if value == JP_LV2_ORDER_STOCK as i32
489 || value == JP_LV2_ORDER_STOCK_FULL as i32
490 )
491}