Skip to content

Commit

Permalink
feat: L3
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrii_Ostapenko1 authored and Andrii_Ostapenko1 committed May 22, 2024
1 parent 9019892 commit 121e791
Show file tree
Hide file tree
Showing 81 changed files with 9,423 additions and 1,279 deletions.
2 changes: 0 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ configure(allprojects) {
exclude group: "org.apache.commons", name: "commons-lang"
exclude group: "com.epam.deltix", name: "containers"
exclude group: "com.epam.deltix", name: "hd-date-time"
exclude group: "com.epam.deltix", name: "gflog-api"
exclude group: "com.epam.deltix", name: "gflog-core"
exclude group: "com.epam.deltix", name: "dfp"
}
}
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version=1.0.17-SNAPSHOT
version=1.0.18-SNAPSHOT

group=com.epam.deltix
org.gradle.jvmargs=-Xmx2500m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package com.epam.deltix.orderbook.core.api;

/**
* Represents validation error codes that can be encountered during order book updates.
* Each constant corresponds to a specific scenario where an update to the order book fails
* validation checks.
*/
public enum EntryValidationCode {
/**
* The quote ID, which uniquely identifies an order, is missing.
*/
MISSING_QUOTE_ID,

/**
* The quote ID submitted already exists in the order book, indicating a duplicated order.
*/
DUPLICATE_QUOTE_ID,

/**
* The price field of the order is missing, which is required for order placement.
*/
MISSING_PRICE,

/**
* The submitted order size is either not well-formed or outside the allowed range.
*/
BAD_SIZE,

/**
* The quote ID referenced does not match any existing order in the order book.
*/
UNKNOWN_QUOTE_ID,

/**
* An attempt to modify an existing order with a new price was made,
* which may not be supported in certain order book implementations.
*/
MODIFY_CHANGE_PRICE,

/**
* An attempt to increase the size of an existing order through modification was made.
* This may be an invalid operation depending on exchange rules.
*/
MODIFY_INCREASE_SIZE,

/**
* The exchange ID, used to identify the marketplace where the order should be placed, is missing.
*/
MISSING_EXCHANGE_ID,

/**
* There's a discrepancy between the exchange ID stated and the one expected by the order book.
*/
EXCHANGE_ID_MISMATCH,

/**
* The action specified for updating the order book is not recognized or allowed.
*/
UNSUPPORTED_UPDATE_ACTION,

/**
* The order does not specify whether it is a buy or sell order.
*/
UNSPECIFIED_SIDE,

/**
* The type of order insert operation specified is not supported by the order book.
*/
UNSUPPORTED_INSERT_TYPE
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.epam.deltix.orderbook.core.api;


import com.epam.deltix.timebase.messages.MessageInfo;

/**
* User-defined error handler
*/
public interface ErrorListener {
/**
* Called when input market message contains something invalid.
*
* @param message message containing invalid market-related messages
* @param errorCode error code that describes what is wrong
*/
void onError(MessageInfo message, EntryValidationCode errorCode);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
*/
package com.epam.deltix.orderbook.core.api;


import com.epam.deltix.timebase.messages.universal.QuoteSide;
import com.epam.deltix.util.annotations.Alphanumeric;

/**
* Represents the order book entries for a specific stock exchange.
Expand All @@ -32,6 +32,7 @@ public interface Exchange<Quote> {
*
* @return exchangeId for this exchange.
*/
@Alphanumeric
long getExchangeId();

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.epam.deltix.orderbook.core.api;

import com.epam.deltix.orderbook.core.options.Option;
import com.epam.deltix.util.annotations.Alphanumeric;

import java.util.function.BiPredicate;
import java.util.function.Predicate;
Expand All @@ -30,7 +31,7 @@
*
* @author Andrii_Ostapenko1
*/
public interface ExchangeList<StockExchange> extends Iterable<StockExchange> {
public interface ExchangeList<Exchange> extends Iterable<Exchange> {

/**
* Get exchange holder by id.
Expand All @@ -40,7 +41,7 @@ public interface ExchangeList<StockExchange> extends Iterable<StockExchange> {
* @return an {@code Optional} containing the exchange holder; never {@code null} but
* potentially empty
*/
Option<StockExchange> getById(long exchangeId);
Option<Exchange> getById(@Alphanumeric long exchangeId);

/**
* Returns the number of elements in this list.
Expand Down Expand Up @@ -69,7 +70,7 @@ public interface ExchangeList<StockExchange> extends Iterable<StockExchange> {
* @see Stream
* @see java.util.Spliterator
*/
default Stream<StockExchange> stream(final boolean parallel) {
default Stream<Exchange> stream(final boolean parallel) {
return StreamSupport.stream(spliterator(), parallel);
}

Expand All @@ -83,21 +84,21 @@ default Stream<StockExchange> stream(final boolean parallel) {
* @see Stream
* @see java.util.Spliterator
*/
default Stream<StockExchange> stream() {
default Stream<Exchange> stream() {
return stream(false);
}

default void forEach(final Predicate<StockExchange> action) {
for (final StockExchange e : this) {
default void forEach(final Predicate<Exchange> action) {
for (final Exchange e : this) {
if (!action.test(e)) {
return;
}
}
}

default <Cookie> void forEach(final BiPredicate<StockExchange, Cookie> action,
default <Cookie> void forEach(final BiPredicate<Exchange, Cookie> action,
final Cookie cookie) {
for (final StockExchange e : this) {
for (final Exchange e : this) {
if (!action.test(e, cookie)) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public interface IterableMarketSide<Quote> extends Iterable<Quote> {
*
* @return an iterator over the elements in this market side in proper sequence
*/
@Override
Iterator<Quote> iterator();

/**
Expand All @@ -45,7 +46,7 @@ public interface IterableMarketSide<Quote> extends Iterable<Quote> {
* @param fromLevel - Starting price level index to use
* @return an iterator over the elements in this order book in proper sequence
*/
Iterator<Quote> iterator(short fromLevel);
Iterator<Quote> iterator(int fromLevel);

/**
* Returns an iterator over the elements in this market side in proper sequence.
Expand All @@ -54,7 +55,7 @@ public interface IterableMarketSide<Quote> extends Iterable<Quote> {
* @param toLevel - End price level index to use
* @return an iterator over the elements in this order book in proper sequence
*/
Iterator<Quote> iterator(short fromLevel, short toLevel);
Iterator<Quote> iterator(int fromLevel, int toLevel);

/**
* Creates a new sequential or parallel {@code Stream} from a
Expand Down Expand Up @@ -89,13 +90,13 @@ default Stream<Quote> stream() {

void forEach(Predicate<Quote> action);

void forEach(short fromLevel, Predicate<Quote> action);
void forEach(int fromLevel, Predicate<Quote> action);

void forEach(short fromLevel, short toLevel, Predicate<Quote> action);
void forEach(int fromLevel, int toLevel, Predicate<Quote> action);

<Cookie> void forEach(BiPredicate<Quote, Cookie> action, Cookie cookie);

<Cookie> void forEach(short fromLevel, BiPredicate<Quote, Cookie> action, Cookie cookie);
<Cookie> void forEach(int fromLevel, BiPredicate<Quote, Cookie> action, Cookie cookie);

<Cookie> void forEach(short fromLevel, short toLevel, BiPredicate<Quote, Cookie> action, Cookie cookie);
<Cookie> void forEach(int fromLevel, int toLevel, BiPredicate<Quote, Cookie> action, Cookie cookie);
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,14 @@ public interface MarketSide<Quote> extends IterableMarketSide<Quote> {
Quote getBestQuote();

/**
* Get quote by level.
* Get worst quote.
*
* @return Worst quote from side or null if quote not found
*/
Quote getWorstQuote();

/**
* Get quote by level. WARNING: this method can be slow for some implementations (for example, in L3 order book). Use iterator instead.
*
* @param level - level to use
* @return quote or null if quote not found
Expand Down Expand Up @@ -89,30 +96,47 @@ public interface MarketSide<Quote> extends IterableMarketSide<Quote> {
* @param level - quote level to use.
* @return true if this market side contains given quote level
*/
boolean hasLevel(short level);
boolean hasLevel(int level);

/**
* Get quote by quoteId.
* Unsupported operation for L2, always returns null.
*
* @param quoteId - Quote Id
* @return quote or null if quote not found
*/
Quote getQuote(CharSequence quoteId);

/**
* Unsupported operation for L2, always returns false.
*
* @param quoteId - Quote Id
* @return true if this market side contains given quote ID
*/
boolean hasQuote(CharSequence quoteId);

@Override
default Iterator<Quote> iterator() {
return iterator((short) 0);
return iterator(0);
}

@Override
default Iterator<Quote> iterator(final short fromLevel) {
return iterator(fromLevel, (short) depth());
default Iterator<Quote> iterator(final int fromLevel) {
return iterator(fromLevel, depth());
}

@Override
default void forEach(final Predicate<Quote> action) {
forEach((short) 0, (short) depth(), action);
forEach(0, depth(), action);
}

@Override
default void forEach(final short level, final Predicate<Quote> action) {
forEach((short) 0, level, action);
default void forEach(final int level, final Predicate<Quote> action) {
forEach(0, level, action);
}

@Override
default void forEach(final short fromLevel, final short toLevel, final Predicate<Quote> action) {
default void forEach(final int fromLevel, final int toLevel, final Predicate<Quote> action) {
Objects.requireNonNull(action);
for (int i = fromLevel; i < toLevel; i++) {
if (!action.test(getQuote(i))) {
Expand All @@ -123,17 +147,17 @@ default void forEach(final short fromLevel, final short toLevel, final Predicate

@Override
default <Cookie> void forEach(final BiPredicate<Quote, Cookie> action, final Cookie cookie) {
forEach((short) 0, (short) depth(), action, cookie);
forEach(0, depth(), action, cookie);
}

@Override
default <Cookie> void forEach(final short fromLevel, final BiPredicate<Quote, Cookie> action, final Cookie cookie) {
forEach(fromLevel, (short) depth(), action, cookie);
default <Cookie> void forEach(final int fromLevel, final BiPredicate<Quote, Cookie> action, final Cookie cookie) {
forEach(fromLevel, depth(), action, cookie);
}

@Override
default <Cookie> void forEach(final short fromLevel,
final short toLevel,
default <Cookie> void forEach(final int fromLevel,
final int toLevel,
final BiPredicate<Quote, Cookie> action,
final Cookie cookie) {
Objects.requireNonNull(action);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@
*/
package com.epam.deltix.orderbook.core.api;


import com.epam.deltix.orderbook.core.options.Option;
import com.epam.deltix.timebase.messages.MarketMessageInfo;
import com.epam.deltix.timebase.messages.MessageInfo;
import com.epam.deltix.timebase.messages.universal.DataModelType;
import com.epam.deltix.timebase.messages.universal.QuoteSide;

Expand All @@ -28,10 +29,10 @@
* of various trading systems that we have previously worked with. It is designed to provide high-level normalized
* format suitable to capture data from majority of very different trading venues.
* Package Type is enumeration of:
* VENDOR_SNAPSHOT snapshot that came directly from data vendor (e.g. exchange).
* PERIODICAL_SNAPSHOT Synthetic snapshot generated by EPAM Market
* VENDOR_SNAPSHOT - snapshot that came directly from data vendor (e.g. exchange).
* PERIODICAL_SNAPSHOT Synthetic snapshot generated by EPAM Market
* Data Aggregation software to simplify data validation and allow late joiners (consumers that appear in the middle of trading session).
* INCREMENTAL_UPDATE incremental update, a list of insert/update/delete data entries.
* INCREMENTAL_UPDATE - incremental update, a list of insert/update/delete data entries.
* This Format does not support snapshot and increment messages mixed in one package.
* Trade entries can be easily combined with Increments.
* It is important to differentiate one type of snapshot from another.
Expand All @@ -52,7 +53,7 @@ public interface OrderBook<Quote> {
* Note: FlyWeight pattern in use. We don't keep any references on your classes (message) after method returns execution.
* </p>
* <p>
* Supported market data messages: L1/L2/ResetEntry
* Supported market data messages: L1/L2/L3/ResetEntry,
*
* @param message Most financial market-related messages to use.
* @return {@code true} if all entries of the package is process otherwise {@code false}
Expand All @@ -63,7 +64,7 @@ public interface OrderBook<Quote> {
* @see com.epam.deltix.timebase.messages.universal.BookResetEntryInterface
* </p>
*/
boolean update(MarketMessageInfo message);
boolean update(MessageInfo message);

/**
* Returns true if this order book contains no quotes, applies to both sides of Order Book.
Expand Down Expand Up @@ -119,4 +120,11 @@ public interface OrderBook<Quote> {
*/
ExchangeList<? extends Exchange<Quote>> getExchanges();

/**
* @return true if order book from this exchange is waiting for snapshot to recover.
* In this state order book appears empty, but corresponding exchange is likely not empty.
* Order book may be in this state initially, or after we market data disconnect, as well as after internal error.
*/
boolean isWaitingForSnapshot();

}
Loading

0 comments on commit 121e791

Please sign in to comment.