CppTrader  1.0.4.0
C++ Trader
itch_handler.cpp
Go to the documentation of this file.
1 
10 
11 #include <cassert>
12 
13 namespace CppTrader {
14 namespace ITCH {
15 
16 bool ITCHHandler::Process(void* buffer, size_t size)
17 {
18  size_t index = 0;
19  uint8_t* data = (uint8_t*)buffer;
20 
21  while (index < size)
22  {
23  if (_size == 0)
24  {
25  size_t remaining = size - index;
26 
27  // Collect message size into the cache
28  if (((_cache.size() == 0) && (remaining < 3)) || (_cache.size() == 1))
29  {
30  _cache.push_back(data[index++]);
31  continue;
32  }
33 
34  // Read a new message size
35  uint16_t message_size;
36  if (_cache.empty())
37  {
38  // Read the message size directly from the input buffer
39  index += CppCommon::Endian::ReadBigEndian(&data[index], message_size);
40  }
41  else
42  {
43  // Read the message size from the cache
44  CppCommon::Endian::ReadBigEndian(_cache.data(), message_size);
45 
46  // Clear the cache
47  _cache.clear();
48  }
49  _size = message_size;
50  }
51 
52  // Read a new message
53  if (_size > 0)
54  {
55  size_t remaining = size - index;
56 
57  // Complete or place the message into the cache
58  if (!_cache.empty())
59  {
60  size_t tail = _size - _cache.size();
61  if (tail > remaining)
62  tail = remaining;
63  _cache.insert(_cache.end(), &data[index], &data[index + tail]);
64  index += tail;
65  if (_cache.size() < _size)
66  continue;
67  }
68  else if (_size > remaining)
69  {
70  _cache.reserve(_size);
71  _cache.insert(_cache.end(), &data[index], &data[index + remaining]);
72  index += remaining;
73  continue;
74  }
75 
76  // Process the current message
77  if (_cache.empty())
78  {
79  // Process the current message size directly from the input buffer
80  if (!ProcessMessage(&data[index], _size))
81  return false;
82  index += _size;
83  }
84  else
85  {
86  // Process the current message size directly from the cache
87  if (!ProcessMessage(_cache.data(), _size))
88  return false;
89 
90  // Clear the cache
91  _cache.clear();
92  }
93 
94  // Process the next message
95  _size = 0;
96  }
97  }
98 
99  return true;
100 }
101 
102 bool ITCHHandler::ProcessMessage(void* buffer, size_t size)
103 {
104  // Message is empty
105  if (size == 0)
106  return false;
107 
108  uint8_t* data = (uint8_t*)buffer;
109 
110  switch (*data)
111  {
112  case 'S':
113  return ProcessSystemEventMessage(data, size);
114  case 'R':
115  return ProcessStockDirectoryMessage(data, size);
116  case 'H':
117  return ProcessStockTradingActionMessage(data, size);
118  case 'Y':
119  return ProcessRegSHOMessage(data, size);
120  case 'L':
121  return ProcessMarketParticipantPositionMessage(data, size);
122  case 'V':
123  return ProcessMWCBDeclineMessage(data, size);
124  case 'W':
125  return ProcessMWCBStatusMessage(data, size);
126  case 'K':
127  return ProcessIPOQuotingMessage(data, size);
128  case 'A':
129  return ProcessAddOrderMessage(data, size);
130  case 'F':
131  return ProcessAddOrderMPIDMessage(data, size);
132  case 'E':
133  return ProcessOrderExecutedMessage(data, size);
134  case 'C':
135  return ProcessOrderExecutedWithPriceMessage(data, size);
136  case 'X':
137  return ProcessOrderCancelMessage(data, size);
138  case 'D':
139  return ProcessOrderDeleteMessage(data, size);
140  case 'U':
141  return ProcessOrderReplaceMessage(data, size);
142  case 'P':
143  return ProcessTradeMessage(data, size);
144  case 'Q':
145  return ProcessCrossTradeMessage(data, size);
146  case 'B':
147  return ProcessBrokenTradeMessage(data, size);
148  case 'I':
149  return ProcessNOIIMessage(data, size);
150  case 'N':
151  return ProcessRPIIMessage(data, size);
152  case 'J':
153  return ProcessLULDAuctionCollarMessage(data, size);
154  default:
155  return ProcessUnknownMessage(data, size);
156  }
157 }
158 
160 {
161  _size = 0;
162  _cache.clear();
163 }
164 
165 bool ITCHHandler::ProcessSystemEventMessage(void* buffer, size_t size)
166 {
167  assert((size == 12) && "Invalid size of the ITCH message type 'S'");
168  if (size != 12)
169  return false;
170 
171  uint8_t* data = (uint8_t*)buffer;
172 
173  SystemEventMessage message;
174  message.Type = *data++;
175  data += CppCommon::Endian::ReadBigEndian(data, message.StockLocate);
176  data += CppCommon::Endian::ReadBigEndian(data, message.TrackingNumber);
177  data += ReadTimestamp(data, message.Timestamp);
178  message.EventCode = *data++;
179 
180  return onMessage(message);
181 }
182 
183 bool ITCHHandler::ProcessStockDirectoryMessage(void* buffer, size_t size)
184 {
185  assert((size == 39) && "Invalid size of the ITCH message type 'R'");
186  if (size != 39)
187  return false;
188 
189  uint8_t* data = (uint8_t*)buffer;
190 
191  StockDirectoryMessage message;
192  message.Type = *data++;
193  data += CppCommon::Endian::ReadBigEndian(data, message.StockLocate);
194  data += CppCommon::Endian::ReadBigEndian(data, message.TrackingNumber);
195  data += ReadTimestamp(data, message.Timestamp);
196  data += ReadString(data, message.Stock);
197  message.MarketCategory = *data++;
198  message.FinancialStatusIndicator = *data++;
199  data += CppCommon::Endian::ReadBigEndian(data, message.RoundLotSize);
200  message.RoundLotsOnly = *data++;
201  message.IssueClassification = *data++;
202  data += ReadString(data, message.IssueSubType);
203  message.Authenticity = *data++;
204  message.ShortSaleThresholdIndicator = *data++;
205  message.IPOFlag = *data++;
206  message.LULDReferencePriceTier = *data++;
207  message.ETPFlag = *data++;
208  data += CppCommon::Endian::ReadBigEndian(data, message.ETPLeverageFactor);
209  message.InverseIndicator = *data++;
210 
211  return onMessage(message);
212 }
213 
214 bool ITCHHandler::ProcessStockTradingActionMessage(void* buffer, size_t size)
215 {
216  assert((size == 25) && "Invalid size of the ITCH message type 'H'");
217  if (size != 25)
218  return false;
219 
220  uint8_t* data = (uint8_t*)buffer;
221 
222  StockTradingActionMessage message;
223  message.Type = *data++;
224  data += CppCommon::Endian::ReadBigEndian(data, message.StockLocate);
225  data += CppCommon::Endian::ReadBigEndian(data, message.TrackingNumber);
226  data += ReadTimestamp(data, message.Timestamp);
227  data += ReadString(data, message.Stock);
228  message.TradingState = *data++;
229  message.Reserved = *data++;
230  message.Reason = *data++;
231 
232  return onMessage(message);
233 }
234 
235 bool ITCHHandler::ProcessRegSHOMessage(void* buffer, size_t size)
236 {
237  assert((size == 20) && "Invalid size of the ITCH message type 'Y'");
238  if (size != 20)
239  return false;
240 
241  uint8_t* data = (uint8_t*)buffer;
242 
243  RegSHOMessage message;
244  message.Type = *data++;
245  data += CppCommon::Endian::ReadBigEndian(data, message.StockLocate);
246  data += CppCommon::Endian::ReadBigEndian(data, message.TrackingNumber);
247  data += ReadTimestamp(data, message.Timestamp);
248  data += ReadString(data, message.Stock);
249  message.RegSHOAction = *data++;
250 
251  return onMessage(message);
252 }
253 
254 bool ITCHHandler::ProcessMarketParticipantPositionMessage(void* buffer, size_t size)
255 {
256  assert((size == 26) && "Invalid size of the ITCH message type 'L'");
257  if (size != 26)
258  return false;
259 
260  uint8_t* data = (uint8_t*)buffer;
261 
262  MarketParticipantPositionMessage message;
263  message.Type = *data++;
264  data += CppCommon::Endian::ReadBigEndian(data, message.StockLocate);
265  data += CppCommon::Endian::ReadBigEndian(data, message.TrackingNumber);
266  data += ReadTimestamp(data, message.Timestamp);
267  data += ReadString(data, message.MPID);
268  data += ReadString(data, message.Stock);
269  message.PrimaryMarketMaker = *data++;
270  message.MarketMakerMode = *data++;
271  message.MarketParticipantState = *data++;
272 
273  return onMessage(message);
274 }
275 
276 bool ITCHHandler::ProcessMWCBDeclineMessage(void* buffer, size_t size)
277 {
278  assert((size == 35) && "Invalid size of the ITCH message type 'V'");
279  if (size != 35)
280  return false;
281 
282  uint8_t* data = (uint8_t*)buffer;
283 
284  MWCBDeclineMessage message;
285  message.Type = *data++;
286  data += CppCommon::Endian::ReadBigEndian(data, message.StockLocate);
287  data += CppCommon::Endian::ReadBigEndian(data, message.TrackingNumber);
288  data += ReadTimestamp(data, message.Timestamp);
289  data += CppCommon::Endian::ReadBigEndian(data, message.Level1);
290  data += CppCommon::Endian::ReadBigEndian(data, message.Level2);
291  data += CppCommon::Endian::ReadBigEndian(data, message.Level3);
292 
293  return onMessage(message);
294 }
295 
296 bool ITCHHandler::ProcessMWCBStatusMessage(void* buffer, size_t size)
297 {
298  assert((size == 12) && "Invalid size of the ITCH message type 'W'");
299  if (size != 12)
300  return false;
301 
302  uint8_t* data = (uint8_t*)buffer;
303 
304  MWCBStatusMessage message;
305  message.Type = *data++;
306  data += CppCommon::Endian::ReadBigEndian(data, message.StockLocate);
307  data += CppCommon::Endian::ReadBigEndian(data, message.TrackingNumber);
308  data += ReadTimestamp(data, message.Timestamp);
309  message.BreachedLevel = *data++;
310 
311  return onMessage(message);
312 }
313 
314 bool ITCHHandler::ProcessIPOQuotingMessage(void* buffer, size_t size)
315 {
316  assert((size == 28) && "Invalid size of the ITCH message type 'W'");
317  if (size != 28)
318  return false;
319 
320  uint8_t* data = (uint8_t*)buffer;
321 
322  IPOQuotingMessage message;
323  message.Type = *data++;
324  data += CppCommon::Endian::ReadBigEndian(data, message.StockLocate);
325  data += CppCommon::Endian::ReadBigEndian(data, message.TrackingNumber);
326  data += ReadTimestamp(data, message.Timestamp);
327  data += ReadString(data, message.Stock);
328  data += CppCommon::Endian::ReadBigEndian(data, message.IPOReleaseTime);
329  message.IPOReleaseQualifier = *data++;
330  data += CppCommon::Endian::ReadBigEndian(data, message.IPOPrice);
331 
332  return onMessage(message);
333 }
334 
335 bool ITCHHandler::ProcessAddOrderMessage(void* buffer, size_t size)
336 {
337  assert((size == 36) && "Invalid size of the ITCH message type 'A'");
338  if (size != 36)
339  return false;
340 
341  uint8_t* data = (uint8_t*)buffer;
342 
343  AddOrderMessage message;
344  message.Type = *data++;
345  data += CppCommon::Endian::ReadBigEndian(data, message.StockLocate);
346  data += CppCommon::Endian::ReadBigEndian(data, message.TrackingNumber);
347  data += ReadTimestamp(data, message.Timestamp);
348  data += CppCommon::Endian::ReadBigEndian(data, message.OrderReferenceNumber);
349  message.BuySellIndicator = *data++;
350  data += CppCommon::Endian::ReadBigEndian(data, message.Shares);
351  data += ReadString(data, message.Stock);
352  data += CppCommon::Endian::ReadBigEndian(data, message.Price);
353 
354  return onMessage(message);
355 }
356 
357 bool ITCHHandler::ProcessAddOrderMPIDMessage(void* buffer, size_t size)
358 {
359  assert((size == 40) && "Invalid size of the ITCH message type 'F'");
360  if (size != 40)
361  return false;
362 
363  uint8_t* data = (uint8_t*)buffer;
364 
365  AddOrderMPIDMessage message;
366  message.Type = *data++;
367  data += CppCommon::Endian::ReadBigEndian(data, message.StockLocate);
368  data += CppCommon::Endian::ReadBigEndian(data, message.TrackingNumber);
369  data += ReadTimestamp(data, message.Timestamp);
370  data += CppCommon::Endian::ReadBigEndian(data, message.OrderReferenceNumber);
371  message.BuySellIndicator = *data++;
372  data += CppCommon::Endian::ReadBigEndian(data, message.Shares);
373  data += ReadString(data, message.Stock);
374  data += CppCommon::Endian::ReadBigEndian(data, message.Price);
375  message.Attribution = *data++;
376 
377  return onMessage(message);
378 }
379 
380 bool ITCHHandler::ProcessOrderExecutedMessage(void* buffer, size_t size)
381 {
382  assert((size == 31) && "Invalid size of the ITCH message type 'E'");
383  if (size != 31)
384  return false;
385 
386  uint8_t* data = (uint8_t*)buffer;
387 
388  OrderExecutedMessage message;
389  message.Type = *data++;
390  data += CppCommon::Endian::ReadBigEndian(data, message.StockLocate);
391  data += CppCommon::Endian::ReadBigEndian(data, message.TrackingNumber);
392  data += ReadTimestamp(data, message.Timestamp);
393  data += CppCommon::Endian::ReadBigEndian(data, message.OrderReferenceNumber);
394  data += CppCommon::Endian::ReadBigEndian(data, message.ExecutedShares);
395  data += CppCommon::Endian::ReadBigEndian(data, message.MatchNumber);
396 
397  return onMessage(message);
398 }
399 
400 bool ITCHHandler::ProcessOrderExecutedWithPriceMessage(void* buffer, size_t size)
401 {
402  assert((size == 36) && "Invalid size of the ITCH message type 'C'");
403  if (size != 36)
404  return false;
405 
406  uint8_t* data = (uint8_t*)buffer;
407 
408  OrderExecutedWithPriceMessage message;
409  message.Type = *data++;
410  data += CppCommon::Endian::ReadBigEndian(data, message.StockLocate);
411  data += CppCommon::Endian::ReadBigEndian(data, message.TrackingNumber);
412  data += ReadTimestamp(data, message.Timestamp);
413  data += CppCommon::Endian::ReadBigEndian(data, message.OrderReferenceNumber);
414  data += CppCommon::Endian::ReadBigEndian(data, message.ExecutedShares);
415  data += CppCommon::Endian::ReadBigEndian(data, message.MatchNumber);
416  message.Printable = *data++;
417  data += CppCommon::Endian::ReadBigEndian(data, message.ExecutionPrice);
418 
419  return onMessage(message);
420 }
421 
422 bool ITCHHandler::ProcessOrderCancelMessage(void* buffer, size_t size)
423 {
424  assert((size == 23) && "Invalid size of the ITCH message type 'X'");
425  if (size != 23)
426  return false;
427 
428  uint8_t* data = (uint8_t*)buffer;
429 
430  OrderCancelMessage message;
431  message.Type = *data++;
432  data += CppCommon::Endian::ReadBigEndian(data, message.StockLocate);
433  data += CppCommon::Endian::ReadBigEndian(data, message.TrackingNumber);
434  data += ReadTimestamp(data, message.Timestamp);
435  data += CppCommon::Endian::ReadBigEndian(data, message.OrderReferenceNumber);
436  data += CppCommon::Endian::ReadBigEndian(data, message.CanceledShares);
437 
438  return onMessage(message);
439 }
440 
441 bool ITCHHandler::ProcessOrderDeleteMessage(void* buffer, size_t size)
442 {
443  assert((size == 19) && "Invalid size of the ITCH message type 'D'");
444  if (size != 19)
445  return false;
446 
447  uint8_t* data = (uint8_t*)buffer;
448 
449  OrderDeleteMessage message;
450  message.Type = *data++;
451  data += CppCommon::Endian::ReadBigEndian(data, message.StockLocate);
452  data += CppCommon::Endian::ReadBigEndian(data, message.TrackingNumber);
453  data += ReadTimestamp(data, message.Timestamp);
454  data += CppCommon::Endian::ReadBigEndian(data, message.OrderReferenceNumber);
455 
456  return onMessage(message);
457 }
458 
459 bool ITCHHandler::ProcessOrderReplaceMessage(void* buffer, size_t size)
460 {
461  assert((size == 35) && "Invalid size of the ITCH message type 'U'");
462  if (size != 35)
463  return false;
464 
465  uint8_t* data = (uint8_t*)buffer;
466 
467  OrderReplaceMessage message;
468  message.Type = *data++;
469  data += CppCommon::Endian::ReadBigEndian(data, message.StockLocate);
470  data += CppCommon::Endian::ReadBigEndian(data, message.TrackingNumber);
471  data += ReadTimestamp(data, message.Timestamp);
472  data += CppCommon::Endian::ReadBigEndian(data, message.OriginalOrderReferenceNumber);
473  data += CppCommon::Endian::ReadBigEndian(data, message.NewOrderReferenceNumber);
474  data += CppCommon::Endian::ReadBigEndian(data, message.Shares);
475  data += CppCommon::Endian::ReadBigEndian(data, message.Price);
476 
477  return onMessage(message);
478 }
479 
480 bool ITCHHandler::ProcessTradeMessage(void* buffer, size_t size)
481 {
482  assert((size == 44) && "Invalid size of the ITCH message type 'P'");
483  if (size != 44)
484  return false;
485 
486  uint8_t* data = (uint8_t*)buffer;
487 
488  TradeMessage message;
489  message.Type = *data++;
490  data += CppCommon::Endian::ReadBigEndian(data, message.StockLocate);
491  data += CppCommon::Endian::ReadBigEndian(data, message.TrackingNumber);
492  data += ReadTimestamp(data, message.Timestamp);
493  data += CppCommon::Endian::ReadBigEndian(data, message.OrderReferenceNumber);
494  message.BuySellIndicator = *data++;
495  data += CppCommon::Endian::ReadBigEndian(data, message.Shares);
496  data += ReadString(data, message.Stock);
497  data += CppCommon::Endian::ReadBigEndian(data, message.Price);
498  data += CppCommon::Endian::ReadBigEndian(data, message.MatchNumber);
499 
500  return onMessage(message);
501 }
502 
503 bool ITCHHandler::ProcessCrossTradeMessage(void* buffer, size_t size)
504 {
505  assert((size == 40) && "Invalid size of the ITCH message type 'Q'");
506  if (size != 40)
507  return false;
508 
509  uint8_t* data = (uint8_t*)buffer;
510 
511  CrossTradeMessage message;
512  message.Type = *data++;
513  data += CppCommon::Endian::ReadBigEndian(data, message.StockLocate);
514  data += CppCommon::Endian::ReadBigEndian(data, message.TrackingNumber);
515  data += ReadTimestamp(data, message.Timestamp);
516  data += CppCommon::Endian::ReadBigEndian(data, message.Shares);
517  data += ReadString(data, message.Stock);
518  data += CppCommon::Endian::ReadBigEndian(data, message.CrossPrice);
519  data += CppCommon::Endian::ReadBigEndian(data, message.MatchNumber);
520  message.CrossType = *data++;
521 
522  return onMessage(message);
523 }
524 
525 bool ITCHHandler::ProcessBrokenTradeMessage(void* buffer, size_t size)
526 {
527  assert((size == 19) && "Invalid size of the ITCH message type 'B'");
528  if (size != 19)
529  return false;
530 
531  uint8_t* data = (uint8_t*)buffer;
532 
533  BrokenTradeMessage message;
534  message.Type = *data++;
535  data += CppCommon::Endian::ReadBigEndian(data, message.StockLocate);
536  data += CppCommon::Endian::ReadBigEndian(data, message.TrackingNumber);
537  data += ReadTimestamp(data, message.Timestamp);
538  data += CppCommon::Endian::ReadBigEndian(data, message.MatchNumber);
539 
540  return onMessage(message);
541 }
542 
543 bool ITCHHandler::ProcessNOIIMessage(void* buffer, size_t size)
544 {
545  assert((size == 50) && "Invalid size of the ITCH message type 'I'");
546  if (size != 50)
547  return false;
548 
549  uint8_t* data = (uint8_t*)buffer;
550 
551  NOIIMessage message;
552  message.Type = *data++;
553  data += CppCommon::Endian::ReadBigEndian(data, message.StockLocate);
554  data += CppCommon::Endian::ReadBigEndian(data, message.TrackingNumber);
555  data += ReadTimestamp(data, message.Timestamp);
556  data += CppCommon::Endian::ReadBigEndian(data, message.PairedShares);
557  data += CppCommon::Endian::ReadBigEndian(data, message.ImbalanceShares);
558  message.ImbalanceDirection = *data++;
559  data += ReadString(data, message.Stock);
560  data += CppCommon::Endian::ReadBigEndian(data, message.FarPrice);
561  data += CppCommon::Endian::ReadBigEndian(data, message.NearPrice);
562  data += CppCommon::Endian::ReadBigEndian(data, message.CurrentReferencePrice);
563  message.CrossType = *data++;
564  message.PriceVariationIndicator = *data++;
565 
566  return onMessage(message);
567 }
568 
569 bool ITCHHandler::ProcessRPIIMessage(void* buffer, size_t size)
570 {
571  assert((size == 20) && "Invalid size of the ITCH message type 'N'");
572  if (size != 20)
573  return false;
574 
575  uint8_t* data = (uint8_t*)buffer;
576 
577  RPIIMessage message;
578  message.Type = *data++;
579  data += CppCommon::Endian::ReadBigEndian(data, message.StockLocate);
580  data += CppCommon::Endian::ReadBigEndian(data, message.TrackingNumber);
581  data += ReadTimestamp(data, message.Timestamp);
582  data += ReadString(data, message.Stock);
583  message.InterestFlag = *data++;
584 
585  return onMessage(message);
586 }
587 
588 bool ITCHHandler::ProcessLULDAuctionCollarMessage(void* buffer, size_t size)
589 {
590  assert((size == 35) && "Invalid size of the ITCH message type 'J'");
591  if (size != 35)
592  return false;
593 
594  uint8_t* data = (uint8_t*)buffer;
595 
596  LULDAuctionCollarMessage message;
597  message.Type = *data++;
598  data += CppCommon::Endian::ReadBigEndian(data, message.StockLocate);
599  data += CppCommon::Endian::ReadBigEndian(data, message.TrackingNumber);
600  data += ReadTimestamp(data, message.Timestamp);
601  data += ReadString(data, message.Stock);
602  data += CppCommon::Endian::ReadBigEndian(data, message.AuctionCollarReferencePrice);
603  data += CppCommon::Endian::ReadBigEndian(data, message.UpperAuctionCollarPrice);
604  data += CppCommon::Endian::ReadBigEndian(data, message.LowerAuctionCollarPrice);
605  data += CppCommon::Endian::ReadBigEndian(data, message.AuctionCollarExtension);
606 
607  return onMessage(message);
608 }
609 
610 bool ITCHHandler::ProcessUnknownMessage(void* buffer, size_t size)
611 {
612  assert((size > 0) && "Invalid size of the unknown ITCH message!");
613  if (size == 0)
614  return false;
615 
616  uint8_t* data = (uint8_t*)buffer;
617 
618  UnknownMessage message;
619  message.Type = *data;
620 
621  return onMessage(message);
622 }
623 
624 } // namespace ITCH
625 } // namespace CppTrader
virtual bool onMessage(const SystemEventMessage &message)
Definition: itch_handler.h:418
bool ProcessMessage(void *buffer, size_t size)
Process a single message from the given buffer in ITCH format and call corresponding handlers.
bool Process(void *buffer, size_t size)
Process all messages from the given buffer in ITCH format and call corresponding handlers.
void Reset()
Reset ITCH handler.
NASDAQ ITCH handler definition.
C++ Trader project definitions.
Definition: errors.h:16