HOME  | SSL INTEGRATION | C# INTERFACE | DEMO  |  BUY NOW

    FixGateway  (c) 2000-2006 Octatec Ltd
   

The Fix Gateway is a FIX Engine with a simple  Application Programming Interface (API). It is very easy to use and requires the programmer to use only a few methods of a C++ FixClient class. Their are versions available for Linux and WIN32 systems. The system includes a sample fix server program that can read either journal files or files written in a simple scripting language that makes testing your application very easy. (For Windows users only, the C++ Fix Class Library is further encapsulated as an ActiveX control.)

The FixGateway can be configured to create its Fix Sessions over Secure Sockets (SSL), but in order to do that,  the FixGateway/SSL Integration Kit is required.

This package includes a C++ class library API and ActiveX control. The API is also separately available as a C# (.NET CLR) assembly  The 3 versions of the  API are, as near as possible,  identical.

The API allows for easy switching of i/o from on line data to files, and, of course, provides a utility class for building and interrogating fix messages.

For more information about the FIX Protocol see http://www.fixprotocol.org

Contents


System Components

There are 2 system components, a FixGateway process (or Fix Engine) that is started automatically when needed, and an API Library that you must link to your application in order to access the fix gateway.

Note: the fix process is not a daemon (or Windows service, or COM object) it is started automatically by the fixgwlib when needed. The fixgwlib  creates a fix gateway session passing in the name of a configuration file. This  causes the fix gateway process to start up and read the config. using information it find in the config file, it will connect, using tcp/ip sockets to an external Fix Engine. It will communicate with the User Application via a local socket. The User Application enters a Fix Message loop receiving and sending messages.

Windows users note: no DLLs are added or removed from your system during installation.

There is a separate package available that supplies a C# (.NET CLR) Assembly that can be used as an alternative to the C++   library. 


Getting Started

You must include the fix client header, #include <fixcli.h> and link the fix gateway static library libFixGW.a on unix systems or fixgw.lib on WIN32 systems - you must also ensure that any libraries required to access the socket interface are also linked in. You are now ready to write your fix application. The standard pattern of a fix gateway application is a message loop which sends and receives fix messages. The following is the basic structure of the fixtest sample application
// FixTest...

#include <fixcli.h>

LPCTSTR configName = "loopback";
    // loopback is a standard config file supplied with the distribution, it
    // allows a fix client (namely fixtest) to connect to the fixgwsrv application

FixClient fixSession;
if( !fixSession.Open(configName) )
    // report error

if( !fixSession.SynchronizeOutputBuffer() ) report error
    // you only need to make this call if your application
    // uses the BufferedOutput methods; this ensures that
    // if your app crashed while processing BuffereOutput,
    // the messages are not lost - if the remote fix gateway
    // is not yet connected, the messages will be stored
    // internally until a connection is made

// you could make this call here if you wished,
// but there is no requirement to...
// if( !fixSession.WaitForConnection() ) report error
    // this is probably of more use when running
    // the fix gateway as a server

FixString sfix;
for(;;)
{
    FixError ok = fixSession.GetFixMsg(sfix);

    if( !ok )
        break

    int msgType = sfix.GetType();

    swicth(msgType)
    {
        // process the message
        ...
    }

    fixSession.SetComplete();
        // must call this once you are happy that a
        // fix message has been fully processed
}

Your application will be in a fix message loop, if your application needs to process WIN32 or X/Windows messages, the best thing to do is put the fix message loop in a worker thread, leaving the User Interface thread free. If you need your User Interface thread to communicate with your Fix Message thread, e.g. to close the fix session, you can create a CntrlInterface object in the User Interface thread and pass it to the FixClient object in the worker thread. You can then pass messages to the worker thread by using the CntrlInterface object in in the User Interface thread. The fixgwsrv sample application uses this technique and implements a Simple (character  based) User Interface thread and a Fix Worker Thread. The following code fragment demonstrates the technique.
// fixgwsrv
#include <fixcli.h>
#include <cntrlif.h>
/*
**user interface thread
*/

CntrlInterface *pctrl = new CntrlInterface;
pctrl->InitControlSide();

// create  worker thread here, passing in pctrl
// E.G CreateThread(...pctrl...) or pthread_create(...pctrl...)
// NB: if you have more than one worker thread, each muts have a
// different control interface, they cannot share a common control
// interface!

pctrl->WaitForActivation(); // still in client thread
                        // this returns when the worker thread is active, i.e. before
             // a connection to another fix engine has been established

/*
**worker thread
*/

LPCTSTR configName = "testsrvr";
    // testsrvr is a standard configuration file supplied with the distribution, if
    // the fixgwsrv application loads the config, it will run as a Fix Server, and
    // can be connected to by any fix client, in particular, the fixtest sample
    // application

fixSession.DisableAutoRecovery();
    // calling this avoids the need for calling SetComplete(), but
    // if the app crashes while processing a message, the message
    // will be lost - it MUST be called before OPEN if it is to be effective
 

FixClient fixSession;
FixError fixResult = fixSession.Open(configName,  NULL,  pctrl);
       // pctrl is created in the UI thread, and passed to the worker,
        // it is the UI threads responsibility to delete the objet when
        // it no longer needs it - the pointer is not stored by the
        // worker thread, instead, parameters are copied from it to allow
       // communication between the 2 threads, so deleting the object
        // in the UI thread will never leave the worker thread with an
        // invalid pointer
        //
        // NB: if configName is already open in this process or any other
        // process, an error will be returened here - multiple fix sessions
        // are permitted in one process or in multiple process but not multiple
        // sessions using the same config!

if( !fixResult )
    // report error

// the session is now open, i.e. the gateway procss has been created without
// errors, and, if running as a server, (as it is in the fixgwsrv sample),
// it is waiting for another Fix Engine to conect to it

fixResult = fixSession.WaitForConnection();
    // this is an optional call introduced in reales 5, it returns
    // only if a connection has been made with another Fix Engine,
    // or if an error occurs, or if a control message has been sent

if( fixResult.IsControlMsg() )
    // procss control message
else if( !fixResult )
    // report error

FixString sfix;
for(bool loop=true;loop;)
{
    fixResult = fixSession.GetFixMsg(sfix);

    if( fixResult.IsControlMsg() )
    {
        long ctlMsg = fixSession.GetControlMsg();
        // process control message
    }
    else if( !fixResult )
    {
        // fix session terminated
    }
    else
    {
        int fixMsgType = sfix.GetType()
        // process fix message
    }
}

Now imagine the situation where you do not have an online fix connection. Instead, a 3rd party delivers a file of fix messages to you, you then process the file and
generate an output file of fix messages which you return to the 3rd party. How can this be achieved? the answer is very easily using the FixFileClient class.
The following code excerpt demonstrates this, and is almost identical to the 1st excerpt above...
// FixTest with input/output from/to an on-line connection or files

#include <fixcli.h>

LPCTSTR configName = "loopback";
    // loopback is a standard config file supplied with the distribution, it
    // allows a fix client (namely fixtest) to connect to the fixgwsrv application

FixClient *pFixSession=NULL;

if( use_file_io_flag )
    pFixSession = new FixFileClient(inputFileName, outputFileName);
else
    pFixSession = new FixClient;

if( !pFixSession->Open(configName) )
    // report error

FixString sfix;
for(;;)
{
    FixError ok = pFixSession->GetFixMsg(sfix);

    if( !ok )
        break

    int msgType = sfix.GetType();

    swicth(msgType)
    {
        // process the message
        ...
    }

    pFixSession->SetComplete();
        // must call this once you are happy that a
        // fix message has been fully processed
}


Configuration File Format

The configuration file describes the remote Fix Engine and local Fix Gateway optional settings. By default, configuration files reside in /Octatec/fixgw/Home/configs on UNIX/Linux systems and C:\Program Files\Octatec\fixgw\configs (or under whatever directory you chose during the installation) on WIN32 systems. Configuration files should have a file extension of .cfg. When you call FixClient::Open() you must pass in the name of config file - you may pass in a full pathname, but more usually you will pass in the file name only, without the extension, in which case the file must reside in the fixgw config directory.

WIN32 users may have expected such configurations to be in the system registry, but to keep differences to a minimum between WIN32 and Linux/UNIX implementations, a configuration file is used in preference to theWIN32  registry.

The config file contains a list of names followed by values as follows.

The following values define the fix session

LocalId local
This is the name of the local fix session and is used in the outgoing fix header
LocalSubId local_sub
This is the sub-name of the local fix session and is used in the outgoing fix header

TargetId testsrvr
This is the expected name of the remote fix engine

TargetSubId testsrvr_sub
This is the expected sub-name of the remote fix engine
NB: these 4 IDs are not hostnames, they just strings chosen by the 2 sides of the fix conversation. Both sides must each know the others IDs and  specify them correctly in the config file. If SubId's are not being used, they can be left out of the config file, or given values starting with a '#' character. If the gateway detects a mismatch of IDs during logon, it will logout from the remote, unless CheckLogonSubIDsis set to 0

Host hostname
The host name to which the Fix Gateway will connect. The FixGateway will attempt to connect to hostname as a client. If the name is local, the local system is used. If the hostname is specified as an asterisk, *, the Fix Gateway will act as a server, i.e. it will listen for incoming calls and accept the first one. Only the first incoming call will be accepted - multiple connections to clients is not supported within a single gateway process, however multiple gateway process are permitted. For added security, you can specify a server using *N.N.N.N, in this case, the server will only accept calls from IPaddress N.N.N.N (note: you must use the actual IPaddress and not a hostname when restricting clients in this way.)

Port n
This is the port to used by the Fix Gateway.
FixVersion MAJ.MIN
This can be used to set the fix version, the default is 4.0. Currently MAJmust be 4. As of writing Fix 4.2 is the latest release release, so MIN should only be 0, 1 or 2.

GmtOffset  n
This parameter allows you to set a ‘virtual’ time zone for the fix gateway. The client application will still see the local time-zone as normal but the FixGateway process will see the timezone as GMT+n (n can be +ve or –ve). The real implication of this is that Fix Message headers will leave with the Virtual Timezone in the time-stamp and midnight will also be dictated by the Virtual Timezone; midnight is important for FIX 4.0 and FIX 4.1 (and even FIX 4.2, when sessions are being re-set automatically) since the Fix Session is automatically reset when a session is restarted after midnight. The default value is 99, if GmtOffset is 99, the Virtual Timezone is the same as the system timezone.

BufferSize n
By default, buffer size is 1024, and the system will not let you set it below 512. If you expect to receive particularly long Fix Messages (larger than 1012 bytes) you can increase the size of the buffer used to read incoming messages here.

FIXML_addhdr  n
If this is 1, a <Header>…</Header> section is automatically added to your outgoing XML. This duplicates the information in the standard FIX header, and is part of the FIXML specification. If you set this flag true, you don’t have to worry about adding te FIXML header yourself. If you set this flag to 0, you can either add FIXML header information yourself or leave it out if that is what has been agreed locally. In all cases the standard FIX header is automatically included by the FixGateway process and you shold not attempt to add header fields using FixString::AddField() .The default value of this field is 0.

FIXML_addroot n
If you set this to 1, your outgoing XML will be automatically enclosed in  <FIXML><FIXMLMessage> … </FIXML></FIXMLMessage> tags, so you don’t have to worry about adding them yourselves. (Of course this is only appropriate if your XML payload is actually FIXML) The default value of this field is 0.
 

The following values control optional behaviour of the fix gateway

NB: there are quite a few parameters here, but mostly, the deault values will be what you want.

ConfrimResend List_of_Msg_Types
This setting allows your application program to decide is a message should be resent or not. List_of_Msg_Types is a colon-separated list of message type that you do not want to be resent automatically if a resend is requested by the remote side, e.g. D:E. When a message that appears in this list needs to be resent, your application is asked is the message is to be resent, if you say no, a gap fill is sent instead. List_of_Msg_Types can be a single asterisk (*), in which case, resend confirmation is requested for all non-admin messages. By default all messages are always resent automatically (except admin messages, of course, which are always replaced with GapFills)

ForwardHeartbeat n
If  n is 1, heartbeats will be received by the user application through the FixClient::GetFixMsg() method, if 0, heartbeats are not delivered to the user application. This might be useful if your application needs to perform housekeeping actions at regular intervals. It is also a useful way for the gateway to detect if your application has crashed or not - the gateway will only detect that your application has crashed when it tries to send data to it. The default value is 1.

ForwardLogon n
If n is 1, logon messages will be received by the user application through the FixClient::GetFixMsg() method, if 0, logon messages are not delivered to the user application. The default value is 0.

ForwardRejection n
If n is 1, rejection messages will be received by the user application through the FixClient::GetFixMsg() method, if 0, rejections are not delivered to the user application. The default value is 0.

TolerateRejection n
If n is 0 rejections are always allowed, if n is > 0, that number defines how many rejections will be received before the Fix Gateway automatically closes. The default value is 1, i.e. the gateway automatically closes after receiving one session level rejection. 

HeartBtInt n
The heart beat interval, in seconds, passed in the login message, this is 15 by default
AlwaysUseOpenEndedResend n
If the value of n is 1, resend requests are always open-ended, if the value is 0,  resend requests are terminated with the current required sequence number. the default value is 1.

SupressNestedResendRequests n
If n is 1, the sending of resend requests after just issuing a resend are suppressed for a maximum of ResendSupressionTimeout seconds. This parameter is designed to avoid the situation where the sender has buffered up a lot of messages, but the first message triggers a resend. In this situation, the 2nd message would also trigger a resend, as would all the messages in the buffer, resulting in a lot of resend requests arriving at the sender. After ResendSupressionTimeout seconds have elapsed, normal resend requesting behaviour is resumed. The default value is 1.

ResendSupressionTimeout n
This parameter controls the number of seconds for which the special behaviour is performed. The default is 10 seconds.

HonourOutOfSeqResend n
This flag allows special action to be taken when a deadlock situation arises. When both fix engines start up, and both discover the Logon message contains an invalid sequence number, both sides will issue resend requests, but both sides will ignore the others resend because it contains an invalid sequence number. If this flag is 0, no special action is performed, if it is 1, a resend request with an invalid sequence number is still processed, and the requested messages are resent, if it is -1, a resend request with an invalid sequence number is rejected and a logout is initiated. The default value is 1.

JournalIncoming n
If n is 1, incoming messages are saved in a journal, if 0, incoming messages are not journaled (The default value is 1). Outgoing messages are always journaled. The Incoming (Receive Journal) plays a part in ensuring messages do not get lost, so read the section abount SetComplete() before switching this off.

FlushJournalAlways  n
This defines how the journal file and other logs are managed. The default is 0, under When the value is 1, the journal and log files are closed after each write, and reopened for the next write - doing this is more secure than keeping the log open all the time, however, it is not done by default because the application detects if anything goes wrong, such as a memory access error, (or a power failure under UNIX), allowing the logs to be flushed and saved. If this value is 0, performance will be improved, but on WIN32 system, there is a greater risk that messages will be lost if the system looses power, since Windows does not inform applications of a loss of poweer as UNIX does - a further consideration when running under WIN32 with NTFS is the file-system buffering strategy - this may need to be switched off  to have a fully resilient  system - you should take advice from your system supplier or technical support department if you require a fault tolerant configuration.

LogDir path
This value defined the log directory. The first character may be a % as in %/logs, in which case the % is replaced by the Installation Directory under WIN32 and by /Octatec/fixgw/Home under UNIX/Linux. NB: the directory must exist. A sub directory with the name YYYYMMDD is created in the log directory, and logs and journal files are saved here. The fix gateway should close down at least once every 24 hours so that a new log directory is allocated. Ideally, the fix gateway will be closed sometime before midnight, and restarted sometime after; however, if you plan to use manual session resets, as permitted  under FIX 4.2, this is not required. NOTE: the path cannot contain spaces, if you are on a WIN32 system and youre path does contain spaces, use the short-form of the path, if you are on a UNIX system, you could create a symbolic link (that doesn't contain spaces) to the directory. NOTE:path must be less than 128 characters.

CliLogDir path
This entry defines where the client logsare placed. Client logs are less important than server logs, but still useful if you encounter problems. If this entry is not present, the environment variable FIXGWLOG is used, and if this is not set, %TEMP% (or $TEMP or /tmp under UNIX) is used, Note: this parameter always takes precedence over FIXGWLOG. If this directory doesn’t exists, the application will display an error message and exit – it is better to know straight away that there is a problem rather than try and search for the non-existent log at some later date 

LogLevel n
This defined the level of logging, 0 is the least verbose and 2 is the most verbose. The default value is 2.

CheckLogonSubIDs n
If any of the IDs (TargetSubID etc) in the config file are blank or start with a hash (#), then the ID is not added to the Fix message that is sent. When we process a logon, the TargetID must match the in-coming SenderID, and the target SubID must match the incoming sender SubID unless the TargetSubID is blank or starts with a hash (#), in which case, we are 'not' processing SubIDs.  If you want to send a TargetSubID, but not validate the returned SubID in the logon message, you must set this parameter to 0. The default value is 1.

ManualSessionSwitch n
This flag must be set to 1 if you are using fix version 4.2 or higher, and you want to use the ResetSession() method. The default value is 0. When this flag is 1, the log directories will have a 'version number' attached to the end of their name. Note: if this flag is set, the session will run until one side issues a ResetSession(). With this flag set to 0, a session is re-established at midnight local time  (or local 'virtual' time)  - but further note: this only occurs when the fix gateway re-starts, hence, to cause a session reset when this flag is set to 0, you must close the fix gateway sometime before midnight, and re-start it after midnight.

CliSndBufSize n
CliRecvBufSize n
These parameters specify the send and receive tcp/ip socket buffer size used within the client library when communicating with the FixGateway process, the default value is 0 which indicates the system-default is to be used.

SrvInSndBufSize n
SrvInRecvBufSize n
These parameters specify the send and receive tcp/ip socket buffer size used within the FixGateway process when communicating with the client application, the default value is 0 which indicates the system-default is to be used.

SrvOutSndBufSize n
SrvOutRecvBufSize n
These parameters specify the send and receive tcp/ip socket buffer size used within the FixGateway process when communicating with the remote Fix Engine, the default value is 0 which indicates the system-default is to be used.

UseLRCP n
See the implementation note at the end of this document. (The default value is 1)

String values can contain embedded spaces if they are surrounded by double or single quotes. Lines beginning with # are comments.


LogFiles and Journals

FixGateway's logfiles and journals

The location of these files is very important, and is controlled by the configuration file's LogDir entry.  These are created in a directory named YYYYMMDD_0  located in the Log Directory specified in the config file. Note: if  ManualSessionSwitch is set to 1 in the config file, the directories are named YYYYMMDD_N, where N is a version number that is incremented whenever a session is reset within any 24-hour period - if the reset takes place in a different 24 hour period, the YYYYMMDD part of the name will change and the N part will be 0.

One way of reseting the sequence number back to zero is simpley to delete these files.

The files created are as follows.

FixGateway.log
The general log file of the fix gateway, the LogLevel entry in the configuration file applies to this file only

FixJnl-TargetId.txt
The journal file - all outgoing messages are recorded here to enable resends of messages missed by the remote system.

FixRcv-TargetId.txt
The incoming journal - this is an optional file, and does not have any particular use.

SeqNo-TargetId.txt
A record of the current incoming and outgoing sequence numbers.

As already mentioned, you should endeavour to ensure that the fix gateway is closed down some time before midnight and started sometime after, so that the fix sequence numbers will restart at 0. It is the act of starting the fix gateway with an empty log directory that resets the sequence numbers to 0.
 

Client Library Log

The client library also creates a log file, FixGatewayClnt.log. The location of this log  is controlled by the config paramater CliLogDir. If this entry is not present, the environment variable FIXGWLOG is used, and if this is not set, %TEMP% (or $TEMP or /tmp under UNIX) is used. Once the base directory has been decided, and directory with the same name as the config file is created, and then a sub directory named YYYYMMDD_c is also created, finally the logfile is created in that directory. To summarize, the client library logfile is created as follows...

$FIXGWLOG/ConfigName/YYYYMMDD_c/FixGatewayClnt.log.

The sequence number of the last successfully processed fix message ( as defined by the FixClient::SetComplete() method) is saved in $FIXGWLOG/ConfigName/YYYYMMDD_c/setcomplete.log

If the client application is using the output buffering mechanism, a buffer file is created in  $FIXGWLOG/ConfigName/buff.txt, this stores unflushed messages, when the buffer is flushed, it is renamed, $FIXGWLOG/ConfigName/buff.cmt, thus should the application fail during flushing, the flushed buffer will be processed by the FixClient::SynchronizeOutputBuffer() call, and messages will not be lost.


FIXML Support

From release 18, support for FIXML was introduced. This support allows you to build ApplicationMessage FIXML sections using your favorite XML DOM implementation and pass these to the gateway, the gateway will add all the required FIXML headers around your ApplicationMessage.  To activate this functaionity, you need to set FIXML_addhdr and FIXML_addroot config parameters.

To make setting the XML payload of a standard FIX message slightly easier, the FixString::SetXmlPayload()method is provided.

You can find more details about FIXML support here.



 

The FixGW Class Library

To use the FixGW class library your system must support the sockets API and you must link to libFixGW.a on UNIX/Linux systems or fixgw.lib on Windows systems.
 
FixClient

NB: many methods in this object return a FixError object to indicate their success or failure. Note: there is no reason why you shouldn't instantiate multiple FixClient objects  in the same application, if that's what you want.

#include <fixcli.h>

FixClient(bool noIntHndlr=false)
Create and initialize a FixClient object. The object is not connected to the fix gateway until Open() is called. (Note: if you want to install your own SIGINT [Ctl-C] Interrupt Handler, either pass in true to the constructor or install it after the construction of the FixClient , as this object installs its own Ctl-C handler. Probably your handler will close the fix session)

~FixClient()
Close any open session before destroying the object.

FixError Open(LPCTSTR configFile, LPCTSTR gatewayHost=NULL, CntrlInterface *pCtrl=NULL)
Open a fix session. The parameters of the fix session, e.g. IP address, port etc., are held in the configFile. The config file can be a full pathname, but more usually, it is just the filename, without extension - given such a value, the fix gateway will look (under UNIX) in /Octatec/fixgw/Home/configs(and under WIN32) in C:/Program File/Octatec/fixgw/configs  for a file of the same name and a .cfg extension. NOTE: gatewayHost must currently be NULL, and is for future use. If you choose to use the full path specification for config files, the path length must be less than 128 characters. (You should try and keep config names (not 
path names) less than 32 characters, as the config file name will be truncated to 32  when the log-directory is created).

The same application can have many FixClient objects, and open multiple fix sessions if it wishes, however, it should only OpenconfigFile once, i.e. if you wish to open 2 or more sessions to the same client, you must create separate config files for each session, the files can just be copies but must have different names, e.g. MyBroker_1, MyBroker_2 etc. The reason for this is that the configFile name defines where the fix log files are created. Attempts to open the same configFile more than once in the same process or even in a different process will fail.

FixError Open(DynamicFixCfg &cfg, LPCTSTR gatewayHost=NULL, CntrlInterface *pCtrl=NULL)
This method works just like the previous method, except it takes a DynamicFixCfg object rather than the name of a config file - this allows you to create a configuartion at runtime rather than relying on a pre-created config file.

FixError WaitForConnection()
You may use this method to wait until a connection has been established with the remote fix engine. The method only returns when (a) the Local Fix Gateway makes a connection to a remote Fix Engine, or (b) if an error occurs, or (c) if the CntrlInterface is in use and a Control Message has been sent by another thread. You do not need to make this call, you can go straight into reading messages or sending messages, (if messages are sent and no connection is ever established, they are not lost, they are stored in the local Fix Gateway, if you try to read before the connection is established you will just wait until the connection is made). This method is, perhaps, of most use when the local Fix Gateway is acting as a server.

bool IsConnected()
This method returns true if the local Fix Gateway is connected to a remote Fix Engine.

FixError GetFixMsg(FixString &str)
This is the main method of the object. Your program should enter a loop calling GetFixMsg() until it returns an error. When the method returns without an error, the str parameter contains a fix message. You should query the returned FixError object to see if the message returned was a Fix Message, or a Control Message. Mostly, it will be a Fix Message. If it is not a fix message, the str parameter is meaningless and you must use  GetControlMsg() to get the  ControlMessage information.

FixError SendFixMsg(int type, FixString &str)
This method is used to send a FixMessage to the remote fix engine. You should set the fix-fields of the str parameter and then send the message. The type parameter should be one of the FIX_MSG_  values found in fixconst.h, or any other value denoting a locally agreed fix message type.

void GetProtocolVersion(long &maj, long &min)
Get the protocol version currently active. NB: this is  defined by the config file.

FixError ResetSession()
This resets sequences numbers back to 1 on both sides of the conversation, using the Reset Session mechanism introduced in protocol version 4.2. If the protocol version is bellow 4.2, this method returns an error. When the session is reset, a new log directory is created. For this method to work, ManualSessionSwitch must be set to 1 in the config file.

FixError ResetLogLevel(int n, bool gatewayOnly=true)
This method can be used once a connection is established to reset the log level, valid values are 1 2 or 3. If gatewayOnly if false, then the client log level is also reset.

FixError ResetForwardHtBtFlag(bool flag)
This method can be used once a connection is established to reset the heartbeat forwarding strategy, if flag is true, heartbeat messages are passd to the client app.

FixError ResetRejectionTolerationLevel(long value)
This method can be used once a connection is established to reset the rejection toleration level. If the value is 0, rejections are always allowed, otherwise, the gateway will close down after receiving the specified number of rejections. A value of 1causes the gateway to close immediately it receives a rejection from the remote Fix Engine.

FixError ResetForwardRejectionFlag(bool flag)
This method can be used once a connection is established to reset the rejection forwarding strategy, if flag is true, fix-protocol rejection messages are passd to the client app.

FixError ResetManualSessionSwitchFlag(bool flag)
This method can be used once a connection is established to reset the ManulSessionReset flag (see the config file for more details about this flag.) If  flag istrue, and the fix version is 4.2 or above, a new fix session will only be started if either side initiates a new session (using ResetSession).

FixError BeginBufferedOutput()
After this method has been called, SendFixMsg() merely records the message in a local persistent buffer.

FixError AbortOutputBuffer()
This method closes and discards the local buffer.

FixError FlushOutputBuffer()
This method closes the local buffer, and then sends all messages to the fix gateway. As each message is sent, it is marked as processed, so that if your application fails or is killed, when it restarts, you can use SynchronizeOutputBuffer() to send any pending messages to the gateway. Once FlushOutputBuffer() or AbortOutputBuffer() is called subsequent calls to SendFixMsg() sends messages directly to the gateway, until BeginBufferedOutput() is called again.
The fixtest sample demonstrates the use of output buffering and SetComplete().

FixError SynchronizeOutputBuffer()
You can use this method when your application starts, it will send any pending messages in the local buffer to the gateway. You should only have pending messages if your application failed or was killed.  If you make use of the buffering mechanism, you should call this method immediately after Open() returns success.

bool SetComplete()
This method tells the system that all messages received since the last call to SetComplete() (or since the 1st message was received if SetComplete() has not yet been called) are fully processed. Until SetComplete() is called, all messages currently received will be received again should your application crash or be killed. Depending on how your application is structured, you may call SetComplete() after each message has been processed or wait until a group of messages, i.e. a list, have been processed. SetComplete() is implemented by saving the sequence number of the last completed message, and then passing this to the gateway at startup - the gateway compares this to the last application-level message received, and if it is lower, the gateway requests a resend from the remote fix engine. If you call DisableAutoRecovery() there is then no need to use  Setcomplete(), but this is not recommended.

bool SetComplete(long lastProcesedSeqNum)
This form of SetComplete() allows you to set which sequence number you are 'happy' with. You can extract the sequence number from the Fix Message.

void DisableAutoRecovery(bool mode=true)
This method disables the SetComplete() mechanism. However, doing this is dangerous, since if your application (not the fix gateway) crashed or was kill after it received the message but before it was processed, the message would be lost, as the fix gate will have received it successfully and passed it to your application successfully as well. It must be called before Open() if it is to be effective.

FixError Close(int grace=15)
Close the fix session. If you do not Close an open session, it will be closed automatically in the destructor. If you open a 'server session', and try to close it before a client has connected to it, you will hit a snag - the gateway is 'busy' waiting for a connection, and will not see the 'close' command, consequently, the Close() method will wait up to grace seconds before forcibly  closing a 'server' GateWay if it doesn't close naturally.

FixError Reopen()
If you get an error from GetFixMsg() or WaitForConnection() you can either call Close() and Open() or just call Reopen(). If you get an error from Reopen(), then you should call Close() and Open().If you call Close(), Reopen() will not work and you must call Open(). Any additional login or header tags you have set will still be active after a Reopen(), but will not be active after a Close(). NB:  Reopen() will return an error if no connection has ever been established, i.e. it should be used after a connection has been established and then closed by the other side.

FixError RunScript(LPCTSTR path, long &numberOfMessages, int reconnect=0, int maxretries=0)
Run a script, the number of messages processed is returned in numberOfMessages. See bellow for the format of a script file. If reconnect is specified, the fix session is automatically reconnected after waiting reconnect seconds - this process is repeated for maxretries times (or forever if maxretries is 0). Note: if the configuration specifies the fix gateway is in server mode, the reconnect will cause the gateway to wait for another connection. You may pass -1 as the reconnect parameter, in which case their is no delay before the reconnection attempt - you may want this if your fix gateway is acting as a server. (see the configuration file section for how to configure the gateway as a server)

FixError RunJournal(LPCTSTR path, long &numberOfMessages)
Process and send the messages in a journal file.

FixError FixClient::OverrideTargetSubId(LPCTSTR newId, bool permanent=true)
You can use this method once a connection has been established to override the TargetSubID defined in the config file. If permanent is false, the change is only applied to the next message you send, otherwise it is applied to all subsequent messages (resent messages are, of course, resent with their original TargetSubID)

FixError FixClient::SetAddionalLoginTags(const FixString &tags)
This method can be used before the FixClient::Open() call to define some additional fields to be sent in the Login message - i.e. this can be used to support non-standard login tags.

FixError FixClient::SetAddionalMsgTags(const FixString &tags)
This method can be used before the FixClient::Open() call to define some additional fields to be sent in all outgoing messages  - i.e. this can be used to support non-standard header/trailer tags (actually the tags are always added to the end of the message, but before the standard fix trailer).

FixError ResetSessionAtLogon();
This method van only be used before a connection is established, i.e. before the Open() call has been made. This instructs the system to include a reset-sequence-number directive with the initial logon. The sequence numbers will be reset to zero on both sides. This can only be used, of course, if the sequence numbers are already ‘in-sync’ to start with. This method can only be used with Fix 4.1 and higher.

FixError ResetSequenceNumber(long num)
This method provides an interface to the Fix Protocol RESET SEQUENCE NUMBER message, sequence numbers can only be increased in value, so the num parameter is added to the current value of the outgoing sequence  number. NOTE: you shoukld not attempt to send this FIX message yourself, if you want to send the message, use this method, however you are very very unlikely to actually want to do this, you are very very unlikely to find this method useful for any  purpose!

void  GetControlMsg(short &msg, StringType &s)
void  GetControlMsgString(StringType &s)
short GetControlMsg()
These methods return the value of the control message (and it's string parameter, if one was present)

SOCKET GetControlInterface(bool detatch=false)
This can be used if a ControlInterface is in use  and you wish to send a response back using  CntrlInterface::SendResponse()  - the control messages  values/contents are chosen entirely by you, but the  intention is that they be used for simple queries  and shutdown commands. If detatch=true, the ‘raw’ Control Interface socket is ‘detached’  from the FixClient Object. The purpose of doing this is so that the socket is not closed by the FixClient::Close() method. You can then close the FixClient and the Control Interface held by the UI thread will remain valid. Thus if you decide to open another FixClient object, you can ‘reuse’ the Control Interface without having to inform the GUI client. The fixgwsrv sample shows the usage of this call.

bool FixClient::AttachControlInterface(SOCKET csd)
Attach a previous detatched ‘raw’ Control Interface. This call MUST be made before FixClient::Open() is called, otherwise it will fail. (If you pass a Control Interface Object in the Open()call, then that is the interface that will be used, and the previously attached ‘raw’ interface will be ignored.)

FixError FixClient::ExpungeSessionData(LPCTSTR configFile)
This method can be used to discard all session information effectively setting the sequence numbers back to zero for the local Fix Gateway. The method can only be used when  the session is not active, i.e. call Close() first then call this method. This method is just a convenient way for you to reset the sequence numbers if you want to, doing this discards session data resting everything. In fact the session data is saved in a director named “-N-{log directory}”, where N is a number that will always increase.

QueryOutSeqNum(int outwardSeqNum, FixString &s)
This method allows you to lookup a sequnce number in the outgoing message journal. It might be used if you receive a message indicating an order has been rejected and want to examine the  information in the order-message you sent.

FixError SetRecoverySeqNos(long out, long in = -1)
This method can be used to recover a connection after complete sequence number failure. To achieve this you must call this method before the FixClient::Open(), probably with out = 899999 and the default in parameter. After the connection has been established, the session will be automatically reset, and both sides will have sequence numbers of 0. IMPORTANT: do not use this method as a 'matter -of-course' - only use it to recover the situation described here. This method can only be used with Fix 4.2 and higher.

bool FixClient::GetGmtOffset(int &offset) 
If a Virtual Timezone is being used in the Gateway process, this method returns true and sets offset to the offset from GMT of the Virtual Timezone.  To find the time as viewed by the gateway process, use code like…

time_t t;
time(&t);
int offset;
if( fixcli.GetGmtOffset(offset) )
    t += offset;
FixError ConfirmResend(bool okToResend)
Call this method in response to a Resend Confirmation Request. You can configure the system to ask for confirmation when resending time-sensitive messages.
 
FixFileClient

FixFileClient is derived from FixClient, and so supports all the methods on the above class. The following documented  methods are the ones that are overridden and have different behaviour. No gateway process is created, instead, messages are read from an input file and written to an output file. The format of the files is simply a sequence of fix strings, separated by new-lines.

#include <fixcli.h>

FixFileClient(LPCTSTR infile, LPCTSTR outfile, bool simulateHeartbeats=false)
Create and initialize a FixClient object. The object is not connected to the fix gateway until Open() is called.

~FixFileClient()
Close any open session before destroying the object.

FixError Open(LPCTSTR configFile, LPCTSTR gatewayHost=NULL, CntrlInterface *pCtrl=NULL)
Open a fix session. The parameters of the fix session, are held in the configFile. The config file can be a full pathname, but more usually, it is just the filename, without extension - given such a value, the fix gateway will look (under UNIX) in /Octatec/fixgw/Home/configs (and under WIN32) in C:/Program File/Octatec/fixgw/configs  for a file of the same name and a .cfg extension.

FixError GetFixMsg(FixString &str)
This is the main method of the object. Your program should enter a loop calling GetFixMsg() until it returns an error. When the method returns without an error, the str parameter contains a fix message. You should query the returned FixError object to see if the message returned was a Fix Message, or a Control Message. Mostly, it will be a Fix Message. If it is not a fix message, the str parameter is meaningless and you must use  GetControlMsg() to get the  ControlMessage information. This method reads fix messages from the infile specified in the constructor. If the simulateHeartbeats parameter in the constructor is true and if the config file specifies that heartbeats are to be passed to the clients, heartbeats are generated and passed to the client at appropriate intervals.

FixError SendFixMsg(int type, FixString &str)
This method is used to send a FixMessage, it merely writes the message to the outfile specified in the constructor. You should set the fix-fields of the str parameter and then send the message. The type parameter should be one of the FIX_MSG_  values found in fixconst.h, or any other value denoting a locally agreed fix message type.

FixError ResetSequenceNumber(long num)
FixError ResetSession()
FixError Close()
FixError SendHeartbeat()
FixError SendTestRequest()
These methods all return FIX_OK, but perform no action !

FixError Close()
Close the fix session. If you do dot Close an open session, it will be closed automatically in the destructor.

bool FilesOpenOk()
This method can be called after the constructor to check that the files were opened without errors.
 
 
DynamicFixCfg

This object can be used instead of a static configuration file. Actually, it allows you to programmatically create a config file; ultimately, a config file is still used. One of these objects can be passed to the FixClient::Open() call  instead of the name of a Config file. If you use this facility, don't be tempted  to re-create a config with the same name, but with a different host name as this will cause the fix journals to become mixed up/corrupted.

DynamicFixCfg(LPCTSTR name)
Construct a DynamicFixCfg with the name of the configuration. Do not use path-names or file extensions in the name, just use simple names.

LPCTSTR GetConfigName()
Get the name of the config, this will be the parameter passed into constructor.

bool Set(ParamName param, LPCTSTR value)
Set the value of a parameter. All the possible values of  param are contained in the ParamName enumeration witin the class. The values must always be strings. All the possible parameters of the config file can be set using this method. The config parameters  LocalId, TargetId, Host and Port must all be set, all other parameters have valid defaults. Note: if you don't specify a log directory, %/logs/configName is used, where % represents the installation directory - this directory, or any you specify yourself,  must already exist - it is not created for you.

bool Save()
Save the configuration. This creates an actual config file. If you pass the object to FixClient::Open(), this method is automatically called, and the resulting config file is then used to actually perform the open.
 
 
FixError

#include <fixcli.h>

All the fix methods return a FixError object to indicate their success or failure. A FixError has one member, int m_err, a value of 0 (FIX_OK) or higher indicates success. FixError objects can be tested for success or failure using boolean operators.

FixError Values

FIX_OK (0)
    no error

FIX_LOGOUT (-1)
    the remote side logged out
FIX_DROPPED (-2)
    the remote side droppend the line
FIX_CANT_CONNECT (-3)
    can't connect to the remote
FIX_NO_CFG (-4)
    the config file specified does not exist
FIX_NO_GTWY (-5)
    the gateway process cannot be started
FILE_OPEN_ERROR(-6)
    couldn't open the config file or an inpuit/output file
FIX_IN_USE(-7)
    the configFile specified in the open call is already opened in this or another process.
FIX_BAD_DYN_CFG (-8)
        you passed a DynamicFixCfg object to  FixClient::Open(), and DynamicFixCfg::Save() failed.
FIX_BAD_ID (-9)
        the other side of the Fix Conversation has an unexpected ID or SubID, the IDs of the sender are specified in the config file, and are called
        the TaregetID and TargetSubID, these must match what the Sender actually sends, similarly our IDs may well be checked by the Sender,
        these are called the LocalID and the LocalSubID in the config file.
FIX_OUT_OF_SYNC (-10)
        The gateway process is issuing resend requests but the remote fix engine is rejecting these requests
FIX_BAD_FIX_VER (-11)
        The gateway process detected an incompatible Fix Version specified in the config files.

NO_ADMIN_INTERFACE (-1000)
    this error can only occur when trying to 'run' a script
        or journal file, and the session is not correctly initialized
NO_FILE (-1001)
    the script or journal file you are trying to run does not exits
WRONG_PROTOCOL_VERSION (-1003)
    a session reset was attempted but this is not allowed in the current protocol version

FIX_CLT_IF_ERROR (-992)
FIX_SELECT_ERROR0 (-993)
FIX_SELECT_ERROR1 (-994)
FIX_INIT (-996)
    internal errors

FIX_ERROR (-999)
    a general error

FIX_CONTROL_MSG (1)
    not an error, and indication that the message is a control message, not a FIX message

Methods
bool IsControlMsg()
bool IsFixMsg()
bool IsError()

After FixClient::GetFixMsg() returns a FixError object, you can use the above methods to see what kind of message has been returned. Equally, you can use the ! operator, to see if the object indicates an error.
 
CntrlInterface

#include "cntrlif.h"

This class allows you to pass messages from a controlling thread, e.g. a user interface thread into the fix message loop of a fix worker thread. Once in a Fix Message Loop, the thread is waiting for messages from the Fix Gateway and/or messages from the Control Interface. Unless you use the Control Interface, their will be no way for you to control the Fix Message Loop except when a Fix Message arrives. The main reason for implementing the Control Interface object is so that a GUI thread can tell the FIX thread to shut down. The fixgwsrv program shows how the Control Interface can be used.

CntrlInterface(int remotePort = -1, LPCTSTR remoteHost = NULL)
The remotePort and remoteHost parameters are currently ignored.

~CntrlInterface();

bool InitControlSide();
Call this method first in the control (GUI) thread

bool WaitForActivation(bool sendStartMsg=true);
Call this method in the Control (GUI) thread after the worker thread has been created, it will wait  for the worker (FIX) thread to become 'ready'. Once the worker thread is ready, provided sendStartMsg was true, WaitForActivation() will send a start message allowing the worker thread to continue and connect to the remote fix engine. If sendStartMsg was false, you must manually send a start message when the time is right.

bool SendStartMsg()
You only need send a Start Message after if you passed in false to WaitForActivation(), if you did, you must call this method at some point after WaitForActivation() returns true.  This allows you to control when the Fix Message Loop actually begins.

bool SendMsg(short iparam, LPCTSTR sparam=NULL);
You can use this method to send messages to a thread in a Fix Message Loop, the messages are entirely under your own control but should all have values above 100, values below 100 are reserve for internal use. It is intended that this mechanism be used for simple  queries and commands, e.g. to shutdown the gateway. The messages will be received in the Fix Message Loop via FixClient::GetFixMessage(), areturn of FixError::FIX_CONTROL_MSG from  FixClient::GetFixMessage() indicates that you should call FixClient::GetControlMsg() and optionally FixClient::GetControlMsgString() to examine the message and any parameter. Normally, SendMsg() will be called from the Control (GUI) thread to send a message to the worker (FIX) thread, possibly to shut down, it is unlikely, but possible, you may want to send a response to the message, to do this, use the SendResponse() method

static bool SendResponse(SOCKET sd, short iparam, LPCTSTR sparam=NULL)
Call this method in the worker (FIX) thread to send a response back to the Control (GUI) thread if you know one is required.

bool GetResponse(short &iparam, StringType &s)
If you are expecting a response to the message, you can use this method in the Control (GUI) thread to wait for it. Mostly, messages you send to the fix thread will not give rise to a response.

int GetLastError()
Return the last error value.
 
 
FixStr

#include <fixstr.h>

This class provides the functionality for building fix messages and accessing all the fields of the message. It is used extensively in the Fix Gateway process, and in the Fix Gateway lib, but probably, you will only need to use the Access methods, GetField(), AddField(),  and to a lesser extent UpdateOrAddField() and RemoveField(). The fixconst.h file provides you with a list of current Fix Fields and Message Types. You can, however, use any value as a Fix Field ID, and any value for a Fix Field Type.

FixString()
FixString(LPCTSTR s)
Construct a fix message string, either empty, or from a string containing fix fields. Note: their is no validation of the string passed into the constructor.

void Set(LPCTSTR s)
Set the contents of the fix string to the specified value. Note: their is no validation of the string passed in.

int GetType()
Return the type of a fix message. This will be one of the FIX_MSG_* values defined in <fixconst.h>

bool GetField(int name, StringType &value)
bool GetField(int name, int     &value)
void AddField(int name, int value)
void AddField(int name, LPCTSTR value)
void UpdateOrAddField(int name, int value)
void UpdateOrAddField(int name, LPCTSTR value)
bool RemoveField(int name)
The above set of methods are likely to be the most useful. In all cases name is just the numerical value of the field (tag). It is most likely to be one of the FIX_FLD_* values in <fixconst.h> but could be any value. The methods treat the contents of fields as either strings or integers, if the field has a different type, e.g. date/time or floating point, you must extract it as a string and convert it. (Their are some helper methods for converting dates).

void SetXmlPayload(LPCTSTR xmlText)
This method discards any tags you ay have already set, just sets the XmlDataLen and XmlData tags based on the xmlText parameter. You probably shoudn’t add any more tags to the message after this one, although you can if you want. You can then send the message using any ‘type’ you wish, it is up to the receiving end to be prepared to decode your XML payload if you use a traditional FIX-MSG-TYPE, or to understand any other type filed you may choose to use, such as “XML” or “FIXML”. It is up to you to serialize your XML into a flat sting before passing it to this method, this might be as easy as reading it into a buffer from an xml file. Note: if you are sending FIXML, there are a couple of config parameters to help you, and a further discussion here.

bool GetXmlPayload(StringType &s)
This method is realy the equivalent of calling GetField(FIX_FLD_XmlData, s) If there is no XML payload present, false is returned.

static void   FormatDate(StringType &s, time_t tim=0, bool localTime=true);
static void   FormatTime(StringType &s, time_t tim=0, bool localTime=true, int ms = -1);
Convert the date in tim into a fix format string. If tim is 0, then  the current date/time is used. If localTime is false, the value of tim is treated as GMT. The output is written into the string s. NB: if the fix protocol version is 4.2 (or higher) and if ms  > -1, milliseconds are added to the formatted string. Note: if you are passing in a virtual-time-zone adjusted time_t value, pass localTime=false.

static time_t ParseDate(LPCTSTR s, int isdst = -1); // YYYYMMDD
static time_t ParseTime(LPCTSTR s, int isdst = -1, int *pms = NULL); // YYYYMMDD-HH:MM:SS.sss
Convert the date or date-time in s to a time_t.  The isdst parameter copied into a struct tm parameter which is passed directly into the C library function mktime(). NB: if the fix protocol version is 4.2 (or higher) and if pms is not NULL, *pms is assigned the milliseconds  in the string (or 0 if none).

void InitEnum()
bool EnumNextField(int &name, StringType &value);
These 2 methods enable the enumeration of all fields in a fix string. You should call InitEnum(), once then repeatedly call EnumNextField() until it returns false.

bool VerifyChecksum();
bool VerifyLength();
Methods to verify the value of a complete fix string. It is unlikely you will need these methods

void EmptyString()
Clear the contents of a fix string

LPCTSTR GetString()
Get a pointer to the actual string

FixString(LPCTSTR myId, LPCTSTR mySubId, LPCTSTR targetId, LPCTSTR targetSubId)
void SetIDs(LPCTSTR myId, LPCTSTR mySubId, LPCTSTR targetId, LPCTSTR targetSubId)
LPCTSTR Compile(char msgType, int seqNum )
static bool SetFixVersion(int maj, int min)
The above methods are for advanced users and used by the Fix Gateway Engine - it is unlikely you will need these methods, they build the actually fix message header/trailer  before sending it. Basically the way it works is, you create your fix string with the 4 ID values, then add fields that you need. Finally, you 'compile' your string, passing in the type of the fix message and a sequence number. Note when setting the fix version, maj must be 4! Further note, the protocol version is set in the config file, and is a property of the gateway, not the client application.
 
 
StringType

#include <strtype.h>

This is a utility class for string handling. It is used extensively in the Fix Gateway and Fix Gateway Library - you may use it in your application if you wish. It has the following methods. It has much in common with the MFC String Class.

StringType()
StringType(const StringType &s)
StringType(LPCTSTR s)

virtual ~StringType()

void Attach(char *s)
If you attach a pointer, the String object will delete it in its destructor do not delete it yourself, - only attach pointers that have been allocated using the new char[] operator, do not attach pointers that have been created in any other way, e.g. using malloc().

StringType &operator=(const char *s)
StringType &operator=(const StringType &s)

StringType &operator +=(LPCTSTR s)
StringType &operator +=(const char ch)
StringType &operator +=(const StringType &s)

char GetAt(int i)const
char operator[](int i)      const
void SetAt(int i, char c)

int Find(char c);
int Find(LPCTSTR s, int startAt=0)
Find the first occurrence of the specified string of character.

void Empty();

bool IsEmpty()

int GetLength()

bool operator==(const char *s)      const
bool operator==(const StringType s) const

bool operator!=(const char *s)      const
bool operator!=(const StringType s) const

operator LPCTSTR ()   const

void Format(const char * lpszFormat, ...)
This methods works like sprintf().

char *GetBuffer(int)
NB: the int parameter is never used. This method only returns a pointer to the string, and never allocates memory! The pointer may be NULL.


Resend Confirmation

This facility was introduced in release 16. You can specify a list of messge-types in the config file, for which confirmation will be sought if a message of that type needs to be resent.

E.G. if you place the following entry in the config file

ConfrimResend  B

If a B (News) message needs to be re-sent because the remote Fix Engine has requested a resend, your application will be notified of this and you must respond with either true or false (if you say false a gap-fill will be sent instead).

NB: under normal circumstances all resends occur transparently to the application, but in some circumstances, you may not want to resend a message if market conditions have changed significantly since the time that the message was originaly sent.

The way to implement this in code is as follows…

FixString sfix;
for(;;)
{
  FixError ok = pfix->GetFixMsg(sfix);

  if( ok.IsResendConfirm() )
  {
    // sfix  contains the message that will be resent, 
    // examine it and call ConfirmResend() with true or false
    if( !pfix->ConfirmResend(true) )
        // report error

    continue;
       // continue listening for messages
  }
    else if( !ok )
       // report error
  else
       // process fix message
}



Fix GateWay ActiveX Control (FixGWctl)

NOTE: the FixGW ActiveX Control is only included in the WIN32 version of Fix GateWay.

The functionality of the FixGW class library is encapsulated (and further simplified) by an ActiveX control. This control can be used from VB or C++ applications -
both a VB and MFC sample is included with the distribution. It is even easier to use the ActiveX control that the C++ library, since the complexity of maintaining a User Interface and waiting for FIX messages is automatically handled by the control. Note: there is no reason why you shouldn't have multiple FixGWctl components in the same application, if that's what you want.

The following VB code fragments demonstrate how the FixGWctl control is used. Firstly, you will to insert a FixGWctl component from the VB Project/Components menu, then use following calls...
 

Private Sub Connect_Click() '// imagine a button that initiates a connection
                            '// to a 3rd party remote FIX Engine
    FixGW1.DisableAutoRecovery True
           '// so we don't have to call SetComplete
            '// after each send or group of sends

    FixGW1.Open "loopback"
           '// a standard configuration that
           '// defines the port and IPaddress

    FixGW1.AsyncGetMsg
            '// tell the control we are ready
            '// to receive message notifications
End Sub
 

Private Sub SendMsg_Click() '// imagine a button that sends a test
                            '// FIX News message to the remote
                            '// FIX engine
    Static n As Integer
    Dim text As String

    text = "Test News " & n

    FixGW1.InitMsg Asc("B")
           '// Initialize a FIX news message
           '// FIX_MSG_News

    FixGW1.AddField 58, text
           '// Add a field to the message
           '// FIX_FLD_Text = 58

    FixGW1.SendMsg
        '// if an error occurs you will be notified via
        '// an error event

    n = n + 1

End Sub

Private Sub FixGW1_OnFixMsg(ByVal msgType As Long)
           '// this event is fired when a FIX message arrives

    Dim text As String
    Static count As Long

    If (Chr(msgType) = "0") Then  '// FIX_MSG_Heartbeat

        text = count & ": GotFixMsg <HEARTBEAT> " & msgType

    ElseIf (Chr(msgType) = "B") Then  '// FIX_MSG_News
        Dim s As String
        s = FixGW1.GetField(58)
           '// FIX_FLD_Text
            '// NOTE - this method gets fields from the INCOMMING message
            '// not the outgoing message that we have just sent

        text = count & ": GotFixMsg NEWS<" & s & "> " & msgType
    Else
        text = count & ": GotFixMsg " & msgType
    End If

    count = count + 1

    FixGW1.AsyncGetMsg
        '// tell the controll we are
        '// ready to recieve fix messages again

End Sub

Private Sub FixGW1_OnFixError()
        '// this event is fired if any errors occur

    Dim msg As String
    msg = "FIX SESSION ERROR " & code
    MsgBox msg

End Sub
 

And that's all there is to it. Very easy indeed. Equally as easy in C++.

For those interested in such things, the FixGWctl is a C++ control written using the ATL. It uses the FixGW class library above to actually make Fix connections and send messages.

Method List

The full set of methods on the control are listed below...

[id(1)]  HRESULT Open(BSTR configName);
Use this method to connect to a remote FIX Engine. The configName parameter is the name of a configuration file, that, amongst other things, defines the IP-address
and port of the remote FIX Engine. If Open() has already been called, and Close() has not been called,  an HRESULT of  -3 is returned, if the Open() fails for any other reason, an Error Event is fired.

[id(2)]  HRESULT Close();
Use this method to close the connection to the remote FIX Engine.Close() must always be called to close a session, even if Open() failed!

[id(3)]  HRESULT InitMsg(long type);
Us this method to initialize a message for sending. The type parameter is the type of the FIX message. Once this has been called, use th AddField or UpdateField method.

[id(4)]  HRESULT AddField(long id, BSTR value);
[id(5)]  HRESULT UpdateField(long id, BSTR value);
[id(6)]  HRESULT AddFieldInt(long id, long value);
[id(7)]  HRESULT UpdateFieldInt(long id, long value);
These methods set fields on the message. AddField will add multiple fields if the field already exists in the message, UpdateField will Add the field if it doesn't exist, or modify it if it does.

[id(8)]  HRESULT SendMsg();
Once all fields have been added , use this method to send the message.

[id(9)]  HRESULT AsyncGetMsg();
This method can be called at any time after the connection has been opened. Once called, the activeX control will deliver at most one message to the application by means of an asynchronous ActiveX event. To obtain subsequent messages, this method must be called again - it is usual to call it as the last thing done in the method that handles the FixMsg event.

[id(10)] HRESULT GetField(long id, [out,retval]BSTR *presult);
[id(11)] HRESULT GetFieldInt(long id, [out,retval]long *presult);
[id(12)] HRESULT GetMsgType([out,retval]long *presult);
Once the FixMsg event has been fired, these methods can be used to obtain the fields of the message. The type of the message is actually a parameter to the FixMsg event, so you probably never need to callGetMsgType. The values returned by these methods always relate to the incoming message, they do NOT relate to the values passed in theAddField/UpdateField methods above. The values remain valid only until the next call to AyncGetMsg, after which, they will be replaced by the values from the next message, as soon as it arrives.

[id(13)] HRESULT DisableAutoRecovery(BOOL dissable);
If you use this method, you must call it before the call to Open. It removes the need to make any calls to SetComplete below.

[id(14)] HRESULT SetComplete();
Imagine the scenario where you are processing an incoming list of message, perhaps the list comprises the orders for one portfolio. You do not save the portfolio until the last order has been received. Now, if the FIX connection goes down just before the last message has arrived, what happens. Well, the Fix protocol layer will only re-request messages it has not  received, and since most of the messages belonging to the list have been received they will not be re-requested. Your application must save the messages in the list some-how, and re-start from where it left off once the Fix Session has been re-established. The SetComplete method allows you to set check-points, whereby, in the event of a connection failure, all messages received since the last call to SetComplete will be re-requested, so in the above scenario, you would call SetComplete after each portfolio has been successfully processed and saved.

[id(15)] HRESULT BeginBufferedOutput();
[id(16)] HRESULT AbortOutputBuffer();
[id(17)] HRESULT FlushOutputBuffer();
These methods provide you with an output buffer. In the above scenario, you may want to send and acknowledgment after each item in the list has been processed, but you might not want to actually send the acknowledgements until all the items in the list have been received. If you call BeginBufferedOutput, all subsequent calls to SendMsg merely record the message in an internal buffer - the messages are not actually sent until FlushOutputBuffer is called. If connection errors occur during the flush operation, any partly flushed buffer is automatically fully flushed the next time the application is re-started. If AbortOutputBuffer is called, the buffer is discarded.

[id(18)] HRESULT ResetSession();
This method is only available in FIX Version 4.2, it initiates a session reset.

[id(19)] HRESULT RunScript(BSTR path, int reconnectFlag);
This method can be used to process a script file.

[id(20)] HRESULT GetLastError([out,retval] long *error);
Call this method to obtain the last error value, 0 is returned if there have been no errors. Note: if an error occurs, a FixError event is fired, with the error code as a parameter. All error codes are negative, and are listed here

[id(21)] HRESULT AddLoginField(long id, BSTR value);
[id(22)] HRESULT AddLoginFieldInt(long id, long value);
Add a tag tat will be sent as part of the Fix logon sequence (to support non-standard login messages). This must be used before the Open() call.

[id(23)] HRESULT AddHdrField(long id, BSTR value); 
[id(24)] HRESULT AddHdrFieldInt(long id, long value);
Add a tag tat will be sent as part of every fix sequence (it is actually added to the end the  tags but before the standard fix trailer). This must be used before the Open() call.

[id(25)] HRESULT SetRecoverySeqNos(long out, long in);
This can be used to recover from certain out-of-sequence conditions, as explained here. (it should be used with care)

[id(26)] HRESULT ResetSessionAtLogon();
Arrange for the Logon message to also reset the sequence number of both sides. This must be used before the Open() call.

[id(27)] HRESULT InitMsgEx(BSTR type);
Use this method to initialize a Fix Message where the Type is longer than a single character.

[id(28)] HRESULT PreferStringMsgTypeEvent(BOOL useString);
Call this method to arrange for all notifications to be via OnFixMsgEx rather than OnFixMsg.

[id(27)] HRESULT InitMsgEx(BSTR type);
Call this method to get the message type where you are processing messages that might have a type longer than a single character. If the type is a single character, that’s fine, the string will be just one character long.

[id(30)] HRESULT OverrideTargetSubId(BSTR newSubId, BOOL permanent);
Change the target SubID at any time during the session. If permanentisfalse, the change is for the next outbound message only.

[id(31)] HRESULT BeginFieldEmum();
[id(32)] HRESULT EnumNextField([out]long *id, [out retval]BSTR *value);
[id(33)] HRESULT EnumNextFieldInt([out] long *id, [out retval]long *value);
These methods can be used to enumerate the fields in the current message. The value parameter will be 0 when there are no more fields available.
E.G.
               Call FixGW1.BeginFieldEmum
        Dim Value As String
        Dim Id As Long
        Id = 1
        Do While (Id <> 0)
            Value = FixGW1.EnumNextField(Id)
        Loop

Events

The FixGWctl control fires only 3 events, these are as follows...

[id(1)] void OnFixMsg(long msgType);
This event is fired when a Fix Message arrives - AsyncGetMsg must previously have been called for this event to be triggered. Once the method has fired, no more FixMsg or FixMsgEx events will be triggered until AsyncGetMsg has been called again. The msgType parameter contains the type of the message received.

[id(2)] void OnFixError(long code);
This event is fired if an error occurs. All error codes are negative, and are listed here. Attempts to call methods other than Close() and  GetLastError() will fail after an error event has been fired. The session  must be closed if an error occurs. Close() must always be called to close a session, even if Open() failed!

[id(3)] void OnFixScriptComplete();
This event is fired when a Script has completed.

[id(4)] void OnFixMsgEx(BSTR msgType);
This event is fired when a Fix Message arrives - AsyncGetMsg must previously have been called for this event to be triggered. This event is different from OnFixMsg in that the msgType parameter  is a string, it is fired if the Fix Message type is more than one bye in length. If you call PreferStringMsgTypeEvent(TRUE) all notifications will be via this event and OnFixMsgwill not be fired, and thus you need only implement this event. Once the method has fired, no more FixMsg or FixMsgEx events will be triggered until AsyncGetMsg has been called again.

NB: the …Ex() methods were implemented to add support for message types longer than a single character.  Even if your message type is a single character, you can still use the  …Ex() methods, and by calling  PreferStringMsgTypeEvent you can ensure that you only receive OnFixMsgEx notifications, making your application simpler.

HRESULT Return Values

The control defines its own set of HRESULT returns from methods. If one of these values is returned, it will result in an exception in the client application, in terms of MFC applications, a pointer to a COleDispatchExceptionobject is thrown by MFC, the m_scError member will contain the actual return code. Possible return codes are as follows...

-1        connection not open
-2        attempt  to send a message without initializing it
-3        attempt  to open an already open connection
-4        error state - the fix connection is in the 'error state', i.e. the OnFixError event has been fired. The connection must now be closed.
-5        no parameter block (this indicates  an internal error and should never be seen).
 

The VB Sample

The sample implements the following scenario...

(sample app|FixGWctl)...[FixGatwWay,cfg:loopback] -----//----- [FixGAteWay,cfg:testsrvr]...(testsrvr app)
 Client                      local Fix Engine                      remote Fix Engine       remote server app

Refere to the system components diagram for more details on the relationship of the client application to the Fix GateWay process.
 
This VB samples implements the code fragments above. When you click the Connect button you will be asked to start the fixgwsrv test server program. Doing this gives the application a 'dummy' remote fix Engine to connect to. 

To use the sample, click Connect, start fixgwsrv (a consol app) as directed and take the o option to open a session within fixgwsrv, and then just hit return to accept the default fixgwsrv session. From fixgwsrv, you can use the  h option to send a heart beat to this app, it will appear in the text box. Take the vfixgwsrv option for verbose mode, then, returning to this app, click the Send Msg button, you will see a News message appear in the fixgwsrv window.

The C++ MFC Sample

This application implements the same functionality as the VB app. It is, however slightly more sophisticated, in that the Connect button will automatically start fixgwsrv as well, but you still need to enter o and accept the default in the fixgwsrv window.

The lower half of the screen contains some diagnostic buttons that will display log files and configuration files - these are purely for information and are not required for the app to establish a FIX session.

Just like the VB app above, this app opens a Fix Gateway session using the standard "loopback" configuration, the test fixgwsrv application opens its own Fix Gateway session using the "testsrvr" configuration. These 2 configurations are supplied with the distribution and designed for testing purposes. They allow a test client application (in this case the sample) to connect to a test server application (in this case  fixgwsrv) via a FIX session.

(NB: to add the FixGWctl ActiveX control to an MFC app, just use the Project/Add To Project/Components and Controls Visual Studio menu option, and then select Registered Active X Controls from the list.)


The FixGWLite Automation Object

NOTE: the FixGWLite Automaton Objet is only included in the WIN32 version of Fix GateWay.

This object implements much the same interface as the FixGWCtl, however this object cannot process asynchronous messages. This object can be used in the simple scenario, where you need to send a series of messages and then listen for responses in an ordered synchronous manner.

The object is named FixGWLite.API.1

[id(1)] HRESULT Open(BSTR configName);
[id(2)] HRESULT Close();
[id(3)] HRESULT InitMsg(long type);
[id(4)] HRESULT AddField(long id, BSTR value);
[id(5)] HRESULT UpdateField(long id, BSTR value);
[id(6)] HRESULT AddFieldInt(long id, long value);
[id(7)] HRESULT UpdateFieldInt(long id, long value);
[id(8)] HRESULT SendMsg();
[id(9)] HRESULT GetMsg([out,retval]long *msgType);
[id(10)]HRESULT GetField(long id, [out,retval]BSTR *presult);
[id(11)]HRESULT GetFieldInt(long id, [out,retval]long *presult);
[id(12)]HRESULT DisableAutoRecovery(BOOL dissable);
[id(13)]HRESULT SetComplete();
[id(14)]HRESULT ResetSession();
[id(15)]HRESULT RunScript(BSTR path, int reconnectFlag);
[id(16)]HRESULT GetLastError([out,retval]long *error);
[id(17)]HRESULT BeginBufferedOutput();
[id(18)]HRESULT AbortOutputBuffer();
[id(19)]HRESULT FlushOutputBuffer();
[id(20)]HRESULT AddLoginField(long id, BSTR value);
[id(21)]HRESULT AddLoginFieldInt(long id, long value);
[id(22)]HRESULT AddHdrField(long id, BSTR value);
[id(23)]HRESULT AddHdrFieldInt(long id, long value);
[id(24)]HRESULT SetRecoverySeqNos(long out, long in);
[id(25)]HRESULT ResetSessionAtLogon(); 
[id(26)]HRESULT InitMsgEx(BSTR type);
[id(27)]HRESULT GetMsgEx([out,retval]BSTR *msgType);
[id(28)]HRESULT OverrideTargetSubId(BSTR newSubId, BOOL permanent);

The main difference to the FixGWCtl ActiveX control is the GetMsg() method, this will not return until a message arrives or an error occurs (such as the remote system dropping the line)


FixGW Error Handling Strategies

The Fix Gateway is a separate process running the fix communication protocol with a remote Fix Engine. The user application communicates with the Fix Gateway via a socket. If the line drops between the Fix Gateway and the remote Fix Engine, the user application must be notified, and any messages that the User application has sent before the error notification must be guaranteed to arrive at the remote Fix Engine. This section explains how this is achieved. Note, the fixtest and fixgwsrvutilities can be used to test the system's terror handling capability.

Connection Errors While Sending Messages

When the FixClient::SendFixMsg() is called, the message is sent to the Fix Gateway via a socket,  provided no error occurs in the call to send the message on the socket, FixClient::SendFixMsg() returns successfully. The problem is, that the line between the Fix Gateway and the remote Fix Engine may have dropped, but the SendFixMsg method does not detect this. (NB: SendFixMsg could query the state of the FixEngine but this would slow things down too much).

In the Fix Gateway process, when a message is received via FixClient::SendFixMsg() it is sent to the remote Fix Engine - if the line to the remote Fix Engine is down, the message is added to the fix Journal file, and the outgoing sequence number is incremented so that when the connection is re-established, the message will be requested by the remote side. When this happens, an Out-Of-Band message is sent back to the User Application setting and error state flag. FixClient::SendFixMsg() checks  the error state flag, and if it finds it set, it returns an error. The consequence of this strategy is, some messages may be sent when the fix connection is down, but this should only be one or two messages before the User Application is detects the error, and these messages are not lost, they are transmitted as soon as the fix connection is re-established.

If the User Application is waiting for a Fix Message and the fix connection drops, an internal fix-admin messages is sent to the User Application to notify it of the error condition straight away.

Sending Messages Using Buffers

The fixgw library implements a buffering facility which enables your application to send messages to a local buffer rather than sending them to the gateway, then when happy with the current application state, the application can flush the buffer to the gate way. If the line goes down or the application is killed while flushing the buffer, the current position in the buffer is remembered when the application restarts, and by calling FixClient::SynchronizeOutputBuffer(), your application can being sending from the point at which it stopped. Once the buffer has been flushed you should call FixClient::SetComplete() (provided you haven't previously called FixClient::DisableAutoRecovery(), in which case you never need to call SetComplete(). )

The FixClient::SetComplete() method

Once you receive a Fix Message, the fix protocol is done with it, your application should then store it into a database soon as   possible so that if your application is killed or crashes, the message is not lost. 

Imagine the situation where your application is slow (for whatever reason) to processes messages it received. The FixGateway  (FixEngine) process will continue to send you messages until your application (socket) buffers are full. If at this point your   application crashes the messages in the application buffer will be lost, but as far as the Fix protocol layer is concerned, the message   will have been received successfully and will not be re-requested. SetComplete() protects your from this  roblem. 

When the FixGateway starts, it checks its last received sequence number with the one specified in the last call to SetComplete(). If the SetComplete sequence number is lower, it checks in the Receive Journal and if the missing messages are there, it sends them to the client app(with the Possible Dup flag set to Y), and all should be well. If the messages are not in the Receive Journal, the Fix Engine sets its own expected sequence number to the one specified by  SetComplete() thus  forcing a re-send of any 'lost' messages. By the remote side. NOTE: the messages should only be missing from the Receive Journal if the Receive Journal has been switched off. (If you do switch the Receive Journal off, be   aware, that,  if the missing message was time-sensitive, the remote Fix engine may decide not to re-send the message, but rather, replace it with a gap fill.

The best way to use SetComplete() is to save the message in the database as soon as your receive it, and then call   SetComplete(). Then, when your application re-starts, it should check the database for received but un-processed messages first,  process these, and then create the Fix session and continue as normal. 

You may decide to only call SetComplete() when you have fully processed the message, e.g, if you are collecting  messages in a list.  If your application crashes with unprocessed messages in its list, the SetComplete mechanism  will ensure that these messages are  not lost. Doing this removes the need to save the message immediately into the database.

You may call  SetComplete() after each message has been processed, or after a sequence of messages have been processed,   once called, it applies to all messages received since the last call. It is, however, probably  safest to save each   message as you receive it and call SetComplete() after each successful save. 

If you don’t want to use SetComplete()at all, just call DisableAutoRecovery(true) as soon as the session is created.
 


The Script File Format

The FixClient::RunScript() method accepts a script file that contains a set of fix messages and sends them to the Fix gateway. The script file should contain  lines in the following format

BEGIN fixMsgType
This defines the start of a fix message - fixMsgType can be either the actual value of a fix message or a symbolic name as defined in <fixconst.h>, but without the leading FIX_MSG_, i.e. fixMsgType could be E or Order_List

fixFieldId  value
This adds a field to the current fix message - fixFieldId can be the numeric or symbolic id, e.g. 38 or OrderQty, value can be any string, it can contain embedded spaces if it is surrounded by double or single quotes. If the value is a fix-time or fix-date, value can be @N, this is interpreted as the current time plus N seconds, or %N which is interpreted the current date plus N days. If a unique id is required for any value, a & can be used at the start of the string - the & is replaced by the Hour/ Minute/Second at the time the script file began to run, in the form of HHMMSS, the rest of the value is then appended to the HHMMSS - in this way & represents a different value each time a script runs, but the same value for the lifetime of the script. Note for & to be expanded into HHMMSS, it must appear at the start of the string.

If, however, more than one script runs in a second, the &  value will not change. For this reason there are several substitution characters that can be used, but note they must appear at the front of the string

& … substituted with HHMMSS
^  … substituted with HHMMSSmmm where mmm is the current milliseconds value, giving a unique value on a dily basis.
|   … substituted with the number of seconds since 10/10/2001 (in hex), thus | should give a
         unique  8 character value over time provided the script doesn’t run more than once per second.
~ …  substituted with  XXXXXXXmmm where XXXXXXX is the number of seconds since 10/10/2001 in hex and
         mmm is the current milliseconds value,  thus ~ should give a unique 10 character value over time 
         regardless of how quickly the scripts run.

SEND
Send the current fix message to the fix gateway.

RESET_AMPERSAND
Reset the value used when substituting &. This will be reset to the current hour/minute/second - note: the substitution values are automatically reset each time a script runs.

SET_AMPERSAND value
Set the value used when substituting &. The value parameters can be any string. Ampersand substitution is designed to enable the same script file to generate different ID's on each run, but you may, temporally, wish to test what happens when you get 2 runs with the same IDs, in this situation, you can use the SET_AMPERSAND at the top of the script to set a fixed value that will remain the same on each run of the script.

LOAD_AMPERSAND
This command loads a previously saved ampersand (&) value from persistent  storage. If there is not a previously saved value, the ampersand value  is set to 000000. Typically, you will LOAD_AMPERSAND and then INCR_AMPERSAND at the start of the script, and SAVE_AMPERSAND at the end, thus guaranteeing a unique value for ampersand on each script run. Values of ampersand loaded like this will be zero-padded to 6 character positions.

SAVE_AMPERSAND
You can save the current value of & to persistent  storage with this command.

INCR_AMPERSAND
Increment the value of the & substitution, if this is not a numeric value, a value of 0 will be used

DECR_AMPERSAND
Decrement  the value of the & substitution, if this is not a numeric value, a value of 0 will be used

RESET_HAT
Reset the value of the ^ substitution

RESET_BAR
Reset the value of the | substitution

RESET_TILDE
Reset the value of the ~ substitution

BEGIN_BUFFER
All subsequent messages are sent to the buffer, rather than the fix gateway.

FLUSH_BUFFER
Flush  the output buffer, sending buffered messages to the gateway. Subsequent messages are sent directly to the gateway unless BEGIN_BUFFER is called again.

#
This is a comment

A simple script file, to send 2 orders in a list would look like this...

# example script file
BEGIN Order_List
    ListID &4
    ListSeqNo 1
    ListNoOrds 2
    ClOrdID  &01
    ClientID ZCN0002
    Account xxxxxxxxx
    FutSettDate %2
    Symbol OCT.L
    SecurityID 12345678
    IDSource 2
    Side 2
    OrderQty 20000
    Price 987
    Currency GBP
    TransactTime @0
    TradeDate %0
SEND
BEGIN Order_List
    ListID &4
    ListSeqNo 2
    ListNoOrds 2
    ClOrdID  &02
    ClientID ZCN0002
    Account xxxxxxx
    FutSettDate %2
    Symbol OCT.L
    SecurityID 12345678
    IDSource 2
    Side 1
    OrderQty 20000
    Price 987
    Currency GBP
    TransactTime @0
    TradeDate %0
SEND

The fixgwsrv Tool

This tool allows you to run fix client or server sessions with a minimum of effort. The tool understands a simple script format whereby you can send fix message to whoever is connected. The source code for this tool is included as a sample. The tool presents a character-based menu for simplicity and portability, and allows you to 'open' any config file you require. The program can act as a server and/or a client - two versions of the program can run on the same machine and communicate with each other. For testing purposes a configuration file named testsrvr is supplied, this configuration sets the fix gateway into server mode. A second configuration, loopback, is supplied for testing purposes, this config is used by the fixtest sample program, which simply connects to the fixgwsrv on the local machine. You can then send heartbeats and other fix messages to fixtest from the fixgwsrv menu, and watch them appear. This tool is particularly useful when testing your applications, you can create a script-file with a set of standard fix data and run fixgwsrv as a dummy, replacing the actual Fix Engine you will want your application to connect to.

Fixgwsrv displays the following character based menu...

    o) Open Session         c) Close Session
    h) Send Heartbeat       t) Send Test Request
    s) Send Script File     n) Send Test News
        r) Reset Session        q) Test Reset Seq Num

    v) verbose mode

    x) exit

o) open session
This option prompts for the name of a config file, the default value is testsrvr, this implements a server that will listen for incoming connections. The fix session runs in a separate thread leaving a user interface thread free to process menu commands. The c)close session option can be used to close the session.

h) send heart beat
Send a fix heartbeat to the remote fix engine.

t) send test request
Send a fix test request to the remote fix engine - we should get a heart beat in response, which will be seen if verbose mode is on.

s) run script file
Run a script file, 5LISTS.TXT is prompted for by default.

n) send test news
A test news message is sent

r) reset session
cause both sides to reset their sequence numbers back to 1. This will only work if both sides of the fix session are running protocol version 4.2 AND the fix gateway config file must have ManualSessionSwitch set to 0.

q) test reset sequence numbers
The sequence numbers are reset from 100.

v) set verbose mode
Verbose mode switches of the display of the menu, but displays all incoming fix messages as they are received. Menu commands are still processed, and entering v again will switch verbose mode off.

If you select the s) option, you will see the following sub menu

  2) 2 Orders Sample script
  5) 5 Orders Sample script
 OR  the name of a script file

This allows you to easily run the sample scripts or any script of your own. If you want to run your own script, just type its name.

The source code for this tool is included as a sample.


The fixtest Sample

This is a simple test program, the source for which is included in the distribution. This program also display a simple menu, as follows...

fixtest menu

0) normal mode
1) none buffered mode
2) local client crash-simulation testing mode
3) local gateway crash-simulation testing mode

4) test File fix-msg-source and fix-msg-destination

x) exit

To run the test, first start fixgwsrv, and take the (o)open menu option and open the testsrv session - this is the default session to open, so you shouldn't have to type in its name, just accept the default. Now, from a different command line window, start the fixtest program - it will give you a small menu, choose option 0. In order to give fixtest some work to do, return to fixgwsrv and take the (s) send script file menu - you will be able to chose from the pre-defined scripts 5LISTS.TXT (option 5), 2LISTS.TXT(option 2) or enter your own script file name. Running5LISTS.TXT script sends lists of orders to fixtest, which simply compiles these lists into a file, and sends acknowledgements back to the sender. It is a relatively trivial test, but demonstrates many features of the fixgw lib. It can be used to test recovery features in the event of a system failure, as fixtest validates the file it creates, and fixgwsrv validates the replies it receives - the validation is based on the FIX_FLD_ClientID which is set in ascending order in 5LISTS.TXT.

The main point of interest in fixtest is the ProcessFixMsg(FixString &sfix, FixClient &fixcli), where the messages are complied into lists. and void ProcessNews(FixString &sfix, FixClient &fixcli, StringType &orderList) where NEWS messages are handled - the 2 test programs use NEWS messages to trigger certain actions.

Note: if you select option (0), you will be invited to "RELEASE VALIDATION FILES", if you are running a normal test you should enter Y and do this. You should  not do this if you are testing a recovery after a previously simulated crash.

Simple fixtest / fixgwsrv Test Session

This session will involve connecting the fixtest program to the fixgwsrv program via a fix session. They will exchange messages and verify that all messages have arrived successfully. Fixtest will use the loopback configuration file, and fixgwsrv will use the testsrvr configuration file. Both thes config files are supplied with the distribution, in fact fixgwsrvr can load any configuration file you choose, but fixtest can only access the loopback config.
(fixtest)...(FixGatwWay,cfg:loopback) -----//----- (FixGatwEay,cfg:testsrvr)...(fixgwsrv)
 Just follow the simple instructions bellow to run a test fix session...
  1. Start fixgwsrv and fixtest. These programs are both windows console applications.
  2. Select option (o) from fixgwsrv and then just hit return at the next prompt.
  3. Select option(0) from fixtest and enter Y at the next prompt
  4. In fixtest, selectoption (s) and enter 5 at the next prompt
  5. You should see messages scrolling in the fixtest window. After a few seconds you should see the message ORDER FILES VALIDATED AND SAVED in the fixtest window, and [TEST LOG VERIFIED OK]in the fixgwsrv window
  6. Enter x in the fixgwsrv window to close the session.
  7. Fixtest will detect that fixgwsrv has closed, enter a q to close fixtest.

Using fixtest and fixgwsrv To Test The System's Error Recovery Capabilities

Note: in following discussion fixtest is used to refer to the fixtest client application and the associated fixgw process, and similarly fixgwsrv refers to the fixgwsrv client application and the associated fixgw processes. Remember, self validation during these tests rely on the fact that 5LISTS.TXT script files supplied with the distribution has a pre-defined format that allows fixtest and fixgwsrv to determine if all messages have arrived successfully.

Testing Recovery from failure in the User Application

(fixtest)...(FixGatwWay,cfg:loopback) ----//----- (FixGatwEay,cfg:testsrvr)...(fixgwsrv)
this side will crash                              this side will wait for a reconnect

Firstly start fixgwsrv and open a session. Start fixtest in crash-simulation testing mode (menu option 2). Use fixgwsrv to run the  5LISTS.TXT script file (option S and option 5), fixtest will crash half way through, it will either exit directly or give you the option to quit or reconnect, you should quit.   The fixgwsrv program will wait for a reconnection, and then continue sending from where it left off, hence you should restart fixtest in normal mode (option 0) Depending on the situation, it may take up to 30 seconds for the 2 fix engines to re-synchronize, so please be patient. Eventually, messages will flow from where they left off, and fixgwsrv and fixtest should print out a messages indicating that validation has completed successfully.

Restart fixtest in normal mode, it will re-received the orders already sent (but not processed) , and then continue to receive the rest of the messages. fixtest and fixgwsrv will both validate the files they have created, and should report no errors. NB: it may take up to 30 seconds for the 2 fix engines to re-synchronize themselves during error recovery in this and the next test.

Testing Recovery from failure in the Fix Gateway

The assumption is that the gateway process dies because of user intervention, i.e. someone kills it, it will not, of course, crash on its own.

(fixtest)...(FixGatwWay,cfg:loopback) ----//----- (FixGatwEay,cfg:testsrvr)...(fixgwsrv)

            this side dies

Firstly start fixgwsrv and open a session. Start fixtest in local gateway crash-simulation testing mode(menu option 3). Again, use fixgwsrv to run the  5LISTS.TXT script file (option S and option 5). The gateway used by fixtest will die and fixtest will detect this it will either exit directly or give you the option to quit or reconnect, you should quit, The remote gateway server(fixgwsrv) will detect that its fix client(fixtest) has died, it will close down and  inform the user application(fixgwsrv), fixgwsrv will then wait for a reconnection. When fixtest is restarted in normal mode (option 0), it will restart its gateway, which will request a resend of any messages that either it or the user application has lost. Once again, depending on the situation, it may take up to 30 seconds for the 2 fix engines to re-synchronize, so please be patient. Eventually, messages will flow from where they left off, and fixgwsrv and fixtest should print out a messages indicating that validation has completed successfully.

Disclaimer

These tests demonstrates the systems reliability in failure situations. The likely causes of failure are

  1. user application crash
  2. computer failure due to power loss or hardware fault
  3. user intervention to kill the gateway process
The above tests show good recovery in the face of a user application crash, however, the behaviour of the user application is entirely the responsibility of the user. Similarly, if the system fails due to hardware errors, the gateway behaves well, but again, it is the users responsibility to minimize the likelihood of hardware failure, using uninteruptable power supplies and fault tolerant hardware.


Troubleshooting

The main source of information when troubleshooting are the log files. If, however, the problem is related to log-file location specification, you might have difficulty finding the logs. There is a set of informational files created at startup to help diagnose any problem. These files have the name $TEMP/.fixgw-Name.info,
and $TEMP/.fixcli-Name.info where $TEMP is the system temp directory and Name is the name of the information contained. Five such files are created as follows...
 
.fixgw-log.info  The location of the log file
.fixgw-cfg.info The configuration file opened by the gateway
.fixgw-logerror0.info This records errors while creating  the log directory
.fixgw-logerror1.info This records errors while creating  the log directory after a manual fix session switch
.fixgw-root.info The location of the active root - this is an advanced feature and only applicable to UNIX/Linux systems
.fixgw-lic.info  This file is only created if there are any licensing problems.
.fixgw-srv-cfg.info This file records config parameters are read by the gateway process
.fixcli-log.info This  location of the client log file
.fixcli-logerror0.info This records errors during the first stage of creating  the log directory
.fixcli-logerror1.info This records errors during the seconds stage of creating  the log directory
.fixcli-loginit1.info The client session-log directory
.fixcli-loginit2.info The client session-log path
.fixcli-exec.info  The comand issued by the client to start the fix gateway
.fixcli-cli-cfg.info This records config paramaters as read by the client lib

NOTE: You cannot copy FixGateway to another computer and expect it to run. Further, if you rename you computer, you will have to reinstall FixGateway, you can, however, change the IP address and not have to reinstall.


Appendix I - Implementation Notes

The Local Client Reliable Protocol

Before reading this refer to the system diagram.

Now, when the client sends a message and the return code indicates success, as far as the client is concerned the messages has gone and will be received. Under normal circumstances the messages reaches the gateway and is then sent, using the FIX protocol to the remote fix engine. This is all very well, but if the machine crashes, or if someone kills the fixgw process after the message has left the client lib but before it arrives at the gateway, the message is lost, but the client thinks it has been sent. This potential problem is overcome by the ‘Local Client Reliable Protocol’ (LCRP) which is a very simple protocol used between the clientg lib and the fix gateway. Basically every message has its own LCRP number. When the client opens a gateway session, the gateway sends the the client the last LRCP number it received, and the client then checks a local journal file, and re-sends any messages that it previously sent whose LRCP is bellow the number sent by the gateway. Remember, this isn’t the FIX protocol at work here, this is just a mechanism to ensure that if the client lib sends a message, that message is guaranteed to reach the fix gateway regardless.

The mechanism is implemented by a file called jnl.txt, in which outgoing messages are saved. When the library opens a session, it renames jnl.txt, (if it exists), to jnl.wrk and then checks the last LCRP number received from the gateway with records in jnl.wrk and resends missing messages. The jnl.txt/jnl.wrk file is located in a 'session' sub-directory of a directory with the same named as the config file, either located in the system temp directory, in the directory specified by the environment variable FIXGWLOG, or in the directory specified by the CliLogDir config parameter. It follows from this, that if you open a config and each time have FIXGWLOG set to different values or sometimes not set at all, the client lib will behave inconsistently with regard to the LRCP, since it will not be checking the correct journal files against the correct LRCP number - previously sent messages may well get sent again.

Note: one source of problems in this area is if the a config is opened by different users that don’t have FIXGWLOG set consistently.

If for any reason you don’t want this protocol to operate, set UseLCRP  to 0 in the config file
 

Client Buffering Support


This is provided by the methods...

  FixError FixCli::SynchronizeOutputBuffer();
 FixError FixCli::BeginBufferedOutput();
 FixError FixCli::AbortOutputBuffer();
 FixError FixCli::FlushOutputBuffer();
The buffer is persisted in a file located in a directory with the same named as the config file, either located in the system temp directory or in the directory specified by the environment variable FIXGWLOG. It follows from this, that if you open a config file and have FIXGWLOG set to different values or not set at all, the client lib will behave inconsistently with regard to buffering.  Afer a config is opened, if you are using buffering you should call SynchronizeOutputBuffer(). This checks the  buff.cmt file for records that are not flags as having been sent, these are then sent. Buffered records are stored in a file buff.txt until the buffer is flushed, the file is then renamed buff.cmt, and each record is actually sent, as a record is sent it is marked as  sent  within the file.
 

The Implementation of FixCli::SetComplete()

When FixCli::SetComplete() is called, the sequence number of the current message is saved in a file setcomplete.log is located in a directory with the same named as the config file, either located in the place specifed by the CliLogDirconfig parameter or system temp directory or in the directory specified by the environment variable FIXGWLOG. It follows from this, that if you open a config file and have FIXGWLOG set to different values or not set at all, the client lib will behave inconsistently with regard to processing SetComplete() data. When the client starts a new session, it passes the last processed sequence number to the gateway, if this is lower than the last sequence number the gateway received from the remote fix engine, it firstly searches the Receive Journal for the missing messages and, if found, passes them to the client app with the Possible Dup flag set to Y, but if the messages are not found, the gateway uses the sequence number defined by SetComplete so that the missing messages are re-requested from the remote Fix Engine. Note a value of –1 in the setcomplete.log file  is an ‘initial value’ flag, and is ignored.

Appendix II - Recovery from total sequence number failure

Firstly, you should never be in a situation of total sequence number failure unless you have suffered some sort of hardware failure.

Firstly, how could this situation arise. We’ll, if your machine suffers total failure and you move your application onto a backup machine, depending on how things are configured, your backup system won’t know the last sequence number sent, so it can only send 0, the receiving system will likely reject this message as a duplicate and then you’re stuck  - the only thing you can do is phone up the 3rd party and get them to reset their sequence numbers to 0.

We’ll, there is an alternative to phoning up if you are running Fix 4.2 or higher. If you are in this situation, you can use the FixClient::SetRecoverySeqNos() to set the outgoing sequence number to a high value, maybe 899999. How will this help? Well, the 3rd party won’t reject your message, but it will ask for a resend of the sequence number it has missed. Your system won’t of course, have these number, but the FixGateway will know that it is trying to recover a connection from an error condition, so it will respond with a GapFill to the remote site, and then, it will issue a session reset. Thus everything will be working again. Of course, you will have to manually investigate what might have been lost due to the failure of your machine. If you don’t want to suffer this sort of problem in the first place, you should run your application on fault-tolerant hardware, at the very least, you should have a UPS and probably disk-mirroring as well. 
 


Home | FixGateway | AFI/J | SimpleGrid | SBpayroll | SXAzip | InstallScript | DiskUsage/DiskClean | Virtual Desktop Manager | ComBridge | Demos | Purchase