In the recent past we have received inquiries from customers and other people asking us to show how to implement full Market Depth, an advanced financial trading feature, with Lightstreamer. We think this is the time to present an example that, in addition to the classic StockList Demo and Portfolio Demo, demonstrates how well the Lightstreamer technology can satisfy the needs of this type of applications.
Market depth is an electronic list of buy and sell orders, organized by price level and updated to reflect real-time market activity. Market depth data are also known as Level II, Depth Of Market (DOM), and the order book.
The Market Depth Demo
The Market Depth Demo is a very simple market depth application based on Lightstreamer real-time data push. On the server side, it is made up of a Lightstreamer Adapter that simulates the market. On the client side, it is an HTML page that uses the Lightstreamer JavaScript library to receive the real-time updates to the order book (level II data) and send orders submitted by the user.
For the impatient, here are the links to the live demo and to the source code:
- Live demo:
http://demos.lightstreamer.com/MarketDepthDemo/ - HTML client source:
https://github.com/Weswit/Lightstreamer-example-MarketDepth-client-javascript - Java adapter source:
https://github.com/Weswit/Lightstreamer-example-MarketDepth-adapter-java
Lightstreamer has semi-native support for full market depth, which can be managed very easily via COMMAND mode subscriptions. Basically, the bid and ask lists for an instrument will be two items subscribed to in COMMAND mode.
Please note that if you don’t want to deliver full market depth but just a predefined number of rows (e.g. 10 best bids and 10 best asks), then MERGE mode, as used for Level I data, may be enough, without requiring COMMAND mode. This article focuses on full market depth delivery.
The Lightstreamer COMMAND mode was indeed designed for all those application scenarios where it is required not only to push changes to an item content in terms of updating one or more fields, but even changes to the list of items itself, in terms of adding and removing rows. This is the so called “meta-push”.
Usually, in COMMAND mode a single item is used for the whole list or table. The itemEvents are interpreted as commands that indicate how to progressively modify a list. In the schema there are two fields that are required to interpret the itemEvent:
- The “command” field contains the command associated with the itemEvent, having a value of “ADD”, “UPDATE” or “DELETE”.
- The “key” field contains the key that unequivocally identifies a line of the list generated from the Item.
The “key” and “command” fields must never be missing from an itemEvent.
In the figure below, a graphical representation of a generic Item handled in COMMAND Mode is shown:
Not all the itemEvents coming from the Data Adapter need to be sent to the client (because filtering is possible). Successive events regarding the same “key” (but not necessarily received consecutively from the Data Adapter) can be automatically merged according to the following rules:
- an UPDATE merges with previous ADD or UPDATE
- a DELETE removes the previous ADD or UPDATE (when removing ADD, the DELETE itself is removed; when removing UPDATE, the DELETE remains)
- an ADD removes the previous DELETE and becomes an UPDATE
For the itemEvents with “ADD” or “DELETE” commands , the “holes” (in the other fields) are propagated to the Client. For the itemEvents with “UPDATE” commands, the “holes” are filled by copying the values of the field corresponding to the last message of ADD or UPDATE with the same key.
In the case of this demo, as said before, the bid and ask order lists are two items subscribed to in COMMAND mode with the following schema:
- the “key” field will be the price of the orders
- the “command” field as per the COMMAND specifications
- the “qty”, the only item-specific field, which represents the total amount of all existing orders at that price.
So, you will be able to add, update, and remove rows, where each row is identified by the price. Lightstreamer will take care of aggregating updates to market depth in the most optimized way, based on bandwidth and frequency constraints. This way, you will be able to manage full market depths even on unreliable networks and mobile devices and also benefit from update resampling with conflation, if needed.
Data and Metadata Adapters
The Data Adpter is implemented by the MarketDepthDataAdapter class. The class implements two interfaces:- SmartDataProvider, which implements the communication with the Lightstreamer server- MarketMaker, which models a very simple set of possible events from the trading market.
Deepening the code of the Data Adapter, you can figure out the logic that translate events coming from the market into simple commands pushed to items subscribed to in COMMAND mode.
- A new order at price X, not previously present in the order book, for Y shares, implies an “ADD” command for the new key X with “qty” field equal to Y:
public void newOrderLevel(String symbol, OrderBase ob) {
if (availableStocks.containsKey(symbol)) {
Stock myStock = availableStocks.get(symbol);
final HashMap<String, String> update = new HashMap<String, String>();
update.put("command", "ADD");
update.put("key", ""+ob.getPrice());
update.put("qty", ""+ob.getQuantity());
if (ob instanceof OrderBuy ) {
listener.smartUpdate(myStock.getLs_buy_handle(), update, false);
} else {
listener.smartUpdate(myStock.getLs_sell_handle(), update, false);
}
}
}
- A quantity change, Y, for a given price level X, implies an “UPDATE” command for the key X with “qty” field equal to Y:
public void orderLevelChange(String symbol, OrderBase ob) {
if (availableStocks.containsKey(symbol)) {
Stock myStock = availableStocks.get(symbol);
final HashMap<String, String> update = new HashMap<String, String>();
update.put("command", "UPDATE");
update.put("key", ""+ob.getPrice());
update.put("qty", ""+ob.getQuantity());
if (ob instanceof OrderBuy ) {
listener.smartUpdate(myStock.getLs_buy_handle(), update, false);
} else {
listener.smartUpdate(myStock.getLs_sell_handle(), update, false);
}
}
}
- A cancellation of the price level X from the order book implies a “DELETE” command for the key X (the “qty” field is not present):
public void deleteOrderLevel(String symbol, OrderBase ob) {
if (availableStocks.containsKey(symbol)) {
Stock myStock = availableStocks.get(symbol);
final HashMap<String, String> update = new HashMap<String, String>();
update.put("command", "DELETE");
update.put("key", ""+ ob.getPrice());
if (ob instanceof OrderSell ) {
listener.smartUpdate(myStock.getLs_sell_handle(), update, false);
} else {
listener.smartUpdate(myStock.getLs_buy_handle(), update, false);
}
}
}
The Metadata Adpter is implemented by the MarketDepthMetadataAdapter class. The class inherits from the reusable LiteralBasedProvider and just adds a simple support for order entry by implementing the NotifyUserMessage method, to handle sendMessage requests from the client. The communication to the Market Orders Simulator, through the Data Adapter, is handled there.
The Market Orders Simulator
The server-side part of the demo includes the implementation of a very simple market orders simulator.
Orders are randomly generated for ask or bid around a reference price that is also randomly determined. Four stocks are managed, each with a different order generation frequency. The stocks are listed below in ascending order (from slower to faster):
– Old&Slow Company: item name “OS_C”
– BTTQ Industries Sa: item name “BTTQ_I”
– AXY Company Ltd, Item name: “AXY_COMP”
– SuperFast Tech.: item name “SF_TECH”
Once a fixed number of executions has been reached, the stock simulates the “End of Day” phase, in which both the order books, for buy and sell, are cleaned up, and the reference price is recalculated (this phase lasts 15 seconds).
The HTML Client
The client-side of the demo consist in a simple HTML page that shows the real-time data received from the Lightstreamer server. Furthermore, you can submit orders at your convenience through a basic input form (only limited orders are allowed).
The code for handling communication with the Lightstreamer server is divided into three simple JavaScript files and includes the following features:
- A Subscription containing 1 item, subscribed to in `MERGE` mode feeding a StaticGrid showing summary data for the stock.
- Two Subscriptions containing 1 item each, subscribed to in `COMMAND` mode feeding two DynaGrids showing the bid and ask lists.
- The orders are sent to the adapter through the Lightstreamer Server using the LightstreamerClient.sendMessage utility.
Reference
If you want to dig a little more on the topic, and start coding yourself, you can play with the online demo and fork its code on GitHub:
- Live demo:
http://demos.lightstreamer.com/MarketDepthDemo/ - HTML client source:
https://github.com/Weswit/Lightstreamer-example-MarketDepth-client-javascript - Java adapter source:
https://github.com/Weswit/Lightstreamer-example-MarketDepth-adapter-java
Let us know if you have any feedback!