Skip to main content

Order Entry API

The Trading Data Model API document describes the Order Entry API used by the Execution Server, Quote Flow, and other Deltix products. The Market Data model is described in a separate document.

Concept

The Deltix Trading API is influenced by the FIX Protocol and native APIs of various trading systems that Deltix has previously worked with. It is designed to provide a high-level normalized format suitable for interacting with 99% of trading venues.

The primary API language is Java. Currently, Deltix only provides Java and C# bindings for the API.

Order States

Deltix supports the following order states:

StatusFinalDescription
UNACKNOWLEDGEDNOrder has not been submitted yet. This status is similar to OrderStatus.PendingSubmit in the QuantOffice API.
ACKNOWLEDGEDNThe order has been acknowledged by the trading provider and is waiting to become open. (Also was known as \"ACKNOWLEDGED\").
OPENNThe order has been submitted but not yet executed. (Also was known as \"OPEN\").
OPEN_PARTIALLY_FILLEDNThe order has been partially filled.
COMPLETELY_FILLEDYThe order has been completely filled. In the case of cancel-replace chains, this status indicates that the cumulative executed quantity of the entire chain has reached the requested size.
REJECTEDYThe order has been rejected.
CANCELLEDYThe order has been cancelled.

Please note that the status codes marked with "Y" under the "Final" column indicate that the corresponding order status is considered final, meaning it represents the end state of the order. Status codes marked with "N" are non-final statuses, indicating that the order is still in progress or can transition to another status.

The following diagram from shows possible state transitions: State transition diagram

Brief note on "exceptional" transitions. These are very rare but can happen in some markets:

  • OPEN -> REJECTED - Unfortunately we've observed that some crypto exchanges may reject order even after it was accepted on the trading floor.
  • FILLED to not filled transitions are possible when market venue issues Trade Cancellation or Trade Bust events. This kind of corrections are rare but even major exchanges like CME sometimes issue these. See section below for additional information.

Requests And Events

Messages in the system are categorized into two types based on their direction: trading Requests and trading Events. Each request generates one or more response events.

The current version of the API supports four types of trading requests:

  • OrderNewRequest - Places a new order on the market.

  • OrderCancelRequest - Cancels a previously placed order.

  • OrderReplaceRequest - Modifies a previously placed order.

  • OrderStatusRequest - Requests information about the current order status.

For users familiar with the FIX protocol, these requests correspond to the NewOrderSingle(D), OrderCancelRequest(F), OrderReplaceRequest(G), and OrderStatusRequest(H) FIX messages.

When it comes to trading events, the system currently supports the following types:

  • OrderPendingNewEvent - Indicates that the trading venue that has received the order, but it is not active in the market yet.

  • OrderNewEvent - Signifies that the order is active and working in the market of the trading venue destination.

  • OrderRejectEvent - Indicates that the trading venue or market rejected the order.

  • OrderPendingCancelEvent - Indicates that the trading venue is processing the order cancellation request.

  • OrderCancelEvent - Signifies that the trading venue or market rejected the order.

  • OrderCancelRejectEvent - Indicates that the trading venue cannot cancel the order.

  • OrderTradeReportEvent - Reports a trade, indicating that the order is fully or partially filled.

  • OrderPendingReplaceEvent - Indicates that the trading venue received a request to modify an order.

  • OrderReplaceEvent - Signifies that the trading venue modified an order in the market.

  • OrderReplaceRejectEvent - Indicates that the trading venue rejected a a request to modify an order.

  • OrderStatusEvent - Reports the current status of the order, including the filled amount and other relevant information.

  • OrderRestateEvent - Signifies that the trading venue made changes to an order parameter (e.g., triggering a stop order).

Users familiar with the FIX protocol will recognize that most of these events represent different types of Execution Report messages:

API EventFIX Protocol
OrderPendingNewEventExecutionReport(8) with ExecType(150)=A Pending New
OrderNewEventExecutionReport(8) with ExecType(150)=0 New
OrderRejectEventExecutionReport(8) with ExecType(150)=8 Reject
OrderPendingCancelEventExecutionReport(8) with ExecType(150)=6 Cancel
OrderCancelEventExecutionReport(8) with ExecType(150)=4 Cancel or =C Expired
OrderCancelRejectedEventOrderCancelReject(9) with CxlRejResponseTo(434)=1 Cancel Request
OrderTradeReportEventExecutionReport(8) with ExecType(150)=F Trade
OrderTradeCorrectEventExecutionReport(8) with ExecType(150)=G Trade Correct
OrderTradeCancelEventExecutionReport(8) with ExecType(150)=H Trade Cancel
OrderPendingReplaceEventExecutionReport(8) with ExecType(150)=E Pending Replace
OrderReplaceEventExecutionReport(8) with ExecType(150)=5 Replace
OrderReplaceRejectEventOrderCancelReject(9) with CxlRejResponseTo(434)=2 Replace Request
OrderStatusEventExecutionReport(8) with ExecType(150)=I Status
OrderRestateEventExecutionReport(8) with ExecType(150)=D Restated

Order Status vs. Order Event Type

In alignment with the FIX Protocol, the Deltix trading model distinguishes between Order Status and Order Event Type. The following information heavily references the section of FIX Protocol Volume 4: Orders and Execution that describes FIX Execution Reports.

Order events serve the purpose of communicating the following:

  1. Confirming the receipt of an order.
  2. Confirming changes to an existing order, (i.e., accepting cancel and replace requests).
  3. Conveying order status information.
  4. Relaying fill information on working orders.
  5. Rejecting orders.

In each of these cases, a specialized event is used to convey what happened to the order (or the purpose of the event). Meanwhile, the attribute orderStatus available in each event conveys the current state of the order as understood by the execution venue. In scenarios where an order exists simultaneously in multiple order states, the OrdStatus field reports the value with the highest precedence.

The order statuses are as follows (ranked from highest to lowest precedence):

PrecedenceOrder StatusDescription
7Pending CancelIndicates that an Order Cancel Request is pending, serving to confirm receipt of the request. Note: This does not indicate that the order has been canceled.
6Pending ReplaceIndicates that an Order Cancel/Replace Request is pending, serving to confirm receipt of the request. Note: This does not indicate that the order has been replaced.
5FilledDenotes that the order has been completely filled, with no remaining quantity.
4SuspendedIndicates that the order has been placed in a suspended state at the client's request.
3CanceledRepresents a canceled order, with or without executions.
3ExpiredIndicates that the order has been canceled in the broker's system due to time-in-force instructions.
2Partially FilledSignifies an outstanding order with executions and a remaining quantity.
1NewRepresents an outstanding order with no executions.
1RejectedDenotes that the order has been rejected by the sell-side (broker, exchange, ECN). Note: An order can be rejected after order acknowledgment, transitioning from New to Rejected status.
1Pending NewIndicates that the order has been received by the sell-side's (broker, exchange, ECN) system but has not yet been accepted for execution. An execution message with this status is only sent in response to a Status Request message.

For instance, in the case of an algorithmic order that receives a fill while pending cancellation, the OrderTradeReport Event is utilized to communicate the filled amount and price. However, the orderStatus in this event will be set to "Pending Cancel" to reflect the pending cancellation status of the order.

Another scenario to consider is an Immediate-or-Cancel (IOC) order. In certain cases, partial fill and cancellation for IOC orders may be reported using a single OrderTradeReportEvent with the orderStatus set to "Cancelled." This conveys that the IOC order has been canceled, even if there was a partial fill before the cancellation occurred.

Source and Destination

Each message has a source and a destination. For Requests and Events that come in response, the source and destination are usually reversed. In other words, the destination of an event corresponds to the source of the original request, and vice versa.

For trading requests, the Source field is required, while the Destination field is optional. When a destination is not specified, the system will apply custom routing rules to determine the appropriate destination for the message. However, for order cancel and order replace requests, the destination field can be skipped altogether, as the Order Management System (OMS) can infer the destination from the order itself.

In the Trading API, both the Source and the Destination are represented by an INT64 data type.

For example, the Execution Server uses ALPHANUMERIC(10) encoding to convert human-readable sources and destinations into their corresponding INT64 identifiers. Further details on this encoding process are provided in the Special Types section.

Order Destination vs. Order Exchange

  • Order Exchange - Identifies an order's final destination by defining the specific trading venue where the order will be executed, such as the "CME" exchange.
  • Order Destination - Identifies the immediate next step in the order routing process. In order words, this field guides the order toward its intended trading venue, for example, by identifying a specific CME trading connector configured in our system.

It's important to note the following:

  • The Order Exchange field is optional. For example, this field is omitted when Ember works with single trading venue.
  • The Order Destination field is also optional. However, when it is not specified, Ember's Order Router will assign an appropriate destination to the order based on its routing rules and algorithms.

For example, let's consider an order designated for the CME exchange. In this case, the order may be routed to a destination called "TWAP" (Time-Weighted Average Price) which represents a specific execution algorithm. The TWAP algorithm will then take the order and divide it into smaller chunks, sending them to the CME trading connector for execution.

In summary, while the Order Exchange field defines the final trading venue, the Order Destination field guides the order to its destination within the system's routing infrastructure.

Identity

When it comes to identifying orders and requests, the Order Entry API follows the conventions of the FIX protocol.

Order ID

Each order submitted by an API client or algorithm is associated with a unique textual identifier known as the Order ID. The uniqueness of the Order ID is scoped within a specific order source, which is identified by the Source ID. In other words, the Order ID is unique within the context of a particular order source.

When an order is modified, the client provides a new Order ID and must explicitly specify the original Order ID that is being modified. Once the modification is approved, the working order will be identified by the ID of the replacement order request. In cases where the modification (replace) request is rejected, the order retains its original identity. This approach is consistent with the handling of order modifications in the FIX protocol, which is familiar to users experienced with FIX-based trading systems.

Correlation Order ID

For the convenience of handling a large chain of cancellation and replace requests, the API supports an optional attribute called the Correlation Order ID. This attribute serves as a means of matching the ID of the first order in the replacement chain. The Correlation Order ID helps in tracking the relationship between the original order and subsequent modifications or replacements. The concept of a Correlation ID can also be found in other trading APIs like CME iLink.

Cancel Replace workflow

When an order undergoes the Cancel Replace workflow, each OrderReplaceRequest uses a separate unique order ID and identifies which [predecessor] order request it replaces using the Original Order ID attribute. For example, if an order was replaced twice, the cancel replace chain will have three order identifiers - original order and two replacement requests.

For any Cancel Replace chain of messages, an optional attribute called Correlation Order ID identifies the very first order in the chain. This attribute can be provided by the API user, and the OMS automatically populates this attribute for downstream messages.

External Order ID

Trading Venues may assign their identifiers to orders represented as an \"external order ID\". These identifiers are unique only within the scope of each trading venue, identified by the Destination ID and Exchange.

An external order ID is typically reported with order events and may or may not change each time the order is modified using a CancelReplaceRequest.

Request ID

To distinguish repeated attempts to cancel the same order, each CancelRequest is identified by a Request ID. The required identifier is subsequently reported in the ACK/NACK events, such as OrderCancelEvent and OrderCancelRejectEventcancel.

Trade ID

Trades (fills, executions) are identified using the eventId field. This event identifier should be unique in the scope of a single order or the order's cancel-replace chain. Deltix OMS uses this field to identify duplicate trade reports.

Message timestamps

FieldRequestsEvents
timestampTypically indicates the moment when the request is first processed by Ember. For instance, in the FIX API gateway, this field captures the time when the request is decoded from the FIX message.Indicates when the event was processed by the Trade Connector, i.e., when the event entered Ember.
originalTimestampUsually reflects when the request was initiated by the source. For example, in the FIX API gateway, it is populated from the TransactTime(60) tag of an inbound new order request (35=D).Represents the actual time when the event occurred on the exchange (market venue).

When Ember algorithms create new trading requests (e.g., submitting an order to the market), they can initialize the originalTimestamp field to match the market data signal timestamp (commonly using MarketData.receiveTime). This facilitates tick-to-order latency monitoring.

Prior to Ember version 1.14, order requests did not include the originalTimestamp field. In earlier versions, the Ember API gateway would set the request timestamp to the current request arrival time, but only if the client had not already defined the field when submitting the request.

More about timestamp data format can be read later in this document.

Required and Optional Attributes

Each message in the API is composed of a set of required and optional fields. For example, in each order event field, the Order ID is a required field, while the External Order ID field is optional.

Refer to sources/javadoc to get information on each field. Typically, optional fields have additional logical methods that check whether a field is defined or not. For example, you can use the OrderEvent.hasExternalOrderId() method. The Ember Java binding of this API uses the @Required or @Optional annotations when defining field getters and setters.

Field Enrichment

When a trading message passes through the Deltix OMS system on its way to a destination, it undergoes the enrichment step. The OMS attempts to define all optional attributes based on the context. For example, the OMS can define instrument type based on the order symbol. For messages that affect a previously known order, the OMS can copy the missing fields from the last known order state. That is, the OMS can derive order symbol and side (BUY or SELL) for a CancelRequest from the symbol and side specified during the order submission. Some trading venues require the order side, symbol, and other fields for each cancellation request.

Quantities

In accordance with FIX protocol, when you modify an order, you need to specify the total desired order quantity.

The following table illustrates various quantity-related attributes on requests and events. The original order quantity is 5, which is subsequently increased to 10. During this time, the order receives partial fills.

MessageQuantityTrade QuantityCumulative QuantityRemaining QuantityOrder State
OrderNewRequest5UNACKNOWLEDGED
OrderNewEvent (ACK)505NEW
OrderTradeReportEvent5223PARTIALLY FILLED
OrderTradeReportEvent5132PARTIALLY FILLED
OrderReplaceRequest10PARTIALLY FILLED
OrderReplaceEvent (ACK)1037PARTIALLY FILLED
OrderTradeReportEvent107100COMPLETELY FILLED

Custom Attributes

The FIX Protocol specifies many more fields than are represented in the Deltix Trading API. While Deltix has made an effort to include the most common fields,in cases where specific fields are not available, custom attributes can be used.

Each trading message in the Deltix Trading API can contain a list of custom attributes. Each attribute is identified by a numeric key and stores a text value.

Mutable and Immutable Messages

For each message in the Trading API, there is usually an immutable interface presented to message consumers, and a mutable message interface that is available to message producers.

For example, the immutable interface for an order cancellation event is called OrderCancelEvent, while the corresponding mutable message interface is called MutableOrderCancelEvent. Similarly, in the TimeBase API, these messages are referred to as OrderCancelEventInfo and OrderCancelEventInterface.

Supported codecs

The Trading API supports multiple codecs for different purposes:

  • TimeBase - Trading Messages can be stored and loaded from TimeBase.
  • Binary - The Deltix Execution Server includes a set of high-performance codecs for working with in-memory buffers or communication frameworks like Aeron.
  • JSON - Messages can be converted back and forth to JSON.
  • FIX - The FIX Server components include codecs for working with FIX 4.4.

Special Types

Decimal

In the Java language, there is no data type for the accurate representation of money. The built-in \'double\' data type introduces rounding errors, while BigDecimal is slow and immutable, requiring frequent memory allocations.

Deltix addresses this limitation by using the Decimal64 IEEE 754 format to represent prices and sizes using the INT64 (Java \'long\') data type.

For more information about Decimal64, you can visit the following GitHub repository: https://github.com/epam/DFP.

Here are some key points to remember:

  • Use the @Decimal annotation to mark fields, parameters, and methods that pass Decimal64 values using the INT64 data type.
  • Use the com.epam.deltix.decimal.Decimal64Util library for conversions to various data types and frequently used operations.

Here's an example of how decimal expressions may look in your code:

import com.epam.deltix.dfp.Decimal64Util.*;

@Decimal final long totalValue = add(order.getTotalExecutedValue(), multiply(event.getTradePrice(), event.getTradeQuantity()));

With a little practice, these prefix math operations are easy to follow.

Timestamp

All timestamps are stored as INT64 (Java \'long\') data type for effectiveness. The numeric value represents the number of milliseconds since midnight on January 1st, 1970 (Linux epoch time).

To indicate fields, parameters, and methods that represent timestamp values using the INT64 data type, use the @Timestamp annotation.

This timestamp format corresponds to the millisecond time used by java.util.Date and java.util.Calendar.

note

Update: since Ember 1.14 all timestamps internally switched to use nanosecond epoch time. API compatibility was preserved so you may observe both nanosecond and millisecond version of timestamp attribute getters and setters:

/**  
* Message timestamp (in epoch time).
* Similar to tag TransactTime(60) in FIX ExecutionReport.
* Input value should have NANOSECOND resolution!
*/
void setTimestampNs(@Timestamp(TimeUnit.NANOSECONDS) long timestamp);

/**
* Legacy API method takes millisecond resolution Timestamp
*/
void setTimestamp(@Timestamp long timestamp);

Alphanumeric

In many cases, short textual identifiers like exchange codes or component names (used as Source or Destination IDs), can be efficiently stored in a single INT64 data type. Deltix uses ALPHANUMERIC(10) TimeBase encoding for this purpose.

ALPHANUMERIC(10) text values must not exceed 10 characters. Valid characters include upper case letters, and digits, and punctuation characters (ASCII range 0x20..0x5F).

For example, the text "COINBASE" is encoded as 0x88EFA6E8A1CE5000 and represented inside the INT64 data type as shown below:

Alphanumeric Encoding

As you can see, the lengh is stored in bits 60-63, and each character is compressed to 6 bites.

To indicate fields, parameters, methods that transmit ALPHANUMERIC-encoded text values using INT64 data type in Java, use the @Alphanumeric Java annotation.

The following Java algorithm demonstrates this encoding process:

public static long parse(final CharSequence text) {  
if (text == null)
return TypeConstants.ALPHANUMERIC_NULL;

int length = text.length();
if (length > 10)
throw new IllegalArgumentException("Text \"" + text + "\" exceeds max length of alphanumeric text");

long value = (long) length << 60L;
for (int i = 0, shift = 54; i < length; i++, shift -= 6) {
final char c = text.charAt(i);
if (c < 0x20 | c > 0x5F) {
throw new IllegalArgumentException("Text \"" + text + "\" contains non-alphanumeric char at " + i);
}
value |= (c - 0x20L) << shift;
}

return value;
}

Trade Corrections and Cancellations

Trade Corrections or Trade Cancellations are special type of events that some market places may issue to nullify previous Order Trade Report event. Both events provide Reference Trade ID of the original trade (the trade that is getting corrected and cancelled). Typically Trade Correction communicate adjusted price or quantity, however it is possible for Trade Correction to communicate correct trade quantity as zero (and hence de-facto notify of trade cancellation).

Remaining Order Quantity and Order Status are two important attributes that help to understand outcome of trade correction / cancellation for completely filled orders. When remaining order quantity is communicated as zero or when order status is communicated as CANCELLED or COMPLETELY_FILLED order remains inactive. When remaining quantity is greater than zero, or when order status is reported as NEW or PARTIALLY_FILLED order become active. This is rare exceptional order state transition from COMPLETELY_FILLED to NEW or PARTIALLY FILLED. Remaining quantity attribute if provided has precedence in this decision making.

Samples

In this section, you will find several fragments that illustrate how the Order Entry API is used.

Order Submission

The following sample demonstrates the filling of an Order New Request for submitting a new order:

MutableOrderNewRequest request = new MutableOrderNewRequest();
request.setOrderId(idGenerator.next());
request.setSide(side);
request.setQuantity(FP.fromLong(size));
request.setSymbol(symbol);
request.setLimitPrice(FP.fromDouble(price));
request.setTimeInForce(TimeInForce.DAY);
request.setOrderType(OrderType.LIMIT);
request.setDestinationId(getServiceByName("marketfactory"));
request.setExchangeId(ExchangeCodec.codeToLong("HOTSPOT"));
request.setSourceId(CLIENT_SOURCE_ID); // Identify order source
request.setTimestamp(System.currentTimeMillis());

Order Fill Event

The following sample reports a fill event:

tradeEvent.setSourceId(MARKET_FACTORY_SOURCE_ID);
tradeEvent.setSymbol(symbol);

tradeEvent.setTradeQuantity(tradeQuantity);
tradeEvent.setTradePrice(tradePrice);
tradeEvent.setDestinationId(orderEntry.getSourceId());
tradeEvent.setOrderId(orderEntry.getOrderId());
tradeEvent.setExternalOrderId(orderEntry.getExternalOrderId());
tradeEvent.setSide(orderEntry.getSide());
tradeEvent.setEventId(tradeId);
tradeEvent.setCumulativeQuantity(orderEntry.getCumulativeQuantity());
tradeEvent.setAveragePrice(orderEntry.getAveragePrice());
tradeEvent.setRemainingQuantity(orderEntry.getRemainingQuantity());
tradeEvent.setAggressorSide(AggressorIndicator.ORDER_INITIATOR_IS_AGGRESSOR);
tradeEvent.setTimestamp(clock.time());

UML Diagram

Class diagram

Mapping to FIX protocol

The Trading Data Model used by Deltix is heavily influenced by messages of the FIX Protocol. Deltix has selected a subset of the most used FIX tags and mapped them as "first class" attributes in the Trading Data Model. Less frequently used tags can still be specified using custom message attributes.

Standard Attributes

The table below describes the mapping of standard message attributes to FIX.

FIX TagDeltix APIDescription
MsgType(35)Mapped to a specific class, for example OrderNewSingle(35=D) is mapped to OrderNewRequest.
ClOrdId(11)Mapped to a pair {SourceId,OrderId}See Order Id section
OrigClOrdId(41)Mapped to a pair {SourceId, OriginalOrderId}
Account(1)Account
Price(44)LimitPrice
StopPx(99)StopPrice
PegDifference(211)PegDifferenceDepends on trading connector
QuoteId(117)QuoteIDIdentifies quote for previously quoted order
MinQty(110)MinQuantityDepends on trading connector
MaxFloor(111)DisplayQuantityDepends on trading connector
TimeInForce(59)TimeInForce
ExpireDate(432) or ExpireTime(126)ExpireTime
Currency(15)CurrencyDepends on trading connector
Side(54)Side
OrderQty(38)QuantityTrading connectors may perform quantity translation (using size multiplier)
OrdType(40)OrderType
Clearing Account (440)ClearingAccount
SenderSubID(50)TraderIdDepends on trading connector
ExDestination(100)ExchangeDepends on trading connector
Symbol(55)SymbolTrading connectors may perform symbol translation
SecurityType(167)InstrumentType
TransactTime(60)Timestamp
ExBroker(76)DestinationDepends on trading connector
Text(56)UserDataDepends on trading connector
Commission(12)CommissionOn events only
LastPx(31)TradePriceOn events only
LastShares(32)TradeQuantityOn events only
TradeDate(75)TradeDateOn events only
FutSettlDate(64)SettlementDateOn events only
AggressorIndicator(1057)AggressorSideOn events only
MultiLegReportingType(442)MultiLegReportingTypeOn events only
OrdStatus(39)OrderStatusOn events only
ExecType(150) and ExecTransType(20)Mapped to event type (e.g. OrderTradeReportedEvent is 150=F)On events only
ExecId(17)EventIdOn events only
CumQty(14)CumulativeQuantityOn events only
AvgPx(6)AveragePriceOn events only
LeavesQty(151)RemainingQuantityOn events only
TransactTime(60)OriginalTimestampOn events only

Custom Attributes

The following code example demonstrates use of custom order attributes.

import deltix.ember.util.CustomAttributeListBuilder;

private static void addCustomAttributes(MutableOrderNewRequest request) {
attributeListBuilder.clear();

// Repeated group
attributeListBuilder\
.addInteger(Tag.NoPartyIDs, 2)
.addText(Tag.PartyID, "AAA\")
.addInteger(Tag.PartyRole, PartyRole.CLIENT_ID)
.addText(Tag.PartyID, "BBB")
.addInteger(Tag.PartyRole, PartyRole.AGENT);

attributeListBuilder
.addTimestamp(7050, System.currentTimeMillis() + 1000);

request.setAttributes(attributeListBuilder.build());
}

Multi-legged Contracts

The data model supports multi-legged securities (e.g., Calendar spreads on the CME exchange).

When submitting a trade request for a multi-legged security, you can use the multi-legged security symbol, such as "ZFH20-ZFM20" for a calendar spread on US Treasury Bond Future contracts. Optionally, you can supply the instrument type "MLEG" (MULTI_LEG_INSTRUMENT) with each request.

When processing fills for multi-legged orders, you need to pay attention to the MultiLegReportingType and Symbol attributes of events.

Here is an example of a fill event for an individual leg:

OrderTradeReport.setMultiLegReportingType(INDIVIDUAL_LEG_SECURITY);
OrderTradeReport.setSymbol("ZFH20") <-- identifies *leg* instrument

Here is an example of fill event for a multi-legged contract:

OrderTradeReport.setMultiLegReportingType(MULTI_LEG_SECURITY);
OrderTradeReport.setSymbol("ZFH20-ZFM20") <-- identifies *spread* instrument

When implementing a custom trade connector that reports trades for multileg instrument you need to issue a series of trade report events. There must be trade reported for synthetic instrument itself (tagged with MultiLegReportingType.MULTI_LEG_SECURITY) and a trade event for each leg of the synthetic instrument (tagged with MultiLegReportingType.INDIVIDUAL_LEG_SECURITY and event symbol identifying the leg). Trade quantity and side reported for each individual leg must follow synthetic composition formula. This behavior follows API of exchanges like CME and ICE.