OSE Access Library (OSELib) is a set of C++ classes to gain access to Osaka Securities Exchange electronic trading system. It was designed to hide the complexities of interconnection protocol and low-level data representation. The library was used as a part of OSE access gateway, providing high-level FIX protocol interface to the trading engine.
Library interface is logically divided into Communication part and Data Representation part. Communication modules encapsulate LAPB protocol access routines, as well as logical OSE session establishment. Data representation classes provide wrappers around all kinds of messages, supported by OSE. All entry points in communication part accept financial data in form, defined by data representation part.
All communication classes have similar structure: Functional interface + Callback interface. Functional interface defines a basis, set of operations supported. StartSession, SendOrder are examples of functional interface methods. On the other side, all asynchronous notifications are performed via callback interface. For instance, OnContractNotice callback interface method notifies client about execution, providing financial data block with relevant information.
On C++ level, callback interface is represented by abstract class. Client code normally derives from said class and overrides corresponding methods. Reference to callback interface implementation is provided to communication object in constructor.
Functional and callback interfaces are logically linked together and always obey the following important rule: Invocation of the method on Functional interface will never result in synchronous Callback interface trigger. It is safe to call Functional interface method, without worrying about possible re-entrance.
Although significant part of the OSE protocol is hidden inside library, it is suggested to get familiar with basic OSE system data flows, especially with sequence number management. Typical member configuration is comprised of number of Input lines, suitable for transaction input, and number of Notice reception lines, used for asynchronous notifications. The protocols, employed on these lines, are identical, but not exactly; hence there are two separate classes to handle each line: COSEOrderInputInterface and COSENoticeReceptionInterface.
Single instance of user application can handle arbitrary number of order input and notice reception lines. Moreover line handling objects can be assigned to different threads, to improve overall system performance. To identify different instances, every communication object is constructed with additional parameter - unique key to identify the instance. So every callback method has the key parameter, specifying the line, asynchronous notification applies to.
Every OSE line has several sequence numbers attached:
OSE system uses synchronous transaction scheme, i.e. every message must be acknowledged before the next one can be sent. This limitation gives the guarantee that a maximum of one message can be missed in the event of line failure. SeqNum.Message.* are used to control data integrity on physical level, to repair from line failure. On the other hand SeqNum.Terminal.* are used to control logical data integrity and stamp single piece of financial information. In case of member system failure, used to initiate manual resend/reroute procedure.
OSELib does not have any kind of external persistence and as a result, it cannot automatically initiate line recovery in case of failure. This design was chosen to allow user system to implement arbitrary redundancy/recovery algorithms. Here we summarize sequence numbers management rules, that need to be handled by the member system:
Sequence number management during order input. OSE trading system has two types of rejects:
SeqNum.Terminal.Member and SeqNum.Message.Member always need to be incremented when an order is accepted by trading system.
Spread instruments price shift. OSE system uses price shift scheme to avoid negative prices in connection protocol. For this purpose, each price value is shifted by designated constant before encoding it into transmission frame. These constants are product-specific and may be adjusted from time to time. Due inconsistencies in this approach, OSELib does not incorporate the code for price shift. Prices for all relevant instruments need to be shifted prior passing financial data to library.
Back to the top ↑Communication object model is represented in the following UML diagram:
COSEAccessBase is designated base class for all communication objects. Functionally, it implements low-level media control, configuration and recovery. Special note about recovery should be given here. OSELibrary sits at the third (Network) layer of the OSI model, using services, provided by Data Link layer(LAPB level in our case). Solaris implementation of communication transports uses STREAMS architecture as a data path between kernel and user space. And all the data is passed between layers as special kernel chunks. Under critical system conditions, the STREAM may suffer from lack of resources and error is reported from the kernel. Software developer is always facing the dilemma in this case: whether terminate and report a lack of system resources or try to recover from local errors. We've chosen the second approach in this library: Whole STREAM is dismantled and recovery timer is activated. When this timer is fired, attempt to rebuild the STREAM is made and if successful, COSEAccessBase::CCallbackInterface::OnLineRestored is called to notify user about restored media. Throughout this document such an occlusion is reffered to as Local failure.
There are two cases when local failure is detected and reported:
In either case, User does not need to initiate any action towards the library. Recovery timer is activated automatically and OnLineRestored callback will be called as soon as line is OK. Depending on application specifics, special action may be needed to notify administrator or to reconsult orders pending for transmission.
Class COSESession is derived from COSEAccessBase and implements logical OSE system protocol session establishment and control. It takes some time to establish the session, so method StartSession starts connection procedure, but final confirmation is delivered with CSessionCallbackInterface::OnSessionEstablished callback. Since there is no LAPB-supported timeout mechanism, the library controls timeout during session establishment phase by means of _uiConnectTimeout parameter of StartSession call. If session could not be established during prescribed period, asynchronous callback method CSessionCallbackInterface::OnSessionConnectFailed is called. Implementation of this method may consider OSE system as offline or retry connection attempt with recurring StartSession call.
Session may be terminated via one-step call to EndSession method.
Session layer is also responsible for Message sequence number synchronization. First resync is performed automatially on session establishment phase. And at the middle of the session current sequence numbers can be reconfirmed via PerformResync call. OSE system state diagram warns that if OSE initiated sequence number resync, it ignores incoming resync requests until reply is received. So the best approach is to expect either CSessionCallbackInterface::OnResyncCompleted, or CSessionCallbackInterface::OnResyncReceived as a sign of resync procedure completion. OnResyncReceived method is used for notification that OSE system has initiated resync. Acknowledgment is sent to OSE prior executing this method.
When either CSessionCallbackInterface::OnResyncCompleted or CSessionCallbackInterface::OnResyncReceived callbacks are invoked, there is probability that last order, sent by member, is not received by OSE. In this case last sent order needs to be transmitted again. Generally speaking, LAPB provides unreliable connection-oriented service. So data loss may occur only when connection is broken(CSessionCallbackInterface::OnSessionTerminated) or when LAPB link reset (CSessionCallbackInterface::OnLinkReset). LAPB link reset condition means that connection is still alive, but recently sent data may not be delivered. As a consequence, when link reset is detected, delivery of the last message must be confirmed by peers via restart message (PerformResync). There are two approaches available for handling link reset condition:
COSESession class has several status methods, which return current state of the session: IsOnline, IsConnecting, IsOffline.
When session is established, some additional information becomes available from OSE: Member center code, Member system code, Line code, Member code. This information is assigned by OSE and can be retrieved with following methods respectively: get_MemberCenterCode, get_MemberSystemCode, get_LineCode, get_MemberCode.
OSE system protocol is designed to be synchronous, meaning that next informative message can be sent only upon reception of the acknowledgement for previous one. This gives important guarantee that only one message can be lost when session is terminated or reset. Method IsSentOperationPending is provided to check whether unacknowledged message is pending.
Class COSEOrderInputInterface is derived from COSESession and represents final interface to the order input line. Basically it handles line state notices and provides functionality for order sending and callbacks for acknowledgements.
Order sending is implemented as two-stage process; first AcquireOrderMessage should be called to initialize supplied transaction object and to fill protocol-specific header fields. Then method SendAcquiredOrder can be used to send specified transaction object to OSE. When OSE acknowledges received order, one of callback interface methods COSEOrderInputInterface::OnNewOrderAck, COSEOrderInputInterface::OnCancelOrderAck or COSEOrderInputInterface::OnAmendOrderAck is called. Implementation of the corresponding callback may send the next order, waiting for transmission.
Callback methods COSEOrderInputInterface::OnOrderEnabledMessage and COSEOrderInputInterface::OnOrderDisabledMessage are used to notify about input state for particular instrument. As soon as interconnection protocol assumes synchronous data transmission - reception of the notice should be acknowledged to OSE. So when processing of the received notice is complete, interface method AcknowledgeLastStatusMessage should be called to send an acknowledgement.
Class COSENoticeReceptionInterface is a final class for Notice reception line. It supports line state notices and transaction notices.
Back to the top ↑Data object model is represented in the following UML diagram:
Conceptually, data model is comprised of frame object, wrapping raw data frame; and frame-parsing objects, manipulating content of the raw frame. Raw frame is represented with CFrameWrapper class. It can be attached to arbitrary character buffer. All frame-parsing objects are derived from abstract CGenericBlock class, that defines the functionality, common to all frame-parsing classes. These include particular frame length method, and certain calls for attaching/detaching a CGenericBlock-derived class to supplied CFrameWrapper. Data framework implements frame cutting functionality: CFrameWrapper's Attach operation cuts part of the buffer from itself and grants the control over it to attached frame-parsing object. This allows plain representation of arbitrary composition of blocks with fixed format.
CFrameWrapper also has embedded classes for protocol-specific data representation. For example CGenericBlock::SOSE_PRICE is a price in OSE protocol.
Class CFrameException reflects exceptional condition, that can arise from improper usage or data errors when frame is being composed or parsed. It has a list of possible exceptional conditions and normally used as direct base class of block-specific exception objects. Every frame-parsing object has embedded exception class derived from CFrameException, and extends it with field identifier, designating the field, caused the exception. Thus exception handler code has enough information to identify the invalid field and reason for exception.
Every data block class is designed to naturally represent raw frame as a sequence of fields. Every field has number of get, set methods and single check method to check whether field is properly formatted. There is also single check() method for a class that subsequently invokes individual field's check method; this is normally used to check a format of the block as whole. There is several rules for get, set and check methods:
All data-specific methods have exception specification, to declare the range of exceptions that can be potentially thrown. This should be helpful to determine where barrier handlers are to be installed.
Back to the top ↑General description of steps required to employ the library is given below:
Sequence of steps, required to send an order:
There is two possible approaches for order composition and sending:
The difference between these two is only the parameter of SendAcquiredOrder method. In the first case it is transaction object, attached with prior call to AcquireOrderMessage. And in the second case, this is just previously filled transaction object. Note that even if the second approach is used, call to AcquireOrderMessage is mandatory, cause it initializes internally stored header.
If the library is used as communication-only facility and all transaction frames are filled without using library, the following scenario is recommended:
This sequence is equivalent to several pointer-related operations and should not give noticeable overhead to application performance.
Back to the top ↑Together with the library, the sample program with source code is provided. This application demonstrates basic library usage, recovery algorithms and can be used as a test console for OSE system. On startup, it attempts to establish logical session with OSE and if successful, it displays command prompt. There are two supported commands: "load" and "send". The first command attempts to load order batch from external file and the second sends previously loaded batch to OSE. Sample code also has basic implementation of event manager and event logger, those can be used in client application if suitable.