AlgoTraderAlgoTrader Documentation

Chapter 23. Execution Algos

23.1. Existing Execution Algos

AlgoTrader provides several built-in Execution Algos.

SlicingOrder

Splits an order into several child orders. child order quantities and time in the market are randomized. The SlicingOrder has the following order properties:


The quantity of each child order is randomized between minVolPct and maxVolPct of the current volume offered at the exchange. In addition minQuantity and maxQuantity restriction can be imposed. If maxVolPct is zero, then the current market volume will not be considered when sizing the order. If maxQuantity is zero, then no maximum quantity will be enforced on top of the market volume restriction. The SlicingOrder will make sure that the remainingQty for the next child order is greater than minQuantity. Maximum quantity rules have precedence over minimum quantity rules.

Example:

minVolPct: 25%, minQuantity: 20, maxVolPct: 100%, maxQuantity: 100, BUY order, quantity: 40, vol ask: 10

minimum quantity: Max(25% x 10, 20) = 20

maximum quantity: Min(100% x 10, 100) = 10

This will result in an order of quantity 10

Each order will stay in the market for minDuration to maxDuration seconds (if it is not filled before that). Between each child order there will be a random delay of minDelay to maxDelay seconds. In addition, the SlicingOrder has a sophisticated pricing logic. For a BUY order the first child order will be place 1 tick below the Ask. For a SELL order the first tick will be placed one tick above the Bid. Depending on whether a child order gets filled, the price of the next child order is adjusted. If a child order gets filled, the price of the next child order will be reduced by one tick (for BUY orders) but it will always be at least one tick above the Bid. If the child order does not get filled, the price of the next child order is increased by one tick (for BUY orders) but it will never be higher than the ask. A SlicingOrder can be created and sent as follows :

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);
order.setMaxDuration(5);
order.setMinDelay(1);
order.setMaxDelay(5);
getOrderService().sendOrder(order);

Alternatively Section 17.1.1, “Order Preferences” can be used to create a SlicingOrder. The AlgoTrader sample data contains an OrderPreference named SLICING (with the default values shown in the table above) which allows placing a SlicingOrder as follows:

Order order = getOrderService().createOrderByOrderPreference("SLICING");

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

The VWAPOrder seeks to achieve the Volume-Weighted Average price (VWAP). VWAP is a trading benchmark used by many institutional investors. VWAP is calculated by adding up the market value traded for every transaction (price multiplied by number of contracts traded) and then dividing by the total contract traded. The VWAPOrder is based on the AdaptiveOrder (see) below and uses its pricing logic. The VWAPOrder has the following order properties in addition to the ones defined by the AdaptiveOrder.


The VWAPOrder retrieves historical prices for the number of days specified in the lookbackPeriod parameter and splits the trading day into buckets with a length in minutes according to the bucketSize parameter.

When a VWAPOrder is either fully-executed or cancelled a message containing the average price, the benchmark price as well as the execution duration and number of executions is logged to the console. For the VWAPOrder to work a historical data adapter will need to be enabled, see Section 7.2.7, “Historical Data Service”.

A VWAPOrder can be created and sent as follows :

VWAPOrder order = new VWAPOrder();

order.setStrategy(strategy);
order.setAccount(account);
order.setSecurity(security);
order.setQuantity(orderQuantity);
order.setSide(Side.BUY);
order.setBucketSize(Duration.MIN_10);
order.setLookbackPeriod(10);
order.setDuration(600)
order.setSliceLength(10)
order.setCancelTime(0.5)
order.setTimeRand(0.25)
order.setQtyRand(0.25)
order.setIncrement(0.05)
order.setInitialOffset(0.8)
order.setMinOffset(0.05)
order.setMaxOffset(1.0)
getOrderService().sendOrder(order);

Alternatively Section 17.1.1, “Order Preferences” can be used to create a VWAPOrder. The AlgoTrader sample data contains an OrderPreference named VWAP (with the default values shown in the table above) which allows placing a VWAPOrder as follows:

Order order = getOrderService().createOrderByOrderPreference("VWAP");

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

The TWAPOrder seeks to achieve the Time-Weighted Average price (TWAP). TWAP is a trading benchmark used by many institutional investors. TWAP is derived by calculating the average execution price over a certain time period irrespective of the executed quantity.

The TWAPOrder is based on the AdaptiveOrder (see) below and uses its pricing logic. The TWAPOrder has no additional order properties in addition to the ones defined by the AdaptiveOrder.

When a TWAPOrder is either fully-executed or cancelled a message containing the average price, the benchmark price as well as the execution duration and number of executions is logged to the console. As the reporting functionality needs historical data a historical data adapter will need to be enabled, see Section 7.2.7, “Historical Data Service”. The TWAPOrder can still be used without historical data but not report will be logged to the console.

A TWAPOrder can be created and sent as follows :

TWAPOrder order = new TWAPOrder();

order.setStrategy(strategy);
order.setAccount(account);
order.setSecurity(security);
order.setQuantity(orderQuantity);
order.setSide(Side.BUY);
order.setDuration(600)
order.setSliceLength(10)
order.setCancelTime(0.5)
order.setTimeRand(0.25)
order.setQtyRand(0.25)
order.setIncrement(0.05)
order.setInitialOffset(0.8)
order.setMinOffset(0.05)
order.setMaxOffset(1.0)
getOrderService().sendOrder(order);

Alternatively Section 17.1.1, “Order Preferences” can be used to create a TWAPOrder. The AlgoTrader sample data contains an OrderPreference named TWAP (with the default values shown in the table above) which allows placing a TWAPOrder as follows:

Order order = getOrderService().createOrderByOrderPreference("TWAP");

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

The AdaptiveOrder is the parent class of the VWAPOrder and TWAPOrder and defines the pricing logic for those. However it is not possible to send an AdaptiveOrder directly. The AdaptiveOrder has the following order properties


The AdaptiveOrder uses a pricing logic similar to the Slicing Execution Algo.

The first child order will be placed at the initialOffset between the Bid and the Ask (e.g. at 80%). Depending on whether a child order gets filled, the price of the next child order is adjusted. If the previous child order got fully or partially filled, the price of the next child order will be reduced by increment % of the spread. If the previous child order did not get filled, the price of the next child order is increased by increment % of the spread. The limit price will always be adjusted within the following price range:

 >= Bid price + minOffset and <= Bid price + maxOffset

The AdaptiveOrder will execute over a predefined time period which can be set by two of the following arguments: startTime, endTime or duration.

New child orders will be sent in randomized time intervals:

Between sliceLength*(1-timeRand) and sliceLength*(1+timeRand)

In case a child order is not fully executed it will get cancelled after the following period of time:

Between sliceLength*cancelTime*(1-timeRand) and sliceLength*cancelTime*(1+timeRand)

The quantity of each child order is randomized in the following interval

between sliceQty*(1-qtyRand) and sliceQty*(1+qtyRand)

Calculated child order quantities respect the optional minSliceQty. In addition, the AdaptiveOrder also respects the optional property maxVolPct which will cause to algo not to place child orders larger than the current VolAsk (for Buy orders) or VolBid (for Sell orders).

As the Algo needs to be execute within a predefined time period the child order quantities are adjusted throughout the order execution. Quantity adjustments take into consideration previously executed quantity in order to fully executed the algo within its time constraints. No further quantity adjustments take place once 90% of the order execution time has passed.

TargetPositionOrder

The TargetPositionOrder seeks to bring the actual position to an intended target quantity. The TargetPositionOrder starts off by looking up the actual position quantity, calculating the delta between the actual and target quantity and issuing a market order to fill the difference. In many cases the TargetPositionOrder differs little from sending a simple market order. Orders can take some time to fully execute. In the meantime the target position may change. The target quantity of a TargetPositionOrder can be altered at any point of time which will cause the order to re-evaluate its actual state and cancel or modify currently pending order and issue a new order if necessary to match the expected target position. The order also reacts intelligently to stray fills that can occur.

By default TargetPositionOrder is considered to be fully executed once its target position has been reached. The order is then removed from the order book. Often however strategies might want to maintain a particular position over a longer period of time. TargetPositionOrder can be issued with keepAlive attribute set to true to make the order active until explicitly canceled. The order will transition into Status#TARGET_REACHED state once fully executed and will stay there until the target is adjusted or the order is canceled. A TargetPositionOrder can be created and sent as follows :

TargetPositionOrder order = new TargetPositionOrder();

order.setStrategy(strategy);
order.setAccount(account);
order.setSecurity(security);
order.setQuantity(orderQuantity);
order.setSide(Side.BUY);
order.setKeepAlive(true);
order.setTarget(BigDecimal.valueOf(111.1));
getOrderService().sendOrder(order);

Alternatively OrderPreferences can be used to create a TargetPositionOrder.

TrailingLimitOrder

A TrailingLimitOrder submits an order directly to the exchange with a limit price set a fixed distance away from the current market price. The limit price is adjusted relative to the market price when the market moves in favor of the order. The TrailingLimitOrder is typically used when entering a position on an instrument with a Bullish view.

For a BUY order the limit price will be set a specific amount (defined by the trailingAmount parameter) below the current market price. In case the market price rises, the limit price is increased once the specified minimum amount (defined by the increment parameter) is exceeded. If the market price falls, the limit price stays untouched. If the market price falls below the limit price the order will get filled by the exchange (depending on adequate liquidity).

For a SELL order the limit price will be set a specific amount (defined by the trailingAmount parameter) above the current market price. In case the market price falls, the limit price is decreased once the specified minimum amount (defined by the increment parameter) is exceeded. If the market price rises, the limit price stays untouched. If the market price rises above the limit price the order will get filled by the exchange (depending on adequate liquidity).

A TrailingLimitOrder can be created and sent as follows :

TrailingLimitOrder order = new TrailingLimitOrder();

order.setStrategy(strategy);
order.setAccount(account);
order.setSecurity(security);
order.setQuantity(orderQuantity);
order.setSide(Side.BUY);
order.setTrailingAmount(BigDecimal.valueOf(0.5));
order.setIncrement(BigDecimal.valueOf(0.1));

Alternatively OrderPreferences can be used to create a TrailingLimitOrder.

TickwiseIncrementalOrder

Sends the entire Order as one Slice. The price of the order is set according to the current market price. The order is first set at startOffsetTicks ticks above the market (for BUY orders). If the order is not filled within a defined period of time, the price of the order is increased by one tick up to a maximum of endOffsetTicks ticks below the other side of the market.

VariableIncrementalOrder

Sends the entire Order as one Slice. The price of the order is set according to the current market price. The order is first set at startOffsetPct (% of the spread) above the market (for BUY orders). If the order is not filled within a defined period of time, the price of the order is increased by increment (%of the spread) up to a maximum of endOffsetPct (% of the spread) below the other side of the market.