This library provides lightweight Order Book component.
Requirements:
- Input data: Level 1, Level 2 market data in Universal Market Data format
- You need to decide if you need aggregated / consolidated / single-exchange order book before you start using it
- No need to keep "before/after" state of each market message update (only "after")
- No memory allocatons in main processing cycle
- Single threaded use only
Step 1: Setting up the dependency.
The first step is to include orderbook
into your project, for example, as a Gradle compile dependency:
dependencies {
implementation com.epam.deltix:orderbook-core:x.x.x
}
(Please replace x with the latest version numbers: Maven Central )
Step 2: Create order book
final OrderBook<OrderBookQuote> orderBook = OrderBookFactory.create();
Step 3: Feed order book with market data
void onMarketData(final MarketMessage message) {
orderBook.update(message);
}
Step 4: Access order book state
- Use for-each loop (procedural style)
for (OrderBookQuote quote : orderBook.getMarketSide(QuoteSide.ASK)) {
System.out.println(quote);
}
- You can use the streaming API if you don't care about memory allocation! πͺ
orderBook.getMarketSide(QuoteSide.ASK).stream() #1) Stream for quotes in order book
.filter(quote -> Decimal64Utils.isGreater(quote.getPrice(), Decimal64Utils.fromInt(15)))
.forEach(System.out::println);
orderBook.getExchangeList().stream() #2) Stream for quotes by exchanges
.flatMap(exchange -> exchange.getMarketSide(QuoteSide.ASK).stream())
.filter(quote -> Decimal64Utils.isGreater(quote.getPrice(), Decimal64Utils.fromInt(15)))
.forEach(System.out::println);
You can use the OrderBookOptionsBuilder
class like so:
final OrderBookOptions commonOpt = new OrderBookOptionsBuilder()
.quoteLevels(DataModelType.LEVEL_TWO)
.initialMaxDepth(marketDepth)
.initialExchangesPoolSize(exchangeIds.length)
.updateMode(UpdateMode.WAITING_FOR_SNAPSHOT)
.build();
final OrderBookOptions opt = new OrderBookOptionsBuilder()
.parent(commonOpt)
.symbol("BTC/USD")
.orderBookType(OrderBookType.AGGREGATED)
.build();
final OrderBook<OrderBookQuote> orderBook = OrderBookFactory.create(opt);
or directly instantiate a OrderBook with default parameters like so:
final OrderBook<OrderBookQuote> orderBook = OrderBookFactory.create();
-
parent - Override the defaults from the given option
You may use this only once.
Since: 1.0.11
Type: OrderBookOptions -
symbol - Stock symbol
This stock symbol is used to check all input packets before processing.
If you are sure that your market data contains data for only one stock symbol, you may not set this option.
Since: 1.0.11
Type: String -
orderBookType - Order book type to use
Since: 1.0.11
Type: OrderBookType
Default Value is: SINGLE_EXCHANGE
The following types are supported:- SINGLE_EXCHANGE - order book from single exchange
- CONSOLIDATED - consolidated view on the market from multiple exchanges, you can see individual exchange sizes
- AGGREGATED - aggregated view of multiple exchanges, you can see combined size of each price level
-
updateMode - What do we do with incremental update if we have empty order book?
Since: 1.0.11
Type: UpdateMode
Default Value is: WAITING_FOR_SNAPSHOT
The following types are supported:- WAITING_FOR_SNAPSHOT - waiting snapshot before processing incremental update
- NON_WAITING_FOR_SNAPSHOT - process incremental update without waiting for the snapshot
-
gapMode - What do we do if we have a gap between the last existing level and the current inserted level (empty levels in between)?
Since: 1.0.11
Type: GapMode
Default Value is: SKIP
The following types are supported:- SKIP - let's skip quote
- SKIP_AND_DROP - let's skip quote and drop all quote for stock exchange
- FILL_GAP - let's fill these empty levels with values from the current event.
The insertion level cannot be greater than the value of the parameter maxDepth
otherwise insertion wiil be skip.
-
quoteLevels - Quote levels to use
Since: 1.0.11
Type: DataModelType
Default Value is: LEVEL_ONE
The following types are supported:- LEVEL_ONE - level one (best bid and best offer)
- LEVEL_TWO - level two. Market by level. More details than LEVEL_ONE
-
π’ initialDepth - How large initial depth of market should be?
Since: 1.0.11
Type: int
Default Value is: 1 -
π’ maxDepth - How large maximum (limit) depth of market should be?
Using this parameter if you want processing not all depth of market.
But is can make orderbook not valid (with gaps). See parameter gapMode
Since: 1.0.11
Type: int
Default Value is: 32767 -
π’ unreachableDepthMode - What do we do if we have quote level more than maxDepth?
Since: 1.0.17
Type: UnreachableDepthMode
Default Value is: SKIP
The following types are supported:- SKIP - let's skip quote
- SKIP_AND_DROP - let's skip quote and drop all quote for stock exchange
-
π’ initialExchangesPoolSize - How large initial pool size for stock exchanges should be?
Supported for AGGREGATED and CONSOLIDATED order book type.
Since: 1.0.11
Type: int
Default Value is: 1
In many cases it is helpful to pass some kind of cookie or state object when iterating order book:
orderBook.getMarketSide(QuoteSide.ASK).forEach(this::quoteViewAccumulatorAction, new QuoteCookie());
Small example that shows some useful accumulator:
private static final class PriceAccumulator {
@Decimal
private long price;
public void apply(@Decimal long add) {
price = Decimal64Utils.add(price, add);
}
public long getPrice() {
return price;
}
}
...
orderBook.getMarketSide(QuoteSide.ASK).forEach(this::quoteViewAccumulatorAction, priceAccumulator);
orderBook.getMarketSide(QuoteSide.BID).forEach(this::quoteViewAccumulatorAction, priceAccumulator);
...
boolean quoteViewAccumulatorAction(final OrderBookQuoteView orderBookQuote,
final PriceAccumulator accumulator){
accumulator.apply(orderBookQuote.getPrice());
return priceLevel< 10; // do not go deeper than 10 levels
}
Samples can be found in the samples folder.
Measured on moderately sized developer's laptop. For run test see OrderBookIT
-
Hardware:
CPU: Intel(R) Core(TM) i7-10610U CPU @ 1.80GHz 2.30 GHz Memory: 32.0 GB Disk: SSD 512
-
Market data:
Quote levels: L1/L2 Types of packages: VENDOR_SNAPSHOT/PERIODICAL_SNAPSHOT/INCREMENTAL_UPDATE Number of exchanges: 1 Price levels: 500 Number of messages: 4 27 042
Table - L1 Quote Level
Order Book Implementation | Messages Processed (msg/s) | Allocation Memory byte(s) |
---|---|---|
Black hole | 1 977 046 | - |
SingleExchangeOrderBook | 1 567 812 | 496 |
ConsolidatedOrderBook | TODO | TODO |
AggregatedOrderBook | TODO | TODO |
Table - L2 Quote Level
Order Book Implementation | Messages Processed (msg/s) | Allocation Memory byte(s) |
---|---|---|
Black hole | 1 977 046 | - |
SingleExchangeOrderBook | 1 110 222 | 62 272 |
ConsolidatedOrderBook | 890 701 | 67 024 |
AggregatedOrderBook | 890 062 | 125 024 |
Copyright (C) 2022 EPAM
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.