Skip to content

Binary EntryPoint Support

Richard Warburton edited this page Aug 30, 2021 · 5 revisions

What is Binary EntryPoint and who should use it?

Binary EntryPoint is a FIXP based protocol for binary order entry used by B3. The B3 Documentation provides details of the protocol itself and should be considered a reference guide, the rest of this wiki page just explains how Artio can be used with Binary EntryPoint.

How does Binary EntryPoint relate to Artio?

Binary EntryPoint is an order entry protocol that Artio supports. Just in the same way that Artio supports different versions of the FIX protocol. That means that Artio will manage the Binary EntryPoint session protocol and your application has to handle the business logic side of things for example sending orders and handling execution reports.

Status

Feature complete.

Implementing Binary EntryPoint with Artio

Setup your project

The Binary EntryPoint implementation requires additional dependencies to artio-core with the following coordinates: uk.co.real-logic:artio-binary-entrypoint-codecs and uk.co.real-logic:artio-binary-entrypoint-impl. These packages are released to maven central along with normal artio releases. Here is an example dependencies section that includes Artio with Binary EntryPoint support.

dependencies {
    implementation "uk.co.real-logic:artio-binary-entrypoint-codecs:${artioVersion}"
    implementation "uk.co.real-logic:artio-binary-entrypoint-impl:${artioVersion}"
    implementation "uk.co.real-logic:artio-codecs:${artioVersion}"
    implementation "uk.co.real-logic:artio-core:${artioVersion}"
}

Core concepts

Within Artio each FIXP session is uniquely identified by a uk.co.real_logic.artio.fixp.FixPKey and each individual connection by a uk.co.real_logic.artio.fixp.FixPContext. Because sessions can have many connections each FixPKey can be associated with many FixPContext objects. The core object that represents a FIXP connection is a uk.co.real_logic.artio.fixp.FixPConnection - the equivalent of our Session object for FIX. This defines the state and the API that is common to all FIXP implementations. Each implementation has a specific key and context class that the classes can be downcasted to in order to extract implementation specific fields.

For any Binary EntryPoint implementation specific methods you can cast this connection object to a uk.co.real_logic.artio.binary_entrypoint.BinaryEntryPointConnection.

Please refer to Artio's normal documentation and samples for examples of how to setup a FixEngine and FixLibrary within your project. These examples assume that you have a connected Library and go from there. The general pattern for accepting FIXP connections is that you have equivalent to Handler interfaces to the FIX interface but with a FIXP prefix here is a table showing comparable interfaces. Due to the nature of the difference between the FIX and FIXP protocols we don't share the exact same interface.

FIX FIXP
uk.co.real_logic.artio.session.CompositeKey uk.co.real_logic.artio.fixp.FixPKey
uk.co.real_logic.artio.library.SessionExistsHandler uk.co.real_logic.artio.library.FixPConnectionExistsHandler
uk.co.real_logic.artio.library.SessionAcquireHandler uk.co.real_logic.artio.library.FixPConnectionAcquiredHandler
uk.co.real_logic.artio.library.SessionHandler uk.co.real_logic.artio.fixp.FixPConnectionHandler
uk.co.real_logic.artio.session.Session uk.co.real_logic.artio.fixp.FixPConnection
uk.co.real_logic.artio.engine.logger.FixMessageConsumer uk.co.real_logic.artio.fixp.FixPMessageConsumer
uk.co.real_logic.artio.BusinessRejectRefIdExtractor uk.co.real_logic.artio.fixp.FixPRejectRefIdExtractor

Accepting Connections

You can take a look at a working example in the uk.co.real_logic.artio.example_fixp_exchange package of the artio-samples project. This can be run with the sample program uk.co.real_logic.artio.system_tests.FixPExchangeApplication.

Engine Configuration

Firstly in order to accept Binary EntryPoint connections you need to set EngineConfiguration configuration option: configuration.acceptFixPProtocol(FixPProtocolType.BINARY_ENTRYPOINT).

If you want to configure an authentication strategy in order to accept or reject connections based upon a username or password then you need to set a FIXP specific authentication strategy. If none is set then all connections are accepted. Here is an example of setting an authentication strategy:

configuration.fixPAuthenticationStrategy((context, authProxy) ->
{
    System.out.println("Request to authenticate: " + context);
    authProxy.accept();
});

Library Configuration

Two library callbacks need to be configured for FIXP connections to be accepted - similar to FIX sesions. These are the FixPConnectionExistsHandler and FixPConnectionAcquiredHandler.

The exists handler is a callback that notifies the library of a FIXP connection having connected and lets libraries make a request to the engine to acquire a FIXP connection - just like they would do with a FIX session. Here is an example of setting an exists handler: libraryConfiguration.fixPConnectionExistsHandler(existsHandler);.

The only method that this needs to implement is the onConnectionExists callback, here is an example that requests the session in question.

public Action onConnectionExists(
    final FixLibrary library,
    final long surrogateSessionId,
    final FixPProtocolType protocol,
    final FixPContext context)
{
    final Reply<SessionReplyStatus> reply = library.requestSession(
       surrogateSessionId, NO_MESSAGE_REPLAY, NO_MESSAGE_REPLAY, 5_000);
    replies.add(reply);

    return Action.CONTINUE;
}

The session acquire handler is again conceptually similar to its FIX equivalent and should return an instance of the FixPConnectionHandler which takes callbacks for events related to the FIXP Connection.

// Configuring the handler:
libraryConfiguration.fixPConnectionAcquiredHandler(connection -> onAcquire((BinaryEntryPointConnection)connection));

// Handler implementation:
FixPConnectionHandler onAcquire(final BinaryEntryPointConnection connection)
{
    System.out.println(connection.key() + " logged in" + " with sessionId=" + connection.sessionId());
    return new FixPExchangeSessionHandler(connection);
}

Sending and Receiving Messages

When Artio receives a FIXP message then the onBusinessMessage method of your FixPConnectionHandler will be invoked. Here is an example with inline comments explaining what to do:

    public void onBusinessMessage(
        final FixPConnection connection,
        final int templateId,
        final DirectBuffer buffer,
        final int offset,
        final int blockLength,
        final int version,
        final boolean possRetrans)
    {
        // (1) You can use the provided template id of the message in order to understand which message your system has received and ...
        if (templateId == NewOrderSingleDecoder.TEMPLATE_ID)
        {
            final NewOrderSingleDecoder newOrderSingle = this.newOrderSingle;

            // (2) ... then wrap the SBE decoder around the buffer, using the provided offset, block length and version.
            newOrderSingle.wrap(buffer, offset, blockLength, version);

            // (3) You need an SBE encoder flyweight - these are provided by the `artio-binary-entrypoint-codecs` project.
            // In an idiomatic, low-allocation, system these encoders should be reused
            final ExecutionReport_NewEncoder executionReport = this.executionReport;

            // (4) Use the tryClaim API in order to wrap the encoder around an in memory buffer
            // the second parameters is the length of the variable length component of the SBE codec.
            final long position = connection.tryClaim(
                executionReport, ExecutionReport_NewEncoder.NoMetricsEncoder.sbeBlockLength());

            if (position < 0)
            {
                  // Your attempt to claim a buffer has been back-pressured. This is unlikely to happen, but you
                  // want to re-attempt this operation later until it succeeds.
            }

            // (5) Set the values for your message - you can see some values are taken from the order that you've just decoded.
            executionReport
                .orderID(orderId++)
                .clOrdID(newOrderSingle.clOrdID())
                .securityID(newOrderSingle.securityID())
                .secondaryOrderID(ExecutionReport_NewEncoder.secondaryOrderIDNullValue())
                .ordStatus(OrdStatus.NEW)
                .execRestatementReason(ExecRestatementReason.NULL_VAL)
                .multiLegReportingType(MultiLegReportingType.NULL_VAL)
                .workingIndicator(Bool.NULL_VAL)
                .transactTime().time(System.nanoTime());
            executionReport
                .putTradeDate(1, 2)
                .protectionPrice().mantissa(1234);
            executionReport.receivedTime().time(System.nanoTime());
            executionReport.noMetricsCount(0);

            // (4) Commit the message - this tells Artio that it is ready to send. If an error or exception has
            // happened during processing then you should call connection.abort() instead of commit.
            connection.commit();
        }
    }

Artio implementation differences compared to FIX

Artio's Binary EntryPoint implementation is Acceptor only, doesn't support Engine owned sessions, sole library mode.