Skip to main content

Appendix

Appendix A: Sample Implementation of Order Timeout

In this section, we will demonstrate how to implement order timeout.

Let's imagine that our API allows users to specify an optional order duration attribute. We will show you how to parse the order duration, define a timer, and cancel order if necessary.

For simplicity, we will assume that the order duration is an immutable order attribute.

Parse Custom Order Attribute

First, let's add custom attribute parsing to our Algorithm. We will use the custom attribute key `6002`` for the order duration.

private static final int DURATION_ATTRIBUTE_KEY = 6002;

A good place to handle custom order attributes is within the processNewOrder() callback. This method provides access to the inbound order request, which contains attributes, as well as the order state.

@Override
protected CharSequence processNewOrder(final IcebergOrder order, final OrderNewRequest request) {
...
// Schedule cancellation timer if necessary
if (request.hasAttributes()) {
ObjectList<CustomAttribute> attributes = request.getAttributes();
for (int i=0; i < attributes.size(); i++) {
CustomAttribute attribute = attributes.get(i);
if (attribute.getKey() == DURATION_ATTRIBUTE_KEY) {
long duration = OrderAttributesParser.parseDuration(DURATION_ATTRIBUTE_KEY, attribute.getValue());
scheduleOrderExpirationTimer (parent, duration);
break; // not interested in other attributes here

}
}
return super.processNewOrder(order, request);
}

In the code snippet above, we utilize the OrderAttributesParser utility class, which provides a convenient method for parsing durations represented in the HH:MM:SS.sss format into the corresponding number of milliseconds.

Schedule Order Expiration Timer

Let's define an algorithm callback method that will be called from expiration timer.

private @Timestamp long onOrderTimeout(long now, IcebergOrder order) {
if (order.isActive())
cancelAlgoOrder(order, "Order expired");

return TimerCallback.DO_NOT_RESCHEDULE;
}

To avoid memory allocations, it is recommended to define the callback reference as a final field:

private final TimerCallback<IcebergOrder> cancelOrderCallback = this::onOrderTimeout;

Now, we can schedule the timer to call our callback:

private void scheduleOrderExpirationTimer(IcebergOrder order, long duration) {
@Timestamp long orderExpirationTimestamp = getClock().time() + duration;
order.setCancelJob(getTimer().schedule(orderExpirationTimestamp , cancelOrderCallback, order));
}

We keep the TimerJob handle returned by the timer's schedule in our order. This allows us to cancel the timer if needed.

For more information about timer callbacks, please efer to the Timers section in the Event Handlers document.

Order Cancellation Timer

To cancel the timer upon order completion, use the order deactivation callback. You can add the following logic to your custom order class:

@Override
public void onDeactivate(OrderEvent finalEvent) {
super.onDeactivate(finalEvent);
if (cancelJob != null) {
cancelJob.cancel();
cancelJob = null;
}
}

Additionally, it's a good idea to clean up the TimerJob handle that we keep during order recycling:

@Override
public void clear() {
super.clear();
cancelJob = null;
}

By implementing these methods, we ensure that the timer is canceled and the cancelJob handle is set to null when the order is deactivated or cleared.