Skip to content

Commit

Permalink
Use virtual methods to inform depth_book of changes rather than having
Browse files Browse the repository at this point in the history
depth_book hijack the perform_callbacks mechanism.
Perform_callbacks is deprecated.  Remove it from unit tests and examples.
  • Loading branch information
Dale Wilson committed Feb 22, 2017
1 parent 38bcc84 commit f7deb99
Show file tree
Hide file tree
Showing 12 changed files with 326 additions and 214 deletions.
3 changes: 0 additions & 3 deletions examples/mt_order_entry/Market.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,6 @@ Market::doAdd(const std::string & side, const std::vector<std::string> & tokens

orders_[orderId] = order;
book->add(order, conditions);
book->perform_callbacks();
return true;
}

Expand All @@ -332,7 +331,6 @@ Market::doCancel(const std::vector<std::string> & tokens, size_t position)
}
out() << "Requesting Cancel: " << *order << std::endl;
book->cancel(order);
book->perform_callbacks();
return true;
}

Expand Down Expand Up @@ -440,7 +438,6 @@ Market::doModify(const std::vector<std::string> & tokens, size_t position)
out() << " PRICE " << price;
}
out() << std::endl;
book->perform_callbacks();
return true;
}

Expand Down
2 changes: 1 addition & 1 deletion pt_run.bat
Original file line number Diff line number Diff line change
@@ -1 +1 @@
test\pt_order_book.exe
bin\test\pt_order_book.exe
205 changes: 114 additions & 91 deletions src/book/depth_order_book.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,13 @@
namespace liquibook { namespace book {

/// @brief Implementation of order book child class, that incorporates
/// aggregate depth tracking. Overrides perform_callback() method to
// track depth aggregated by price.
/// aggregate depth tracking.
template <class OrderPtr = Order*, int SIZE = 5>
class DepthOrderBook : public OrderBook<OrderPtr> {
public:
typedef Depth<SIZE> DepthTracker;
typedef BboListener<DepthOrderBook >TypedBboListener;
typedef DepthListener<DepthOrderBook >TypedDepthListener;
typedef Callback<OrderPtr> DobCallback;

/// @brief construct
DepthOrderBook(const std::string & symbol = "unknown");
Expand All @@ -30,15 +28,34 @@ class DepthOrderBook : public OrderBook<OrderPtr> {
/// @brief set the depth listener
void set_depth_listener(TypedDepthListener* depth_listener);

/// @brief handle a single callback
virtual void perform_callback(DobCallback& cb);

// @brief access the depth tracker
DepthTracker& depth();

// @brief access the depth tracker
const DepthTracker& depth() const;

protected:
//////////////////////////////////
// Implement virtual callback methods
// needed to maintain depth book.
virtual void on_accept(const OrderPtr& order, Quantity quantity);

virtual void on_fill(const OrderPtr& order,
const OrderPtr& matched_order,
Quantity fill_qty,
Cost fill_cost,
bool inbound_order_filled,
bool matched_order_filled);

virtual void on_cancel(const OrderPtr& order, Quantity quantity);

virtual void on_replace(const OrderPtr& order,
Quantity current_qty,
Quantity new_qty,
Price new_price);

virtual void on_order_book_change();

private:
DepthTracker depth_;
TypedBboListener* bbo_listener_;
Expand Down Expand Up @@ -67,96 +84,102 @@ DepthOrderBook<OrderPtr, SIZE>::set_depth_listener(TypedDepthListener* listener)
depth_listener_ = listener;
}

template <class OrderPtr, int SIZE>
inline void
DepthOrderBook<OrderPtr, SIZE>::perform_callback(DobCallback& cb)
template <class OrderPtr, int SIZE>
void
DepthOrderBook<OrderPtr, SIZE>::on_accept(const OrderPtr& order, Quantity quantity)
{
OrderBook<OrderPtr>::perform_callback(cb);
switch(cb.type) {
case DobCallback::cb_order_accept:
// If the order is a limit order
if (cb.order->is_limit()) {
// If the order is completely filled on acceptance, do not modify
// depth unnecessarily
if (cb.quantity == cb.order->order_qty()) {
// Don't tell depth about this order - it's going away immediately.
// Instead tell Depth about future fills to ignore
depth_.ignore_fill_qty(cb.quantity, cb.order->is_buy());
} else {
// Add to bid or ask depth
depth_.add_order(cb.order->price(),
cb.order->order_qty(),
cb.order->is_buy());
}
}
break;

case DobCallback::cb_order_fill: {
// If the matched order is a limit order
if (cb.matched_order->is_limit()) {
bool matched_order_filled =
(cb.flags & DobCallback::ff_matched_filled) != 0;
// Inform the depth
depth_.fill_order(cb.matched_order->price(),
cb.quantity,
matched_order_filled,
cb.matched_order->is_buy());
}
// If the inbound order is a limit order
if (cb.order->is_limit()) {
bool inbound_order_filled =
cb.flags & DobCallback::ff_inbound_filled;
// Inform the depth
depth_.fill_order(cb.order->price(),
cb.quantity,
inbound_order_filled,
cb.order->is_buy());
}
break;
// If the order is a limit order
if (order->is_limit())
{
// If the order is completely filled on acceptance, do not modify
// depth unnecessarily
if (quantity == order->order_qty())
{
// Don't tell depth about this order - it's going away immediately.
// Instead tell Depth about future fills to ignore
depth_.ignore_fill_qty(quantity, order->is_buy());
}
else
{
// Add to bid or ask depth
depth_.add_order(order->price(),
order->order_qty(),
order->is_buy());
}
case DobCallback::cb_order_cancel:
// If the order is a limit order
if (cb.order->is_limit()) {
// If the close erases a level
depth_.close_order(cb.order->price(),
cb.quantity,
cb.order->is_buy());
}
break;
}
}

case DobCallback::cb_order_replace:
{
// Remember current values
Quantity current_qty = cb.quantity;
Quantity new_qty = current_qty + cb.delta;

// Notify the depth
depth_.replace_order(cb.order->price(), cb.price,
current_qty, new_qty, cb.order->is_buy());
break;
template <class OrderPtr, int SIZE>
void
DepthOrderBook<OrderPtr, SIZE>::on_fill(const OrderPtr& order,
const OrderPtr& matched_order,
Quantity quantity,
Cost fill_cost,
bool inbound_order_filled,
bool matched_order_filled)
{
// If the matched order is a limit order
if (matched_order->is_limit()) {
// Inform the depth
depth_.fill_order(matched_order->price(),
quantity,
matched_order_filled,
matched_order->is_buy());
}
// If the inbound order is a limit order
if (order->is_limit()) {
// Inform the depth
depth_.fill_order(order->price(),
quantity,
inbound_order_filled,
order->is_buy());
}
}

template <class OrderPtr, int SIZE>
void
DepthOrderBook<OrderPtr, SIZE>::on_cancel(const OrderPtr& order, Quantity quantity)
{
// If the order is a limit order
if (order->is_limit()) {
// If the close erases a level
depth_.close_order(order->price(),
quantity,
order->is_buy());
}
}

template <class OrderPtr, int SIZE>
void
DepthOrderBook<OrderPtr, SIZE>::on_replace(const OrderPtr& order,
Quantity current_qty,
Quantity new_qty,
Price new_price)
{
// Notify the depth
depth_.replace_order(order->price(), new_price,
current_qty, new_qty, order->is_buy());
}

template <class OrderPtr, int SIZE>
void
DepthOrderBook<OrderPtr, SIZE>::on_order_book_change()
{
// Book was updated, see if the depth we track was effected
if (depth_.changed()) {
if (depth_listener_) {
depth_listener_->on_depth_change(this, &depth_);
}
case DobCallback::cb_book_update:
// Book was updated, see if the depth we track was effected
if (depth_.changed()) {
if (depth_listener_) {
depth_listener_->on_depth_change(this, &depth_);
}
if (bbo_listener_) {
ChangeId last_change = depth_.last_published_change();
// May have been the first level which changed
if ((depth_.bids()->changed_since(last_change)) ||
(depth_.asks()->changed_since(last_change))) {
bbo_listener_->on_bbo_change(this, &depth_);
}
}
// Start tracking changes again...
depth_.published();
if (bbo_listener_) {
ChangeId last_change = depth_.last_published_change();
// May have been the first level which changed
if ((depth_.bids()->changed_since(last_change)) ||
(depth_.asks()->changed_since(last_change))) {
bbo_listener_->on_bbo_change(this, &depth_);
}
break;

default:
// Nothing
break;
}
// Start tracking changes again...
depth_.published();
}
}

Expand Down
17 changes: 17 additions & 0 deletions src/book/logger.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright (c) 2012, 2013 Object Computing, Inc.
// All rights reserved.
// See the file license.txt for licensing information.
#pragma once

#include <exception>
#include <string>
namespace liquibook { namespace book {
/// @brief Interface to allow application to control error logging
class Logger
{
public:
virtual void log_exception(const std::string & context, const std::exception& ex) = 0;
virtual void log_message(const std::string & message) = 0;
};

}}
Loading

0 comments on commit f7deb99

Please sign in to comment.