Accessing Xetra and Eurex exchange systems
Introduction to the technical interface Values API
(C) Michael Härtfelder, 2003 <michael@haertfelder.com>

 

Home

Preface

How are buy and sell stock orders transferred to their final destination, the stock exchange? From the bank's customer view the first step is obviously to enter all necessary information into some online brokerage forms on certain internet web pages. Alternatively the orders can be entered into the banks internal securities order management systems on behalf of the customer or fund asset managers.

Step by step they are checked for validity and plausbility like expiration date, buying power and many more criterions. Having passed all these filters successfully they will reach a status where they are ready to be send to the stock exchange. Depending on the entered target stock exchange the security order is handed over to a specialized order management system which prepares the data individually for the transfer to the stock exchange. The target stock exchange can be selected from a set of existing exchanges provided that the security paper is listed at this exchange and the bank is an official trading member at this exchange.

Possible exchanges for the german cash market are either the leading trading platform XETRA (driven by the Deutsche Boerse, Frankfurt), regional exchanges, bank inhouse trading ECNs or even foreign exchanges.
Concerning the forward market first and foremost EUREX, the worlds leading forward exchange platform for options and futures (driven by Deutsche Boerse and Swiss Exchange), should be addressed.

The following introduction will give a brief overview about the technical interface of the XETRA and EUREX trading system. This programming interface (called "Values API") of both exchanges is very related. The technical framework correspond very closely and will be merged more and more with every new release.

Xetra/Eurex communication Both rely on the GATE communication architecture established and maintained by Deutsche Boerse. The GATE architecture is a collection of software tools which are installed on a MISS-Server at the client site. In this context the client (of the exchange) is the bank, not the private customer. After having installed the MISS/GATE architecture and established successfully a connection to the exchange the socket is ready to accept calls from the banks order management system. Setting up a MISS/GATE architecture should not be discussed here. A lot of effort is necessary to adjust all components and parameters correctly to fit into the individual network and permission environment of the bank.

This article focusses on the technical programming interface Values API. Of cause this article can not be a complete overview or even a comprehensive documentation. It is only meant to be a small insight into how to access the central trading system.

Every Xetra/Eurex Values API session consists of a pair of an enclosing VCI_CONNECT/VCI_DISCONNECT and several VCI_LOGIN/VCI_LOGOUT calls. These initial/final general calls establish a valid Values API connection resp. a valid trader connection to the trading system with all security features and the permission environment. Nested inside such a Values API session all the other function calls are embedded.

As suitable samples one function call to the XETRA system and one function call to EUREX are presented. The corresponding parameters are described in more detailed and possible values are listed. A list of all currently available functions can be found here for XETRA and for EUREX.

The Values API interface itself is implemented in C. However this doesn't mean that the bank securities management system must be written in C(++) as well. Often the inhouse core main applications are written in Java and the data is passed through JNI technology to a C(++) module which in turn handles the communication traffic with Values API.

A couple of header files are provided by Deutsche Boerse/Eurex. They contain all necessary pre-defined data structures and constants. Whenever a constant name (consisting of only capital letters) is mentioned below it refers to one of these already existing declarations. For a complete list of constants see the official documentation.

XETRA function "Enter Order"

In general most of the Values API calls refer to the following scheme. The Values Api function passes
  • a general request structure (reqControl),
  • the actual request Data (reqData),
  • the name of the function which is used for the callback (orderCallback),
  • individual client data (cntxtData) and
  • the status structure (status)
to Values API.

ReqCntrlT       reqControl;
SubmitReqDataT  reqData;
AppCntxtDataT   *cntxtData;
StatusDataT     status;

...

VCI_Submit(&reqControl, &reqData, orderCallback, cntxtData, &status);

switch (status.techComplCode) {
   case ELB_TECH_OK:
     ...
     break;
   case ELB_TECH_INVALID_PARAMETER:
   case ELB_TECH_INTERNAL_ERROR:
   case ELB_TECH_NOT_CONNECTED:
   case ELB_TECH_TOO_MANY_PENDING_REQUESTS:
   case ELB_TECH_NOT_LOGGED_IN:
     ...
     break;
   default:
     printf("Unknown Error=[%d] in vapienterorder\n", status.techComplCode);            
   break;  }
The general request structure contains global parameters for the current function and is part of every call to Values API.

typedef struct ReqCntrlT {
int connectionID;The unique connection idenfier which was
obtained from the initial Gate connect
int dbApplID;The predefined identifier for the target trading
system (in this case XETRA_XID)
char appDescr[MAX_APPDSCR];User definable text name of the calling application (e.g. "myApp")
int reqID;The pre-defined identifier for the current type
of call (in this case: constant XETRA_ENTER_ORDER_RID)
int resubmitFlag;Flag if this call is a re-submit of a previous call
(necessary e.g. because of network errors).
Usually equal to 0 (= first call)
unsigned int resubmitNo;If this call is a re-submission the number of
resubmission is entered here
char VCIver[MAX_VCIVER];The version identifier of the ValuesAPi release being
used must be entered here (e.g. pre-defined CVN_012)
int loginID;The unique login identifier which was obtained from the
initial trader login
} ReqCntrlT;

At a first glance the second parameter structure seems to be very simple. It contains only two fields. However pay attention to the pointer definition of the variable appReq. Part of every function call is the allocation of an individual object which contains the specific current data. The address of this data structure will be assigned later to this appReq pointer.

typedef struct {
int appReqBlockSize;The number of bytes of the structure to which the pointer appReq refers
void *appReq;Pointer to the actual request data structure. In the case of the
function "Enter Order" this structure is of type rfmorentT
} SubmitReqDataT;

As mentioned above for every call a request structure must be allocated and filled with the appropriate data. In case of the function Xetra Enter Order the necessary pre-defined structure need to be retrieved from the header file rfmorent.hxx and looks like:

    reqData.appReqBlockSize = sizeof(rfmorentT);
    reqData.appReq          = (pRfmorentT)malloc(reqData.appReqBlockSize);  
typedef struct partIdCodTag {
char partSubGrpIdCod[PART_SUB_GRP_ID_COD_LEN];The group to which the issuing user/trader has been assigned (e.g."TRD")
char partNoText[PART_NO_TEXT_LEN];The number identifying the issuing trader/user inside the group (e.g. "001")
} partIdCodT, *pPartIdCodT;

typedef struct acctTypCodGrpTag {
char acctTypCod;Defining the type of account for which the order is issued (e.g.
"A"gent, Best "E"xecutor, Designated Sponsor ("M") or "P"roprietary)
char acctTypNo;Account number (usually "1")
} acctTypCodGrpT, *pAcctTypCodGrpT;

typedef struct ffTxtGrpTag {
char userOrdNum[USER_ORD_NUM_LEN];Client (not XETRA) order number
char text[TEXT_LEN];Free text field available to user
} ffTxtGrpT, *pFfTxtGrpT;

typedef struct bestExrMembIdCodTag {
char bestExrIstIdCod[BEST_EXR_IST_ID_COD_LEN];The institution part of the Best Executor MemberId
char bestExrBrnIdCod[BEST_EXR_BRN_ID_COD_LEN];The location/trader part of the Best Executor MemberId
} bestExrMembIdCodT, *pBestExrMembIdCodT;

typedef struct rsmorentWs2RecTag {
char buyCod;Indicator if "B"uy or "S"ell order
char ordrQty[ORDR_QTY_LEN+1];Order quantity
char ordrExpDat[ORDR_EXP_DAT_LEN];Order expiration date
char ordrResCod;Order restriction code (e.g. "I"mmediate-or-cancel, "F"ill-or-kill,
"S"top-Order, None " ")
char trdResTypCod[TRD_RES_TYP_COD_LEN];Trading restriction code (e.g. opening auction only ("OA"),
Auction only ("AU"), Closing auction only ("CA"),
Main auction ("MA"), Auction or continous trading (" "))
char ordrTypCod;
ffTxtGrpT ffTxtGrp;User related fields (see above)
acctTypCodGrpT acctTypCodGrp;
partIdCodT partIdCod;
} rsmorentWs2RecT, *pRsmorentWs2RecT;

typedef struct instGrpIdCodTag {
char isinCod[ISIN_COD_LEN];International security identification number (ISIN)
} instGrpIdCodT, *pInstGrpIdCodT;

typedef struct rfmorentTag {
instGrpIdCodT instGrpIdCod;
char ordrExePrc[ORDR_EXE_PRC_LEN+1];Order execution (limit) price
rsmorentWs2RecT rsmorentWs2Rec;
char prcRsblChkFlg;Flag indicating if Xetra should check the entered price for reasonibility
char peakSizeQty[PEAK_SIZE_QTY_LEN+1];Largest quantity of an iceberg order that is visible to the market
char netTypCod;Indicator for the order netting level (e.g. "N"one, "A"ccount, "P"rice)
bestExrMembIdCodT bestExrMembIdCod;Identifier of the Best Executor MemberId if Best Execution is intended
} rfmorentT, *pRfmorentT;

Every successful call to Values API will be answered with a callback from Values API. Having finished a call through VCI_SUBMIT means only that Values Api accepted the call syntactically and had passed some minor plausibility checks. It does not mean that the request data was passed successfully to the final trading system and is already placed in the orderbook. The actual result with the acceptance values from XETRA core system is returned in a separate callback to the function being declared in the initiating request call.

It is very important to know that this callback call is perform asynchronously depending from the system load and the network traffic. This implies that the banks inhouse securities management system must implement a comprehensive thread mechanism to coordinate outgoing requests and corresponding incoming responses.

It remains to the backend system software architects if they use one callback function for multiple different possible callbacks and split up the different messages inside this multi-purpose function or use different callback functions right from the beginning.

The callback function should be implemented like:

static void enterOrderCallback(ReqCntrlT *reqCntrl, 
                               CallBkAppDataT *appData,
                               AppCntxtDataT *cntxt,
                               StatusDataT *status)
The appData points to a structure which contains (in the case of success) e.g. the assigned XETRA order number. This key value identifies the order uniquely in subsequent calls and responses (e.g. Order execution confirmations and Trade confirmations).

Up to now nearly all the mentioned data structures contain only fields required by the XETRA trading system. Under certain circumstances the client securities management systems need some extra fields to remember some status or help values which are valid at the time of request. Keep in mind that the response to a previous request can roll in asynchronously possibly 20 messages later. To avoid difficult status maintenance management it is possible to attach some accompanying help information. The variable data structure can be defined by the user dynamically or even be omitted completely.

typedef struct{
int custBlockSize;Length of user context data
void *custData;Pointer to user context data structure
} AppCntxtDataT;

As you may have noticed there is a parameter cntxt among the parameters of the callback function. The same context stuff which is send with the request to XETRA will be received in the callback function as third parameter.

Obviously every single call to Values API yields a result, either success or an error. The structure "status" will be filled by Values API with the particular degree of completion. Moreover it is broken down into a functional and a technical part.

typedef struct {
SeverityClassT complSeverity;Severity priority of the functional part of the current call (possible
values are VCI_FATAL, VCI_ERROR, VCI_WARNING, VCI_SUCCESS)
int complCode;More detailed (error) completion code of the functional part of the
current call (e.g. ELB_INVALID_REQUEST_ID or ELB_XETRA_INVALID_PARAMETER)
char complText[ELB_MAX_STRING];More detailed (error) completion text explaining the occured functional error
SeverityClassT techComplSeverity;Severity priority of the technical part of the current call (possible
values same as complSeverity)
int techComplCode;More detailed (error) completion code of the technical part of the
current call (e.g. ELB_TECH_REQ_UNSUCCESSFUL or ELB_TECH_INVALID_CONNECTION_ID)
char techComplText[ELB_MAX_STRING];More detailed (error) completion text explaining the occured
technical error
} StatusDataT;

 

EUREX function "Inquire Own Single Leg Order"

Of cause for the EUREX platform there is a similar function for entering an option or future order like the one presented above for the XETRA stock market. However in order to show other aspects of the Values API interface another function is taken to demonstrate the EUREX access. The main task of the function "Inquire Own Single Leg Order" is not to push something into the trading system but to retrieve information from it. For some given future or option values a couple of important information values are returned.

Since there are two Values API interface functions to inquire own orders the prefix "Single Leg" is used to distinguish the current one from the other "Double Leg" order.

ReqCntrlT       reqControl;
SubmitReqDataT  reqData;
AppCntxtDataT   *cntxtData;
StatusDataT     status;

...

VCI_Submit(&reqControl, &reqData, inquireCallback, cntxtData, &status);

switch (status.techComplCode) {
   case ELB_TECH_OK:
     ...
     break;
   case ELB_TECH_INVALID_PARAMETER:
   case ELB_TECH_INTERNAL_ERROR:
   case ELB_TECH_NOT_CONNECTED:
   case ELB_TECH_TOO_MANY_PENDING_REQUESTS:
   case ELB_TECH_NOT_LOGGED_IN:
     ...
     break;
   default:
     printf("Unknown Error=[%d] in vapiinquiresinglelegorder\n", status.techComplCode);            
     break;  }
As you may have expected the first data structure ist the same as in XETRA. The fields are filled correspondingly. Differing from the first example EUREX_XID is assigned to reqControl.dbApplId and DRIV_INQUIRE_OWN_SINGLE_LEG_ORDER_RID to reqControl.reqId.

Analog the two last parameters cntxtData and status have the same meaning and structure as their XETRA counterparts.

The structure reqData works similarly except the fact that appReq points to another request structure. Depending on wether the order is a Future or an Option different data structures must be used. For Futures:

    reqData.appReqBlockSize = sizeof(futInqOwnSLegOrdrRequestT);
    reqData.appReq          = (futInqOwnSLegOrdrRequestT *)malloc(reqData.appReqBlockSize);  
or for Options:

    reqData.appReqBlockSize = sizeof(optInqOwnSLegOrdrRequestT);
    reqData.appReq          = (optInqOwnSLegOrdrRequestT *)malloc(reqData.appReqBlockSize);
Since both sibling structures are very similar we present only the Option data structure in more detail:

typedef struct dataheaderTag {
char exchApplId[EXCH_APPL_ID_LEN];Exchange identifier (For Eurex "XEUR")
char prodLine[PROD_LINE_LEN];Product line (either "O"ptions or "F"utures)
char membExchIdCodOboMs[MEMB_EXCH_ID_COD_OBO_MS_LEN];Member identifier
} dataheaderT, *pDataheaderT;

typedef struct optBscInqOwnSLegOrdrRequestTag {
optCntrIdGrpT optCntrIdGrp[OPT_BSC_INQ_OWN_S_LEG_ORDR_GRP_MAX];Group of key fields uniquely identifying an option. The group comprises ProductId, ClassCode, ExpirationMonth, ExpirationYear, ExercisePrice and VersionNumber (e.g. ODAX C 03 2003 3000 0).
char buyCod;Indicator if "B"uy or "S"ell order
char ordrNo[DRIV_ORDR_NO_LEN];Eurex order number
trdrIdGrpT trdrIdGrp;Participant group and id to which a trader has been assigned (e.g. "TRD001")
char mliCntrDataCtr[MLI_CNTR_DATA_CTR_LEN];Counter for the number of contracts in a multi contract message
char keyDataCtrlBlk[KEY_DATA_CTRL_BLK_LEN];Key data control block. Used for processing multiple subsequent requests/responses
} optBscInqOwnSLegOrdrRequestT, *poptBscInqOwnSLegOrdrRequestT;

typedef struct optInqOwnSLegOrdrRequestTag {
dataheaderT header;General header fields
optBscInqOwnSLegOrdrRequestT basic;Basic contract data fields
} optInqOwnSLegOrdrRequestT, *pOptInqOwnSLegOrdrRequestT;

The callback function for the response message should be defined like:

static void inquireownsinglelegCallback(ReqCntrlT *reqCntrl, 
                                        CallBkAppDataT *appData,
                                        AppCntxtDataT *cntxt,
                                        StatusDataT *status)
The CallBkAppDataT is a structure which contain a pointer void *appRespData which in turn point to the actual response data. In the case of the function Inquire Single Leg Order this response structure is depicted in parts below.

typedef struct optBscInqOwnSLegOrdrRecTag {
char buyCod;Indicator if "B"uy or "S"ell order
optCntrIdGrpT optCntrIdGrp;Group of key fields uniquely identifying an option. The group comprises ProductId, ClassCode, ExpirationMonth, ExpirationYear, ExercisePrice and VersionNumber (e.g. ODAX C 03 2003 3000 0).
trdrIdGrpT trdrIdGrp;Participant group and id to which a trader has been assigned (e.g. "TRD001")
char ordrNo[DRIV_ORDR_NO_LEN];Order number which has been assigned to this order by EUREX
char ordrBkQty[DRIV_VOLUME_LEN];Original order quantity
char ordrExeQty[DRIV_VOLUME_LEN];Quantity of an order which has already been (partially) matched/executed
char ordrTypCod;Indicator for the order type (e.g. "M"arket order, "L"imit order, "Q"uote, Bl"O"ck trade)
char ordrExePrc[DRIV_PRICE_LEN];Limit price for an order. If filled with zero then the order is treated as a market order.
char ordrExpDat[DRIV_DATE_LEN];Date when the order expires. Three possible types of expiration are possible:
Good-for-day, Good-till-date and Good-till-cancel
char opnClsCod;Code indication wether this order is submitted to "O"pen or to "C"lose a position
char trnDat[DRIV_DATE_LEN];Transaction date of the order (Date of reception in the trading system resp. execution date)
char trnTim[DRIV_TIME_LEN];Transaction time of the order (Time of reception in the trading system resp. execution time)
char membExchIdCodObo[MEMB_EXCH_ID_COD_OBO_LEN];MemberId of the institution entering the order
char dateLstUpdDat[DATE_LST_UPD_DAT_LEN];Timestamp of last update of the order
} optBscInqOwnSLegOrdrRecT, *pOptBscInqOwnSLegOrdrRecT;

typedef struct optInqOwnSLegOrdrResponseTag {
dataheaderT header;General header fields (e.g. ExchangeId "XEUR", ProductLine "O"ptions)
optBscInqOwnSLegOrdrResponseT basic;Basic contract data fields
optExtInqOwnSLegOrdrResponseT extension;Extended contract data fields
} optInqOwnSLegOrdrResponseT, *pOptInqOwnSLegOrdrResponseT;

Advanced considerations

As already mentioned the introduction on this web page can only be a very short extract from the complete Values API and GATE architecture. There are a lot of advanced issues like
  • Creating a message socket and dispatching incoming messages
  • Subscribing and Unsubscribing to data streams
  • Managing public and private data streams
  • Setup of Multicast channels
  • Processing of responses with variable data record length
  • Handling Multi-record responses
  • Implementing hundreds of other functions
  • Administrating permissions for traders and senior traders
  • Managing instrument groups
  • Setup of test accounts
  • Installing MISS-Servers and GATE-Software
  • ...
Since we designed several brokerage backend systems based on Values API we have extensive experiences with this topic. Various order and quote management systems had been developed for major clients.

If you have questions or comments let email us know.