AlgoTraderAlgoTrader Documentation

Chapter 16. Order Management

16.1. Order Validation
16.2. Place Order
16.2.1. Order Preferences
16.2.2. Trade Suggestions
16.2.3. Order Properties
16.3. Order requests and confirmations
16.4. Order Status
16.5. Receive Fills
16.6. Handling of Fees and Commissions
16.7. Examples of Orders and Executions
16.7.1. Margin Order with Fee in Quote Currency
16.7.2. Exchange Order with Fee in Base Currency
16.7.3. Exchange Order with Fee in Alternate Currency
16.8. Internal Order Id Format
16.9. Symbology

Before sending an Order, it is advised to call the validate method on the order. This will validate the order regarding limits, amount, quantity, etc. In case validation fails an Exception will be thrown and the order can be modified.

In addition to the validate method all configured Section 12.1, “Pre-Trade Checks” will be invoked. In case any pre-trade check is breached the order will be rejected.

The method sendOrder of the OrderService is responsible for placing Orders. This method takes an Order Entity or Order Value Object as parameter.

Sending an order using and Order Entity looks like this:

MarketOrder order = MarketOrder.Factory.newInstance();

order.setStrategy(strategy);
order.setAccount(account);
order.setSecurity(security);
order.setQuantity(orderQuantity);
order.setSide(Side.BUY);
getOrderService().sendOrder(order);

The associated Entities (i.e. strategy, account and security) can be retrieved via the LookupService.

Sending an order using Order Value Objects looks like this:

MarketOrderVO order = MarketOrderVOBuilder.create()

.setStrategyId(strategyId)
.setAccountId(accountId)
.setSecurityId(securityId)
.setQuantity(orderQuantity)
.setSide(Side.BUY)
.build();
getOrderService().sendOrder(order);

Creating and sending an AlgoOrder looks like this:

SlicingOrder order = new SlicingOrder();

order.setStrategy(strategy);
order.setAccount(account);
order.setSecurity(security);
order.setQuantity(orderQuantity);
order.setSide(Side.BUY);
order.setMinQuantity(BigDecimal.valueOf(10));
order.setMaxQuantity(BigDecimal.valueOf(100));
order.setMinVolPct(0.01);
order.setMaxVolPct(0.1);
order.setMinDuration(1.0);
order.setMaxDuration(5.0);
order.setMinDelay(1.0);
order.setMaxDelay(5.0);
getOrderService().sendOrder(order);

Sending an algo order using Order Value Objects looks like this:

SlicingOrderVO order = SlicingOrderVOBuilder.create()

.setStrategyId(strategyId)
.setAccountId(accountId)
.setSecurityId(securityId)
.setQuantity(orderQuantity)
.setSide(Side.BUY)
.setMinQuantity(BigDecimal.valueOf(10))
.setMaxQuantity(BigDecimal.valueOf(100))
.setMinVolPct(0.01)
.setMaxVolPct(0.1)
.setMinDuration(1.0)
.setMaxDuration(5.0)
.setMinDelay(1.0)
.setMaxDelay(5.0)
.build();
getOrderService().sendOrder(order);

The broker / exchange specific SimpleOrderExecService will create the broker / exchange specific order, assign an intId if none has been assigned yet and send the order to the broker / exchange.

After sending the Order to the broker / exchange, the order object is propagated to the AlgoTrader Server Esper service instance (running inside the AlgoTrader Server) as well as to the Esper service instance of the corresponding strategy (where potential actions like cancel order or modify order can be executed).

Open orders are kept in an internal order book until their full execution or cancellation. Completed orders remain in the book and are accessible through OrderService until evicted. AlgoTrader evicts completed orders at 24:00 local time daily by default. One can also manually evict orders by calling OrderService#evictExecutedOrders() method.

The actual exchange an Order is sent to will be retrieved from the associated Security/SecurityFamily. Alternatively it is possible to assign an Exchange to an Order Entity or Order Value Object directly.

Even though the Order Entity already contains commonly used properties like side, quantity, time-in-force, etc. it is possible to attach additional arbitrary properties to an Order. Order properties have a name, a value and a type.

Order properties of type INTERNAL are kept inside the system and are not propagated to external brokers.

If the type of an Order property is FIX it is assigned to an outgoing Fix order as an additional fix tag. It is therefore mandatory that the name of the order property is a number (representing the fix tag).

If the type of an Order property is FIX_LITERAL it is parsed and assigned to an outgoing Fix order as a list of fix tags. It is therefore mandatory that the value of the order property is a string consisting of comma delimited entries tag=value.

If the type of an Order property is IB the system will try to find an IB order field corresponding to the IB order property name. In case no matching field is found the order property is added as an AlgoParams)

An internal order property can be attached to an order as follows:

order.addOrderProperty("test", "XYZ", OrderPropertyType.INTERNAL);

An Fix order property can be attached to an order as follows:

order.addOrderProperty("4000", "XYZ", OrderPropertyType.FIX);

An IB order property can be attached to an order as follows:

order.addOrderProperty("faGroup", "group1", OrderPropertyType.IB);

Any object can be attached to an order as a property value using addProperty(String name, Object value) method, it can be done as follows:

order.addProperty("myProperty", "propertyValue");

Order Property can be removed from order as follows:

order.removeProperty("name");

The method getOrderProperties cannot be used to manage order properties it's returning unmodifiable map of OrderProperty objects excluding all other properties provided to order, to remove or update properties it's needed to use methods above.

Note

OrderProperties are only supported on Order Entities but not on Order value objects (VOs).

Apart from sending a new Order, there are several other Order operations that you can request from OrderService:



                @Override
                public void onOrderRequestStatus(OrderRequestStatusEventVO event) {
                }
            

The current status of an order is represented by one ore many OrderStatus events. Whenever order status events are received back from the broker / exchange, OrderStatus events are created and propagated to the AlgoTrader Server Esper service Instance and subsequently to the strategy that initiated the order.

Permitted Order Status transitions are depicted by the following state machine diagram.


If an order does not receive either an Acknowledgment or Fill within a configurable time period (default: 1 sec) after sending the Order, an Exception is thrown, as there might be a problem with the broker / exchange connection. This is enforced by the NOTIFY_MISSING_ORDER_REPLY statement which can be turned off by changing the following property inside conf-core.properties. Alternatively the properties can be changed via Section 2.3, “VM Arguments”

# notify in case there is no reply on an order
statement.notifyMissingOrderReply = false

Once all fills corresponding to an Order are fully persisted an OrderCompletionVO event is generated and propagated to the Strategy. By the time an OrderStatus event is received by the strategy, corresponding database activity might not have been completed yet. However by the time an OrderCompletionVO event is received, it is guaranteed that all database activity has been completed. It is therefore safe to invoke any sort of the database lookup at this time. For further details see Section 8.4.8, “Callbacks”.

Whenever fills are received back from the broker / exchange, Fill events are created and propagated to the AlgoTrader Server Esper service Instance and subsequently to the strategy that initiated the order.

The Fill events trigger the creation of a Transaction object (a persistent Record in the database). In addition the Fill and corresponding Transactions are also propagated to the strategy, where actions can be taken upon.

AlgoTrader supports handling of the following three types of fees and commissions:

All three types are available in the database table transaction.

Most adapter for traditional asset classes (e.g. equities, forex and derivatives) do not provide fee information on execution messages. Some crypto exchanges provide fee information. If the fees are in the currency of the transaction, they are stored in the fee attribute of the transaction. In case the fees are charged in another currency (for example Binance charges in its own currency - BNB), a new transaction is created with transactionType = FEES, quantity = -1 for fees paid (and quantity = -1 for fees received, e.g. maker rebates), price = fee value and currency = fee currency.

For the other adapters, AlgoTrader uses the internal Execution Model (see Section 5.1, “Exchange Simulator”) to assign fees and commissions based on configuration (e.g. commission-per-contract).

The following sections show a few example orders and their corresponding executions/fills. All examples start from a "clean" database with empty transaction, cash_balance and position tables.

intId is the internally assigned order identifier whereas extId is the id assigned by the external broker / exchange.

In general the internal order identifier has the following format:

Example: lmax1.1

By default AlgoTrader automatically assigns an IntId value to all outgoing orders. Open and executed orders can be identified and looked up by their IntId.

Especially when using a Section 8.4.8.2, “Trade callback” it is necessary to generate and assign an IntId value to the order prior to submitting it to the order service. The OrderService#getNextOrderId() method can be used to generate a unique IntId value per session associated with an Account record.

String orderId = getOrderService().getNextOrderId(order.getClass(), accountId);


order.setIntId(orderId);
engine.addTradeCallback(Collections.singleton(orderId), (strategyName, orderStati) -> {
    ...
});
getOrderService().sendOrders(orders);

Note

Please note that care must be taken when using OrderService#getNextOrderId() with the IB order service. The IB native interface expects orders to be sent with their order ids in ascending order. The Class IBOrderIdSynchronizer is responsible to make sure order ids are actually in ascending order. In case an order id is skipped the IBOrderIdSynchronizer will wait for up to maxOrderSyncTime milliseconds for the order with the correct order id to arrive.

In the electronic trading domain there are different ways to identify a security, some of which are:

Different Brokers employ different types of Symbology to identify a security. For this purpose AlgoTrader provides the notion of SymbologyResolver which is responsible for assigning appropriate information to outgoing broker / exchange communication. These SymbologyResolvers can be extended on a per adapter basis.