JayBeams  0.1
Another project to have fun coding.
itch5bookdepth.cpp
Go to the documentation of this file.
1 /**
2  * @file
3  *
4  * Compute ITCH5 Depth of Book statistics.
5  *
6  * Generate statistics per symbol and aggregated.
7  * See:
8  * https://github.com/GFariasR/jaybeams/wiki/ITCH5-Depth-of-Book-StatisticsProject
9  * for design and implementation details.
10  */
15 #include <jb/fileio.hpp>
16 #include <jb/log.hpp>
17 
18 #include <chrono>
19 #include <iostream>
20 #include <stdexcept>
21 #include <unordered_map>
22 
23 /**
24  * Define types and functions used in this program.
25  */
26 namespace {
27 
28 /// Configuration parameters for itch5bookdepth
29 class config : public jb::config_object {
30 public:
31  config();
33 
34  void validate() const override;
35 
41  jb::config_attribute<config, bool> enable_symbol_stats;
42 };
43 
44 /// Record the book depth
45 template <typename book_type>
46 void record_book_depth(
49  jb::itch5::book_update const& update) {
50  auto buy_price_levels =
51  jb::itch5::price_levels(book.worst_bid().first, book.best_bid().first);
52  auto sell_price_levels = jb::itch5::price_levels(
53  book.best_offer().first, book.worst_offer().first);
54  stats.sample(buy_price_levels + sell_price_levels);
55 }
56 
57 } // anonymous namespace
58 
59 int main(int argc, char* argv[]) try {
60  config cfg;
61  cfg.load_overrides(argc, argv, std::string("itch5bookdepth.yaml"), "JB_ROOT");
62  jb::log::init(cfg.log());
63 
64  boost::iostreams::filtering_istream in;
65  jb::open_input_file(in, cfg.input_file());
66 
67  boost::iostreams::filtering_ostream out;
68  jb::open_output_file(out, cfg.output_file());
69 
70  std::map<jb::itch5::stock_t, jb::book_depth_statistics> per_symbol;
71  jb::book_depth_statistics stats(cfg.stats());
72 
74  [&stats](
75  jb::itch5::message_header const& header,
77  updated_book,
78  jb::itch5::book_update const& update) {
79  record_book_depth(stats, header, updated_book, update);
80  };
81 
82  if (cfg.enable_symbol_stats()) {
83  jb::book_depth_statistics::config symcfg(cfg.symbol_stats());
85  chain = [&per_symbol, symcfg, cb](
86  jb::itch5::message_header const& header,
88  jb::itch5::book_update const& update) {
89  cb(header, book, update);
90  auto location = per_symbol.find(update.stock);
91  if (location == per_symbol.end()) {
92  auto p = per_symbol.emplace(
93  update.stock, jb::book_depth_statistics(symcfg));
94  location = p.first;
95  }
96  record_book_depth(location->second, header, book, update);
97  };
98  cb = std::move(chain);
99  }
100 
103  std::move(cb), cfg_bk);
104  jb::itch5::process_iostream(in, handler);
105 
107  for (auto const& i : per_symbol) {
108  i.second.print_csv(i.first.c_str(), out);
109  }
110  stats.print_csv("__aggregate__", out);
111  return 0;
112 
113 } catch (jb::usage const& u) {
114  std::cerr << u.what() << std::endl;
115  return u.exit_status();
116 } catch (std::exception const& ex) {
117  std::cerr << "Standard exception raised: " << ex.what() << std::endl;
118  return 1;
119 } catch (...) {
120  std::cerr << "Unknown exception raised" << std::endl;
121  return 1;
122 }
123 
124 namespace {
125 
126 /// Limit the amount of memory used on each per-symbol statistics
127 #ifndef JB_ITCH5BOOKDEPTH_DEFAULT_per_symbol_max_book_depth
128 #define JB_ITCH5BOOKDEPTH_DEFAULT_per_symbol_max_book_depth 5000
129 #endif // JB_ITCH5BOOKDEPTH_DEFAULT_per_symbol_max_book_depth
130 
131 /// Create a different default configuration for the per-symbol stats
132 jb::book_depth_statistics::config default_per_symbol_stats() {
135 }
136 
137 config::config()
138  : input_file(
139  desc("input-file").help("An input file with ITCH-5.0 messages."),
140  this)
141  , output_file(
142  desc("output-file")
143  .help("The name of the file where to store the statistics."
144  " By default output to stdout."
145  " Files ending in .gz are automatically compressed."),
146  this, "stdout")
147  , log(desc("log", "logging"), this)
148  , stats(desc("stats", "book-depth-statistics"), this)
149  , symbol_stats(
150  desc("symbol-stats", "book-depth-statistics-per-symbol"), this,
151  default_per_symbol_stats())
152  , enable_symbol_stats(
153  desc("enable-symbol-stats")
154  .help("If set, enable per-symbol statistics."
155  " Collecting per-symbol statistics is expensive in both"
156  " memory and execution time, enable only if needed."),
157  this, true) {
158 }
159 
160 void config::validate() const {
161  if (input_file() == "") {
162  throw jb::usage(
163  "Missing input-file setting."
164  " The program needs an input file to read ITCH-5.0 data from.",
165  1);
166  }
167  if (output_file() == "") {
168  throw jb::usage(
169  "Missing output-file setting."
170  " Use 'stdout' if you want to print to the standard output.",
171  1);
172  }
173  log().validate();
174  stats().validate();
175  symbol_stats().validate();
176 }
177 
178 } // anonymous namespace
Compute the book and call a user-defined callback on each change.
Define the header common to all ITCH 5.0 messages.
half_quote worst_bid() const
Definition: order_book.hpp:78
Base class for all configuration objects.
void sample(book_depth_t book_depth)
Record a sample, that is book depth value after the event.
virtual void validate() const
Validate the settings.
static void print_csv_header(std::ostream &os)
Print a CSV header.
int exit_status() const
Definition: usage.hpp:21
void open_output_file(boost::iostreams::filtering_ostream &out, std::string const &filename)
Open a file for writing.
Definition: fileio.cpp:12
void process_iostream(std::istream &in, message_handler &handler)
Process an iostream of ITCH-5.0 messages.
Keep statistics about a feed and its book depth.
void print_csv(std::string const &name, std::ostream &os) const
Print all the measurements in CSV format.
void init(config const &cfg)
Initialize the logging functions using the configuration provided.
Definition: log.cpp:190
#define config_object_constructors(NAME)
Helper class to easily define configuration attributes.
std::function< void(message_header const &header, order_book< book_type > const &updated_book, book_update const &update)> callback_type
Define the callback type.
jb::config_attribute< config, book_depth_t > max_book_depth
No more than this value is recorded.
Configure a book_depth_statistics object.
half_quote best_bid() const
Definition: order_book.hpp:73
stock_t stock
The security updated by this order.
A simple class to communicate the result of parsing the options.
Definition: usage.hpp:11
A flat struct to represent updates to an order book.
#define JB_ITCH5BOOKDEPTH_DEFAULT_per_symbol_max_book_depth
Limit the amount of memory used on each per-symbol statistics.
void open_input_file(boost::iostreams::filtering_istream &in, std::string const &filename)
Open a file for reading.
Definition: fileio.cpp:27
static attribute_descriptor desc(std::string const &name)
Convenience function to create attribute descriptors with less typing.
Configure an map_based_order_book config object.
half_quote worst_offer() const
Definition: order_book.hpp:88
std::size_t price_levels(price_field_t lo, price_field_t hi)
Compute the number of price levels between two prices.
Maintain the ITCH-5.0 order book for a single security.
Definition: order_book.hpp:57
int main(int argc, char *argv[])
half_quote best_offer() const
Definition: order_book.hpp:83