The Application Fix Interface is a FIX Engine with a very
simple Application
Programming Interface (API) that is designed to make adding Fix
Connectivity
to your applications very easy; it is very easy to use and requires the
programmer to implement only a few methods of a FixHandler Java class.
The system includes a sample fix server program
that can read files written in a simple scripting language and
thus
makes testing your application very easy.
For more information about the FIX Protocol see http://www.fixprotocol.org
Contents
System Components
There are 3 system components, a Fix Engine that is started
automatically
when needed, and 2 API jars that must be available on your classpath in
order to access the Fix Engine

The system creates an AFI FixEngine session passing in
the name
of a properties file. This causes the AFI FixEngine process to start up
and read the properties file. using information it finds in the
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.
Getting Started
The following is the basic structure of the afitest
sample application and demonstrates the standard pattern of an AFI
application.
// AfiTest...
import com.octatec.aficlient.*;
import com.octatec.jfixgw.*;
// implement a Fixhandler
class MyFixHandler extends FixHandler {
public void onPreOpen()
{
m_session.enableAutoSetComplete();
//
doing this means you do never need to call
// m_session.setComplete() yourself
}
public void onFixMsg(String type, FixString msg)
{
if( type.equals( FixConst.FIX_MSG_SomeType
) )
{
...process
the message contained in msg...
// E.G. Use...
String
value = msg.GetField(FixConst.FIX_FLD_SomeFieldType);
m_session.setComplete();
//
indicates the message is fully processed
//
maybe you now want to send a message
FixString
myMsg = new
FixString();
myMsg.addField(FixConst.FIX_FLD_SomeFld,
"some value");
...add
more fields
as required...
m_session.sendMsg(FixConst.FIX_MSG_SomeOtherType,
myMsg);
//
in an actual application you must catch
// any exception thrown by this method
}
}
}
/*
** from your application's main
method...
*/
LPCTSTR propFileName = "loopback";
// loopback is a
standard
properties file supplied with the distribution, it
// allows a fix
client
(namely afitest) to connect to the afisrv
application
AfiApp app = new AfiApp(propFileName);
FixHandler handler = new MyFixHandler();
int result = app.startApp(handler);
//
the system will now create a FixSession
// and call your Fixhandler's methods
// NB: there is NO RETURN from this method unil
// the Fix Session has ended - to run a Fix Session
// in a worker thread, see below
If you want your Fix Session to be created in a worker thread, just use
an AfiThreadedApp object as follows
// afisrv
/* from the main thread...
*/
AfiThreadedApp app = new AfiThreadedApp(propFileName);
FixHandler handler = new MyFixHandler();
int result = app.startThread(handler);
//
the fix session is created in a worker thread and your
// FixHandler’s methods are call from the worker thread -
// you can use methods on the AfiThreadedApp object to
// send messages to your worker thread
/* still from the main thread… */
app.sendThreadFixMsg(FixConst.FIX_MSG_SomeOtherType,
myMsg);
// send a Fix Message via the worker thread - you
// Don’t have to use this method to send fix messages
// in a muti-threaded app, if the structure of your
// application permits it, you can send them directly
// from the worker thread using m_session.sendMsg()
// just as you would for a single threaded app
// at some point, close the session
app.closeThread();
FixEngine Properties File
This properties file describes the Fix Engine session, in particular
what IP
address and port number to use, as well as local optional
settings.
You pass the full pathname of a properties file into the constructor of
the AfiApp or AfiThreadedApp. If you
pass
in a file name rather than a full pathname, the file is assumed to
reside
in /Octatec/afi/Home/configs on UNIX-based systems
and
C:\Program Files\Octatec\afi\configs (or under
whatever
directory you chose during the installation) on WIN32 systems.
The properties file contains a list of names
=values
entries, all entries are case sensitive
The following entries define the fix session
host = hostname
The host name to which the AFI Fix Engine will connect. The AFI Fix
Engine 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.
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 checkLogonSubIDs
is set to 0
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 Fix Engine 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 Fix Engine 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.
preferNIO = n
The default value value is 1. Your
should not normally change this – you will only want to change this if
you are implementing your own SocketI
and/or ServerSocketI in order to use a 3rd party SSL
provider,
and their implementation dos not support ‘nio’, in
which case you can set this value to 0.
The following entries 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.
confirmResendSpec = 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 if 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. This translates to a call to onLogon(FixMsg
msg) on the Fix Handler.
forwardLogout = n
If n is 1, logout 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. This translates to a call to onRemoteLogout(FixMsg
msg) on the Fix Handler.
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 Engine
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.
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 you're 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:
If you are entering a path-name on a WIN32 system, you must use \\ (two
backslashes) as the path separator.
clientLogDir = path
This entry defines where the client logs
are placed. Client logs are less important than server logs, but still
useful if you encounter problems. If this entry is not present, if this
entry is not present, the logDir (above) is used. 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.
__debug__ = n
If this value is 1, debug logging mode is switched
on, in this mode all log files are closed after each entry is written,
and opened again as needed, in this way, the log files can always be
viewed
in all environments. NOTE: setting this to 1 will slow
the system down; the default value is 0.
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.
__useLCRP__ = 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.
Client Library
Properties File
fixgw.properties
This properties file must reside in the startup directory of
your application
that is using the aficlient.jar. This allows the client library to find
the AFI Fix Engine. A suitable properties file is supplied with the
installation
and is located in the installation directory – normally you will just
copy
this and not change any of the entries. It contains the following
entries
which are all created during installation.
Home=C:\\Program Files\\Octatec\\AFI_J\\1.00
The installation directory, this will use single forward slashes if
on UNIX, but if on Windows, it will use double backslashes.
Gateway=javaproc
Gateway process type. This entry tells the system to start the AFI
Fix Engine in a new Java Virtual Machine, an alternative value is javathread,
which will cause the Fix Engine to be started in a new thread in the
current
VM. (If you use javathread, you must ensure that afi.jar is on the
classpath.)
Java=C:\\...\\bin\\java
The location of the java command
AFIsrv=C:\\...\\afi.jar
The location of the AFI Fix Engine classes
AFIcli=C:\\...\\JFixGW.jar
The location of additional Fix classes used by the Fix Engine
LogFiles and Journals
AFI'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 fix emgine properties 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.
AFIserver.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 fix
engine properties file paramater cliLogDir. If this
entry is not present, the logDir property is used
instead.
Once the base directory has been decided, a 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...
.../ConfigName/YYYYMMDD_c/FixGatewayClnt.log.
The sequence number of the last successfully processed fix
message (
as defined by the FixSession.setComplete()
method) is saved in .../ConfigName/YYYYMMDD_c/setcomplete.log
If the client application is using the output buffering
mechanism, a
buffer file is created in .../ConfigName/buff.txt,
this
stores unflushed messages, when the buffer is flushed, it is renamed, .../ConfigName/buff.cmt.
FIXML Support
This package supports FIXML; it 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 andFIXML_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 AfiClient Class library
This is an event-driven API and is extremely easy to use, it is the
preferred
method of accessing the AFI Fix Engine. It is built on top of a
low-level
API which you can access, but are encouraged not to use.
Jar Files Needed: aficlient.jar, jfixgw.jar
import com.octatec.aficlient.*;
import com.octatec.jfixgw.* ;
| Abstract Class com.octatec.aficlient.FixHandler |
You must derive your own class from the FixHandler
class in order
to process incoming FIX messages. The only method you really need to
implement
is onFixMsg(FixString s).
public void onPreCreate()
This method is called just before the fix session is created, it allows
you to set low level options if you require them, mostly, you will not
need to implement this method.
public void onOpenComplete()
This method is called just after a session is established with the
remote FIX counterparty.
public void onLogon(FixString fixMsg)
If you have enabled notification of logon messages in the
properties.file,
[the default setting is to disable logon notification] this
method
is called when the remote sends a logon message. You only need to
implement
this method if you are particularly interested in the remote’s logon
message. This method will only be called
if
the forwardLogon property is set to 1.
public void onHeartbeat (FixString fixMsg)
If you have enabled notification of heartbeat messages in the
properties.file,
[the default setting is to enable heartbeat notification] this method
is
called when the remote sends a heartbeat message. You only need to
implement
this method if you are particularly interested in heartbeat messages,
(maybe
you are using them as a timer?)
public void onRejection (FixString fixMsg)
If you have enabled notification of session protocol rejection messages
in the properties.file, [the default setting is to disable
rejection
notification]. This method is called when the remote sends a rejection
message, the default behavioiur is for the fix engine to treat this as
a ‘fatal’ error condition hence you will normally receive an onClose()
notification not an onRejection(). You only need to implement this
method
is you have configured the fix engine to tolerate rejection messages
sent
from the remote side – something you will not normally want to do!
public void onRequestResend(FixString fixMsg)
If you have enabled confirmation of resend requests in the
properties.file,
[the default setting is to automatically fulfil all resend request]
this
method is called to ask permission to resend the specified message, if
you return true the message is resent, if you return false a gap-fill
is
sent instead. You only need to implement this method if you do not want
to automatically resend all requested messages
abstract public void onFixMsg(FixString)
This is the only method you really need to implement,
it is called whenever an application-level fix message arrives. You
should
process the message as needed, a good first step is to put it in the
database.
You can use methods on the FixSession object (m_session) to send
response fix messages if required.
public void onLogout()
DEPRECATED
This method is called when the fix session
closes
normally. You do not need to implement this method, as the
AfiApp.start()
method will automatically return and no more messages will be received
when the session closes. One reason you might want to implement this
method
is to call m_session.reopen(), if the reopen succeeds, the
AfiApp.start()
method will not return (at this juncture).
This method is now deprecated and has been replaced by the
following
2 methods.
public void onLocalLogout()
This is called is a local logout is issued
within
the application.
publi void onRemoteLogout(FixString
msg)
This method is called when the remote logs
out.
The msg parameter will be null unless the forwardLogout
property
is set to 1.
public void onError(int statuscode, boolean
duringOpen)
This method is called when the fix session closes due to an error.
Again, you do not need to implement this method, as the AfiApp.start()
method will automatically return and no more messages will be received
when the session closes. Again, one reason you might want to implement
this method is to call m_session.reopen(), if the reopen succeeds, the
AfiApp.start() method will not return (at this juncture). The duringOpen
parameter
will be true if the error occurred during the attempt to
open
the session.
public void onClosed()
This method is called once the session is completely closed, for either
of the above 2 reasons or if you called m_session.logout().
(Note: It is too late to call m_session.reopen() from
here.)
NB - for every session you will either get an onError() or an onLogout(),
this will cause the open session to close automatically, so you will
then
get an onClosed() event. If you call m_session.logout()
you
will get still get onLogout( ) followed by an onClosed().
If an error occurs during the attempt to open a session you will still
get an onError() event but with duringOpen set to true,
you
will immediately get an onClosed() event to maintain
consistent
ordering and delivery of events.
onThreadMessageSent(String
type,
FixString sfix, int result)
This method will only be called if you used the AfiThreadedApp
object when creating your application: In this case your Fix session
will
be in a worker thread. If you call AfiThreadedApp. sendThreadFixMsg(type,
sfix), this method will be called immediately after the worker
thread
actually sends the message (. If result is not 0, it indicates an
error,
and to preserve consistency in the API, onError() will also be
called
immediately after this method. (Note: type and sfix
could
be null if a serious error occurs.) You don’t need to do
anything
in this method, but it may be important for you to know that the
fix-message
failed to be sent, remember the User Interface thread that used sendThreadFixMsg(type,
sfix) will not know for sure that the message has been successfully
sent to the remote fix engine - the return value of sendThreadFixMsg(type,
sfix) only indicates that the message has been successfully sent on
its way to the worker thread.
(NOTE: the actual sending of the message in response to AfiThreadedApp.
sendThreadFixMsg(type, sfix) is performed automatically by
the
frame-work, you don’t need to worry about that, and then once sent, ths
method is called to inform you of the fact.)
public void onThreadCmd(short
cmd, String
text)
This method will only be called if you used the AfiThreadedApp
object when creating your application. In this case your Fix session
will
be in a worker thread, and the GUI or foreground thread can use AfiThreadedApp.sendThreadCmd()
to send the Fix Worker Thread messages. NB: the text parameter
may
be null.
public void onUserError(Throwable t)
This method is called if an Exception (Throwable) is thrown
from any of the above methods. For example, if you access a null
reference or perform some other programing error in one of the above
methods, unless you catch the exception yourself, this method will be
called.
protected FixSession m_session
This member contains the current FixSession object and is guaranteed
never to be null. Your FixHandler class can call methods on this
object,
typically to send Fix messages or close the session.
| Class com.octatec.aficlient.FixSession |
This class is created automatically and is made available to
your application
via the FixHandler.m_session member.
public void sendMsg(String type, FixString fixMsg) throws
AfiException;
Send a Fix message of the specified type. If you are in a loop sending
fix messages, your application will not be able to receive any incoming
messages until the loop completes.
Note: the correct thing to do when catching an AfiException
thrown by any method is, after recording whatever information you want,
call m_session.handleException(x), and
then
return immediately. Doing this allows the session to tidy up correctly
and will also give rise to you handler’s onError() method
being called.
public void sendMsgEx(String type, FixString fixMsg) throws
AfiException;
Send a Fix message of the specified type. After the messages has been
sent, the system will check for any incoming messages, and if there are
any, they will be dispatched by the system. So your Fixhandler’s
onFixMessage()
or other methods may be called before this method returns. If you are
in
a loop sending fix messages, your application will still receive
incoming
messages while the loop is active.
public void logout()
Send a logout message and close the session.
public boolean reopen()
You can call this method to attempt to re-open a closed session,
typically,
you will call it from your FixHandler’s onClose() method. The
reopen()
call will wait until a connection has been made or until an error
occurs.
public void setComplete()
Use this method to indicate to the system that all messages received
to-date have been fully processed (or saved in your database for latter
processing). If this has not been called, and the application crashes
(or
exits in some other way), any messages received (since the last call to
setComplete ) will be re-requested automatically when the application
is
next started. If you don’t want to have to call setComplete(), you can
use the following method.
public boolean enableAutoSetComplete()
If you are going to call this method, you MUST do so before
the fix session is established, i.e. from you’re your FixHandler’s
onPreCreate()
method. If you call this method, all messages received are
automatically
marked as ‘fully’ processed, and there is no need to call
setComplete().
public void beginBufferedOutput() throws AfiException;
public void abortBufferedOutput() throws AfiException;
public void flushBufferedOutput() throws AfiException;
If you call beginBufferdOutput(), all subsequent calls to sendMsg()
or sendMsgEx()
will merely add the message to a persistent buffer. The messages will
not
be sent until flushBufferdOutput() is called. If abortBufferdOutput()
is called the buffer is discarded. If you use this facility, and the
application
exits before you flush the buffer, the buffer is automatically flushed
the next time your application runs. if you don't want to flush the
buffer
on application start-up, you can call, abortBufferdOutput()
from
your FixHandler’s onPreCreate() method, it is always
safe
to do this, even if there is no buffer to abort, (no exception will be
thrown).
public void
handleException(AfiException
x)
This method should be called whenever you catch an AfiException;
you will almost certainly be in a FixHandler method at
the
time - you should return immediately after calling this method. Calling
handleException()
allows the session to tidy up correctly and will also give rise to you
FixHanler’s onError() method being called.
public FixClient getLowLevelApi();
You can call this method to access the ‘low-level api’, mostly you
should not need to access the low-level api at all, but if you have
special
requirements, you can do this. One reason to use the low-level API is
to send
script file, the afisrv test program uses
this
facility,
| Class com.octatec.aficlient.AfiApp |
You should create one of these objects to run your application
public AfiApp(String propertiesFile);
Pass a properties file that defines the fix session connection
parameters
such as IPAddress and port.
public int start(FixHandler handler);
Once you have created the AfiApp object, call this method to actually
start the fix session, pass in your FixHandler-derriver object to this
method.
| Class com.octatec.aficlient.AfiThreadedApp |
You can create an instance of this object instead of an AfiApp
object
if you want your Fix session to run in a worker thread, perhaps
your
foreground thread will be presenting a GUI to a user. Internally, an AfiApp
instance is created in its own thread. You could do this yourself if
you
wished, but the advantage of using the AfiThreadedApp
object
is that you can use the sendThreadCmd() methods from te GUI
thread
to send ‘internal’ messages to your FixHandler class in the worker
thread,
in which case your FixHandler's onThreadCmd(short cmd,
String
text) method will be called
AfiThreadedApp(String propertiesFile)
Pass a properties file that defines the fix session connection
parameters
such as IPAddress and port.
public boolean startThread(FixHandler handler);
Create a new worker thread to run your fix session. The worker thread
will automatically initiate the fix connection when this method is
called.
This method will not return until a connection has been made
or an error has occurred.
public void startThreadNoWait(FixHandler handler);
Create a new worker thread to run your fix session. The worker thread
will automatically initiate the fix connection when this method is
called.
This method will return immediately.
public boolean closeThread();
This will cause the worker thread to send a logout and close the
session,
if this method is called, any call to FixSession.reopen() will
automatically
fail.
public boolean
sendThreadFixMsg(String
type, FixString sfix)
You can call this method from the User Interface thread to cause the
worker thread to send the specified fix message. Your fix
handlers onThreadMessageSent(type,
sfix, result) will be called after the message has been sent in the
worker thread, if result indicates an error, your fix handlers onError()
will
also be called. Of course, you don’t have to use this method to
send fix messages – if your message can be generated entirely from the
worker thread, e.g. in response to an incoming message, you can just
use
the m_session.sendMsg() method from you fix handler.
Note:
this method will return false if you try and send an empty fix
message.
public boolean
sendThreadCmd(short cmd);
Send an arbitrary notification to the Fix session thread. The cmd
parameter
should be above 100, other than that, it can be any value you choose,
and
you can interpret it in any way you choose in your FixHandler’s onThreadCmd(short
cmd, String text) method, note the text parameter will be null.
public boolean sendThreadCmd(short cmd, String text);
This method allows you to also send an arbitrary notification and a
text string to the worker thread. The cmd parameter should be above
100.
int getLastStatusCode();
You can use this method to ‘poll’ the status of the worker thread,
however, you should probably implement some sort of notification send
from
the worker to the GUI thread if an important event occurs that the GUI
needs to know about, e.g. using something like EventQueue.invokeLater()
The following class is actually found in the low-level API,
but is
used extensively by this class library, and encapsulates a fix message…
| Class com.octatec.jfixgw.FixString |
This class provides the functionality for building fix
messages and
accessing all the fields of the message. The class FixConst
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.
new FixString()
new FixString(String 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(String s)
Set the contents of the fix string to the specified value.
Note:
their is no validation of the string passed in.
String GetMsgType()
Return the type of a fix message. This will be one of the FIX_MSG_*
values defined in FixConst
bool GetField(int tag, OutputString value)
bool GetField(int tag, OutputInt value)
void AddField(int tag, int value)
void AddField(int tag, String value)
void UpdateOrAddField(int tag, int value)
void UpdateOrAddField(int tag, String value)
bool RemoveField(int tag)
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 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.
String GetField(int tag)
A slightly more convenient method, if the field isn’t present, an empty
string is returned.
void SetXmlPayload(String 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.
String GetXmlPayload()
This method is realy the equivalent of calling GetField(FIX_FLD_XmlData)
If
there is no XML payload present, null is returned.
void InitEnum()
boolean EnumNextField(OutputInt name, OutputString 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.
void EmptyString()
Clear the contents of a fix string
String GetString()
Get a reference to the actual string
static Calendar GetCurretTime() // implies gmtOffeset
= Config.V_LOCAL_TIME
static Calendar GetCurretTime(short gmtOffeset)
This is a convenience method to get the current time taking into
account
the GMT offset (virtual timezone) present in the Fix Gateway process.
If
the first version of the method is used, any GMT offset is ignored, and
the current local time is returned.
static String FormatDate(Calendar cal) // implies
format = FixString.FMT_LONG_MS
static String FormatTime(Calendar cal, int format);
Convert the date in cal into a fix format string. If cal
is null, then the current date/time is used. If format=FixString.FMT_LONG_MS,
the output is in the form YYYYMMDD-HH:MM:SS.sss, if format=FixString.FMT_LONG,
the output is in the form YYYYMMDD-HH:MM:SS and if format=FMT_SHORThe
output is in the form YYYYMMDD
static Calendar ParseDate(String s); //
YYYYMMDD or
YYYYMMDD-HH:MM:SS.sss
Return a Calendar object that representd the date/time in the input
fix date/time string.
| Class com.octatec.jfixgw.OutputString |
This is a class with a single public m_value String
member. It
is used to return output string values via parameters from various
methods.
new OutpuString(String value);
new OutpuString();
boolean equals(Object o);
boolean equals(OutputString s);
boolean equals(String s);
These 2 methods compare the characters in the strings and not the
object
references.
| Class com.octatec.jfixgw.OutputInt |
This is a class with a single public m_value int
member. It is
used to return output int values via parameters from various methods.
new OutputInt(int value);
new OutputInt();
| Class com.octatec.jfixgw.OutputShort |
This is a class with a single public m_value short
member. It
is used to return output short values via parameters from various
methods.
new OutputShort(short value);
new OutputShort();
| Class com.octatec.jfixgw.OutputBool |
This is a class with a single public m_value boolean
member.
It is used to return output boolean values via parameters from various
methods.
new OutputBool(boolean value);
new OutputBool();
| Class com.octatec.jfixgw.FixConst |
This class defines all the Fix Message Types and most of the
Fix Fields
(tags) that can be used in the various messages. The FIX_MSG_
constants can be used as arguments to the FixSession.SendMsg()
method, while the FIX_FLD_ constants can be used as
the
‘name’ parameter to various methods in the FixString class.
public static final String FIX_Delimiter =
"\001";
public static final String
FIX_MSG_Heartbeat
="0";
public static final String
FIX_MSG_Test_Request
="1";
public static final String
FIX_MSG_Resend_Request
="2";
public static final String
FIX_MSG_Reject
="3";
public static final String
FIX_MSG_Sequence_Reset
="4";
public static final String
FIX_MSG_Logout
="5";
public static final String
FIX_MSG_Indication_of_Interest
="6";
public static final String
FIX_MSG_Advertisement
="7";
public static final String
FIX_MSG_Execution_Report
="8";
public static final String
FIX_MSG_Order_Cancel_Reject
="9";
public static final String
FIX_MSG_Logon
="A";
public static final String
FIX_MSG_News
="B";
public static final String
FIX_MSG_Email
="C";
public static final String
FIX_MSG_Order_Single
="D";
public static final String
FIX_MSG_Order_List
="E";
public static final String
FIX_MSG_Order_Cancel_Request
="F";
public static final String
FIX_MSG_Order_Cancel_Replace_Request="G";
public static final String
FIX_MSG_Order_Status_Request
="H";
public static final String
FIX_MSG_Allocation
="J";
public static final String
FIX_MSG_List_Cancel_Request
="K";
public static final String
FIX_MSG_List_Execute
="L";
public static final String
FIX_MSG_List_Status_Request
="M";
public static final String
FIX_MSG_List_Status
="N";
public static final String
FIX_MSG_Allocation_ACK
="P";
public static final String
FIX_MSG_Dont_Know_Trade
="Q";
public static final String
FIX_MSG_Quote_Request
="R";
public static final String
FIX_MSG_Quote
="S";
public static final String
FIX_MSG_Settlement_Instructions
="T";
public static final String
FIX_MSG_Market_Data_Request
="V";
public static final String
FIX_MSG_Market_Data_Full_Refresh
="W";
public static final String
FIX_MSG_Market_Data_Incremental_Refresh
="X";
public static final String
FIX_MSG_Market_Data_Request_Reject
="Y";
public static final String
FIX_MSG_Quote_Cancel
="Z";
public static final String
FIX_MSG_Quote_Status_Request
="a";
public static final String
FIX_MSG_Quote_Acknowledgement
="b";
public static final String
FIX_MSG_Security_Definition_Request
="c";
public static final String
FIX_MSG_Security_Definition
="d";
public static final String
FIX_MSG_Security_Status_Request
="e";
public static final String
FIX_MSG_Security_Status
="f";
public static final String
FIX_MSG_Trading_Session_Status_Request
="g";
public static final String
FIX_MSG_Trading_Session_Status
="h";
public static final String
FIX_MSG_Mass_Quote
="i";
public static final String
FIX_MSG_Business_Message_Reject
="j";
public static final String
FIX_MSG_Bid_Request
="k";
public static final String
FIX_MSG_Bid_Response
="l";
public static final String
FIX_MSG_List_Strike_Price
="m";
public static final String FIX_MSG_XML = "XML";
public static final String FIX_MSG_FIXML =
"FIXML";
// you can use either of
these
or any other localy agreed
// message type to
indicate
the FIX MESSAGE actually
// contains FIXML or aome
other
XML payload, these are
// just included as a
sugestion
public static final int
FIX_FLD_Account
=1;
public static final int
FIX_FLD_AdvId
=2;
public static final int
FIX_FLD_AdvRefID
=3;
public static final int
FIX_FLD_AdvSide
=4;
public static final int
FIX_FLD_AdvTransType
=5;
public static final int
FIX_FLD_AvgPx
=6;
public static final int
FIX_FLD_BeginSeqNo
=7;
public static final int FIX_FLD_BeginString
=8;
public static final int
FIX_FLD_BodyLength
=9;
public static final int
FIX_FLD_CheckSum
=10;
public static final int
FIX_FLD_ClOrdID
=11;
public static final int
FIX_FLD_Commission
=12;
public static final int
FIX_FLD_CommType
=13;
public static final int
FIX_FLD_CumQty
=14;
public static final int
FIX_FLD_Currency
=15;
public static final int
FIX_FLD_EndSeqNo
=16;
public static final int
FIX_FLD_ExecID
=17;
public static final int
FIX_FLD_ExecInst
=18;
public static final int
FIX_FLD_ExecRefID
=19;
public static final int
FIX_FLD_ExecTransType
=20;
public static final int
FIX_FLD_HandlInst
=21;
public static final int
FIX_FLD_IDSource
=22;
public static final int
FIX_FLD_IOIid
=23;
public static final int
FIX_FLD_IOIOthSvc
=24;
public static final int
FIX_FLD_IOIQltyInd
=25;
public static final int
FIX_FLD_IOIRefID
=26;
public static final int
FIX_FLD_IOIShares
=27;
public static final int
FIX_FLD_IOITransType
=28;
public static final int
FIX_FLD_LastCapacity
=29;
public static final int
FIX_FLD_LastMkt
=30;
public static final int
FIX_FLD_LastPx
=31;
public static final int
FIX_FLD_LastShares
=32;
public static final int FIX_FLD_LinesOfText
=33;
public static final int
FIX_FLD_MsgSeqNum
=34;
public static final int
FIX_FLD_MsgType
=35;
public static final int
FIX_FLD_NewSeqNo
=36;
public static final int
FIX_FLD_OrderID
=37;
public static final int
FIX_FLD_OrderQty
=38;
public static final int
FIX_FLD_OrdStatus
=39;
public static final int
FIX_FLD_OrdType
=40;
public static final int FIX_FLD_OrigClOrdID
=41;
public static final int
FIX_FLD_OrigTime
=42;
public static final int FIX_FLD_PossDupFlag
=43;
public static final int
FIX_FLD_Price
=44;
public static final int
FIX_FLD_RefSeqNum
=45;
public static final int
FIX_FLD_RelatdSym
=46;
public static final int
FIX_FLD_Rule80A
=47;
public static final int
FIX_FLD_SecurityID
=48;
public static final int
FIX_FLD_SenderCompID
=49;
public static final int FIX_FLD_SenderSubID
=50;
public static final int FIX_FLD_SendingDate
=51;
public static final int FIX_FLD_SendingTime
=52;
public static final int
FIX_FLD_Shares
=53;
public static final int
FIX_FLD_Side
=54;
public static final int
FIX_FLD_Symbol
=55;
public static final int
FIX_FLD_TargetCompID
=56;
public static final int FIX_FLD_TargetSubID
=57;
public static final int
FIX_FLD_Text
=58;
public static final int FIX_FLD_TimeInForce
=59;
public static final int
FIX_FLD_TransactTime
=60;
public static final int
FIX_FLD_Urgency
=61;
public static final int
FIX_FLD_ValidUntilTime
=62;
public static final int FIX_FLD_SettlmntTyp
=63;
public static final int FIX_FLD_FutSettDate
=64;
public static final int
FIX_FLD_SymbolSfx
=65;
public static final int
FIX_FLD_ListID
=66;
public static final int
FIX_FLD_ListSeqNo
=67;
public static final int FIX_FLD_TotNoOrders
=68;
public static final int
FIX_FLD_ListNoOrds
=68;
public static final int
FIX_FLD_ListExecInst
=69;
public static final int
FIX_FLD_AllocID
=70;
public static final int
FIX_FLD_AllocTransType
=71;
public static final int
FIX_FLD_RefAllocID
=72;
public static final int
FIX_FLD_NoOrders
=73;
public static final int FIX_FLD_AvgPrxPrecision
=74;
public static final int
FIX_FLD_TradeDate
=75;
public static final int
FIX_FLD_ExecBroker
=76;
public static final int FIX_FLD_OpenClose
=77;
public static final int
FIX_FLD_NoAllocs
=78;
public static final int
FIX_FLD_AllocAccount
=79;
public static final int FIX_FLD_AllocShares
=80;
public static final int FIX_FLD_ProcessCode
=81;
public static final int
FIX_FLD_NoRpts
=82;
public static final int
FIX_FLD_RptSeq
=83;
public static final int
FIX_FLD_CxlQty
=84;
public static final int
FIX_FLD_NoDlvyInst
=85;
public static final int
FIX_FLD_DlvyInst
=86;
public static final int FIX_FLD_AllocStatus
=87;
public static final int
FIX_FLD_AllocRejCode
=88;
public static final int
FIX_FLD_Signature
=89;
public static final int
FIX_FLD_SecureDataLen
=90;
public static final int
FIX_FLD_SecureData
=91;
public static final int
FIX_FLD_BrokerOfCredit
=92;
public static final int FIX_FLD_SignatureLength
=93;
public static final int
FIX_FLD_EmailType
=94;
public static final int
FIX_FLD_RawDataLength
=95;
public static final int
FIX_FLD_RawData
=96;
public static final int FIX_FLD_PossResend
=97;
public static final int
FIX_FLD_EncryptMethod
=98;
public static final int
FIX_FLD_StopPx
=99;
public static final int
FIX_FLD_ExDestination
=100;
public static final int
FIX_FLD___Not_Defined
=101;
public static final int
FIX_FLD_CxlRejReason
=102;
public static final int
FIX_FLD_OrdRejReason
=103;
public static final int
FIX_FLD_IOIQualifier
=104;
public static final int
FIX_FLD_WaveNo
=105;
public static final int
FIX_FLD_Issuer
=106;
public static final int
FIX_FLD_SecurityDesc
=107;
public static final int
FIX_FLD_HeartBtInt
=108;
public static final int
FIX_FLD_ClientID
=109;
public static final int
FIX_FLD_MinQty
=110;
public static final int
FIX_FLD_MaxFloor
=111;
public static final int
FIX_FLD_TestReqID
=112;
public static final int
FIX_FLD_ReportToExch
=113;
public static final int
FIX_FLD_LocateReqd
=114;
public static final int FIX_FLD_OnBehalfOfCompID
=115;
public static final int FIX_FLD_OnBehalfOfSubID
=116;
public static final int
FIX_FLD_QuoteID
=117;
public static final int
FIX_FLD_NetMoney
=118;
public static final int
FIX_FLD_SettlCurrAmt
=119;
public static final int
FIX_FLD_SettlCurrency
=120;
public static final int
FIX_FLD_ForexReq
=121;
public static final int FIX_FLD_OrigSendingTime
=122;
public static final int FIX_FLD_GapFillFlag
=123;
public static final int
FIX_FLD_NoExecs
=124;
public static final int
FIX_FLD_CxlType
=125;
public static final int
FIX_FLD_ExpireTime
=126;
public static final int
FIX_FLD_DKReason
=127;
public static final int FIX_FLD_DeliverToCompID
=128;
public static final int
FIX_FLD_DeliverToSubID
=129;
public static final int
FIX_FLD_IOINaturalFlag
=130;
public static final int
FIX_FLD_QuoteReqID
=131;
public static final int
FIX_FLD_BidPx
=132;
public static final int
FIX_FLD_OfferPx
=133;
public static final int
FIX_FLD_BidSize
=134;
public static final int
FIX_FLD_OfferSize
=135;
public static final int
FIX_FLD_NoMiscFees
=136;
public static final int
FIX_FLD_MiscFeeAmt
=137;
public static final int FIX_FLD_MiscFeeCurr
=138;
public static final int FIX_FLD_MiscFeeType
=139;
public static final int FIX_FLD_PrevClosePx
=140;
public static final int FIX_FLD_ResetSeqNumFlag
=141;
public static final int FIX_FLD_SenderLocationID
=142;
public static final int FIX_FLD_TargetLocationID
=143;
public static final int
FIX_FLD_OnBehalfOfLocationID
=144;
public static final int
FIX_FLD_DeliverToLocationID
=145;
public static final int
FIX_FLD_NoRelatedSym
=146;
public static final int
FIX_FLD_Subject
=147;
public static final int
FIX_FLD_Headline
=148;
public static final int
FIX_FLD_URLLink
=149;
public static final int
FIX_FLD_ExecType
=150;
public static final int
FIX_FLD_LeavesQty
=151;
public static final int
FIX_FLD_CashOrderQty
=152;
public static final int
FIX_FLD_AllocAvgPx
=153;
public static final int
FIX_FLD_AllocNetMoney
=154;
public static final int
FIX_FLD_SettlCurrFxRate
=155;
public static final int
FIX_FLD_SettlCurrFxRateCalc
=156;
public static final int
FIX_FLD_NumDaysInterest
=157;
public static final int
FIX_FLD_AccruedInterestRate
=158;
public static final int
FIX_FLD_AccruedInterestAmt
=159;
public static final int
FIX_FLD_SettlInstMode
=160;
public static final int
FIX_FLD_AllocText
=161;
public static final int
FIX_FLD_SettlInstID
=162;
public static final int
FIX_FLD_SettlInstTransType
=163;
public static final int
FIX_FLD_EmailThreadID
=164;
public static final int
FIX_FLD_SettlInstSource
=165;
public static final int
FIX_FLD_SettlLocation
=166;
public static final int
FIX_FLD_SecurityType
=167;
public static final int
FIX_FLD_EffectiveTime
=168;
public static final int
FIX_FLD_StandInstDbType
=169;
public static final int
FIX_FLD_StandInstDbName
=170;
public static final int
FIX_FLD_StandInstDbID
=171;
public static final int
FIX_FLD_SettlDeliveryType
=172;
public static final int
FIX_FLD_SettlDepositoryCode
=173;
public static final int
FIX_FLD_SettlBrkrCode
=174;
public static final int
FIX_FLD_SettlInstCode
=175;
public static final int
FIX_FLD_SecuritySettlAgentName
=176;
public static final int
FIX_FLD_SecuritySettlAgentCode
=177;
public static final int
FIX_FLD_SecuritySettlAgentAcctNum
=178;
public static final int
FIX_FLD_SecuritySettlAgentAcctName
=179;
public static final int
FIX_FLD_SecuritySettlAgentContactName
=180;
public static final int
FIX_FLD_SecuritySettlAgentContactPhone
=181;
public static final int
FIX_FLD_CashSettlAgentName
=182;
public static final int
FIX_FLD_CashSettlAgentCode
=183;
public static final int
FIX_FLD_CashSettlAgentAcctNum
=184;
public static final int
FIX_FLD_CashSettlAgentAcctName
=185;
public static final int
FIX_FLD_CashSettlAgentContactName
=186;
public static final int
FIX_FLD_CashSettlAgentContactPhone
=187;
public static final int
FIX_FLD_BidSpotRate
=188;
public static final int
FIX_FLD_BidForwardPoints
=189;
public static final int
FIX_FLD_OfferSpotRate
=190;
public static final int
FIX_FLD_OfferForwardPoints
=191;
public static final int
FIX_FLD_OrderQty2
=192;
public static final int
FIX_FLD_FutSettDate2
=193;
public static final int
FIX_FLD_LastSpotRate
=194;
public static final int
FIX_FLD_LastForwardPoints
=195;
public static final int
FIX_FLD_AllocLinkID
=196;
public static final int
FIX_FLD_AllocLinkType
=197;
public static final int
FIX_FLD_SecondaryOrderID
=198;
public static final int
FIX_FLD_NoIOIQualifiers
=199;
public static final int
FIX_FLD_MaturityMonthYear
=200;
public static final int
FIX_FLD_PutOrCall
=201;
public static final int
FIX_FLD_StrikePrice
=202;
public static final int
FIX_FLD_CoveredOrUncovered
=203;
public static final int
FIX_FLD_CustomerOrFirm
=204;
public static final int
FIX_FLD_MaturityDay
=205;
public static final int
FIX_FLD_OptAttribute
=206;
public static final int
FIX_FLD_SecurityExchange
=207;
public static final int
FIX_FLD_NotifyBrokerOfCredit
=208;
public static final int
FIX_FLD_AllocHandlInst
=209;
public static final int
FIX_FLD_MaxShow
=210;
public static final int
FIX_FLD_PegDifference
=211;
public static final int
FIX_FLD_XmlDataLen
=212;
public static final int
FIX_FLD_XmlData
=213;
public static final int
FIX_FLD_SettlInstRefID
=214;
public static final int
FIX_FLD_NoRoutingIDs
=215;
public static final int
FIX_FLD_RoutingType
=216;
public static final int
FIX_FLD_RoutingID
=217;
public static final int
FIX_FLD_SpreadToBenchmark
=218;
public static final int
FIX_FLD_Benchmark
=219;
public static final int
FIX_FLD_CouponRate
=223;
public static final int
FIX_FLD_ContractMultiplier
=231;
public static final int
FIX_FLD_MDReqID
=262;
public static final int
FIX_FLD_SubscriptionRequestType=263;
public static final int
FIX_FLD_MarketDepth
=264;
public static final int
FIX_FLD_MDUpdateType
=265;
public static final int
FIX_FLD_AggregatedBook
=266;
public static final int
FIX_FLD_NoMDEntryTypes
=267;
public static final int
FIX_FLD_NoMDEntries
=268;
public static final int FIX_FLD_MDEntryType
=269;
public static final int
FIX_FLD_MDEntryPx
=270;
public static final int
FIX_FLD_MDEntrySize
=271;
public static final int
FIX_FLD_MDEntryDate
=272;
public static final int
FIX_FLD_MDEntryTime
=273;
public static final int
FIX_FLD_TickDirection
=274;
public static final int
FIX_FLD_MDMkt
=275;
public static final int
FIX_FLD_QuoteCondition
=276;
public static final int
FIX_FLD_TradeCondition
=277;
public static final int
FIX_FLD_MDEntryID
=278;
public static final int
FIX_FLD_MDUpdateAction
=279;
public static final int
FIX_FLD_MDEntryRefID
=280;
public static final int
FIX_FLD_MDReqRejReason
=281;
public static final int
FIX_FLD_MDEntryOriginator
=282;
public static final int
FIX_FLD_LocationID
=283;
public static final int
FIX_FLD_DeskID
=284;
public static final int
FIX_FLD_DeleteReason
=285;
public static final int
FIX_FLD_OpenCloseSettleFlag
=286;
public static final int
FIX_FLD_SellerDays
=287;
public static final int
FIX_FLD_MDEntryBuyer
=288;
public static final int
FIX_FLD_MDEntrySeller
=289;
public static final int
FIX_FLD_MDEntryPositionNo
=290;
public static final int FIX_FLD_FinancialStatus
=291;
public static final int
FIX_FLD_CorporateAction
=292;
public static final int
FIX_FLD_DefBidSize
=293;
public static final int
FIX_FLD_DefOfferSize
=294;
public static final int
FIX_FLD_NoQuoteEntries
=295;
public static final int
FIX_FLD_NoQuoteSets
=296;
public static final int
FIX_FLD_QuoteAckStatus
=297;
public static final int
FIX_FLD_QuoteCancelType
=298;
public static final int
FIX_FLD_QuoteEntryID
=299;
public static final int
FIX_FLD_QuoteRejectReason
=300;
public static final int
FIX_FLD_QuoteResponseLevel
=301;
public static final int
FIX_FLD_QuoteSetID
=302;
public static final int
FIX_FLD_QuoteRequestType
=303;
public static final int
FIX_FLD_TotQuoteEntries
=304;
public static final int
FIX_FLD_UnderlyingIDSource
=305;
public static final int
FIX_FLD_UnderlyingIssuer
=306;
public static final int
FIX_FLD_UnderlyingSecurityDesc
=307;
public static final int
FIX_FLD_UnderlyingSecurityExchange
=308;
public static final int
FIX_FLD_UnderlyingSecurityID
=309;
public static final int
FIX_FLD_UnderlyingSecurityType
=310;
public static final int
FIX_FLD_UnderlyingSymbol
=311;
public static final int
FIX_FLD_UnderlyingSymbolSfx
=312;
public static final int
FIX_FLD_UnderlyingMaturityMonthYear=313;
public static final int
FIX_FLD_UnderlyingMaturityDay
=314;
public static final int
FIX_FLD_UnderlyingPutOrCall
=315;
public static final int
FIX_FLD_UnderlyingStrikePrice
=316;
public static final int
FIX_FLD_UnderlyingOptAttribute
=317;
public static final int
FIX_FLD_Underlying
=318;
public static final int
FIX_FLD_RatioQty
=319;
public static final int
FIX_FLD_SecurityReqID
=320;
public static final int
FIX_FLD_SecurityRequestType
=321;
public static final int
FIX_FLD_SecurityResponseID
=322;
public static final int
FIX_FLD_SecurityResponseType
=323;
public static final int
FIX_FLD_SecurityStatusReqID
=324;
public static final int
FIX_FLD_UnsolicitedIndicator
=325;
public static final int
FIX_FLD_SecurityTradingStatus
=326;
public static final int
FIX_FLD_HaltReason
=327;
public static final int
FIX_FLD_InViewOfCommon
=328;
public static final int
FIX_FLD_DueToRelated
=329;
public static final int
FIX_FLD_BuyVolume
=330;
public static final int
FIX_FLD_SellVolume
=331;
public static final int
FIX_FLD_HighPx
=332;
public static final int
FIX_FLD_LowPx
=333;
public static final int
FIX_FLD_Adjustment
=334;
public static final int
FIX_FLD_TradSesReqID
=335;
public static final int
FIX_FLD_TradingSessionID
=336;
public static final int
FIX_FLD_ContraTrader
=337;
public static final int
FIX_FLD_TradSesMethod
=338;
public static final int
FIX_FLD_TradSesMode
=339;
public static final int
FIX_FLD_TradSesStatus
=340;
public static final int
FIX_FLD_TradSesStartTime
=341;
public static final int
FIX_FLD_TradSesOpenTime
=342;
public static final int
FIX_FLD_TradSesPreCloseTime
=343;
public static final int
FIX_FLD_TradSesCloseTime
=344;
public static final int
FIX_FLD_TradSesEndTime
=345;
public static final int
FIX_FLD_NumberOfOrders
=346;
public static final int
FIX_FLD_MessageEncoding
=347;
public static final int
FIX_FLD_EncodedIssuerLen
=348;
public static final int
FIX_FLD_EncodedIssuer
=349;
public static final int
FIX_FLD_EncodedSecurityDescLen
=350;
public static final int
FIX_FLD_EncodedSecurityDesc
=351;
public static final int
FIX_FLD_EncodedListExecInstLen
=352;
public static final int
FIX_FLD_EncodedListExecInst
=353;
public static final int
FIX_FLD_EncodedTextLen
=354;
public static final int
FIX_FLD_EncodedText
=355;
public static final int
FIX_FLD_EncodedSubjectLen
=356;
public static final int
FIX_FLD_EncodedSubject
=357;
public static final int
FIX_FLD_EncodedHeadlineLen
=358;
public static final int
FIX_FLD_EncodedHeadline
=359;
public static final int
FIX_FLD_EncodedAllocTextLen
=360;
public static final int
FIX_FLD_EncodedAllocText
=361;
public static final int
FIX_FLD_EncodedUnderlyingIssuerLen
=362;
public static final int
FIX_FLD_EncodedUnderlyingIssuer
=363;
public static final int
FIX_FLD_EncodedUnderlyingSecurityDescLen
=364;
public static final int
FIX_FLD_EncodedUnderlyingSecurityDesc
=365;
public static final int
FIX_FLD_AllocPrice
=366;
public static final int
FIX_FLD_QuoteSetValidUntilTime
=367;
public static final int
FIX_FLD_QuoteEntryRejectReason
=368;
public static final int
FIX_FLD_LastMsgSeqNumProcessed
=369;
public static final int
FIX_FLD_OnBehalfOfSendingTime
=370;
public static final int
FIX_FLD_RefTagID
=371;
public static final int
FIX_FLD_RefMsgType
=372;
public static final int
FIX_FLD_SessionRejectReason
=373;
public static final int
FIX_FLD_BidRequestTransType
=374;
public static final int
FIX_FLD_ContraBroker
=375;
public static final int
FIX_FLD_ComplianceID
=376;
public static final int
FIX_FLD_SolicitedFlag
=377;
public static final int
FIX_FLD_ExecRestatementReason
=378;
public static final int
FIX_FLD_BusinessRejectRefID
=379;
public static final int
FIX_FLD_BusinessRejectReason
=380;
public static final int
FIX_FLD_GrossTradeAmt
=381;
public static final int
FIX_FLD_NoContraBrokers
=382;
public static final int
FIX_FLD_MaxMessageSize
=383;
public static final int
FIX_FLD_NoMsgTypes
=384;
public static final int
FIX_FLD_MsgDirection
=385;
public static final int
FIX_FLD_NoTradingSessions
=386;
public static final int
FIX_FLD_TotalVolumeTraded
=387;
public static final int
FIX_FLD_DiscretionInst
=388;
public static final int
FIX_FLD_DiscretionOffset
=389;
public static final int
FIX_FLD_BidID
=390;
public static final int
FIX_FLD_ClientBidID
=391;
public static final int
FIX_FLD_ListName
=392;
public static final int
FIX_FLD_TotalNumSecurities
=393;
public static final int
FIX_FLD_BidType
=394;
public static final int
FIX_FLD_NumTickets
=395;
public static final int
FIX_FLD_SideValue1
=396;
public static final int
FIX_FLD_SideValue2
=397;
public static final int
FIX_FLD_NoBidDescriptors
=398;
public static final int
FIX_FLD_BidDescriptorType
=399;
public static final int
FIX_FLD_BidDescriptor
=400;
public static final int
FIX_FLD_SideValueInd
=401;
public static final int
FIX_FLD_LiquidityPctLow
=402;
public static final int
FIX_FLD_LiquidityPctHigh
=403;
public static final int
FIX_FLD_LiquidityValue
=404;
public static final int
FIX_FLD_EFPTrackingError
=405;
public static final int
FIX_FLD_FairValue
=406;
public static final int
FIX_FLD_OutsideIndexPct
=407;
public static final int
FIX_FLD_ValueOfFutures
=408;
public static final int
FIX_FLD_LiquidityIndType
=409;
public static final int
FIX_FLD_WtAverageLiquidity
=410;
public static final int
FIX_FLD_ExchangeForPhysical
=411;
public static final int
FIX_FLD_OutMainCntryUIndex
=412;
public static final int
FIX_FLD_CrossPercent
=413;
public static final int
FIX_FLD_ProgRptReqs
=414;
public static final int
FIX_FLD_ProgPeriodInterval
=415;
public static final int
FIX_FLD_IncTaxInd
=416;
public static final int
FIX_FLD_NumBidders
=417;
public static final int
FIX_FLD_TradeType
=418;
public static final int
FIX_FLD_BasisPxType
=419;
public static final int
FIX_FLD_NoBidComponents
=420;
public static final int
FIX_FLD_Country
=421;
public static final int
FIX_FLD_TotNoStrikes
=422;
public static final int
FIX_FLD_PriceType
=423;
public static final int
FIX_FLD_DayOrderQty
=424;
public static final int
FIX_FLD_DayCumQty
=425;
public static final int
FIX_FLD_DayAvgPx
=426;
public static final int
FIX_FLD_GTBookingInst
=427;
public static final int
FIX_FLD_NoStrikes
=428;
public static final int
FIX_FLD_ListStatusType
=429;
public static final int
FIX_FLD_NetGrossInd
=430;
public static final int
FIX_FLD_ListOrderStatus
=431;
public static final int
FIX_FLD_ExpireDate
=432;
public static final int
FIX_FLD_ListExecInstType
=433;
public static final int
FIX_FLD_CxlRejResponseTo
=434;
public static final int
FIX_FLD_UnderlyingCouponRate
=435;
public static final int
FIX_FLD_UnderlyingContractMultiplier=436;
public static final int
FIX_FLD_ContraTradeQty
=437;
public static final int
FIX_FLD_ContraTradeTime
=438;
public static final int
FIX_FLD_ClearingFirm
=439;
public static final int
FIX_FLD_ClearingAccount
=440;
public static final int
FIX_FLD_LiquidityNumSecurities
=441;
public static final int
FIX_FLD_MultiLegReportingType
=442;
Resend Confirmation
With this facility you can specify a list of messge-types in the fix
engine
properties 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 properties
file
confrimResend B
If a B (News) message needs to be re-sent because
the remote
Fix Engine has requested a resend, Your FixHandler’s onRequestResend(FixString
fixMsg) will be called with the message as a parameter; if you
return
true, the message will be resent, if you return false the message will
be replaced with a gap-fill.
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.
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 afitest and afisrv
utilities can be used to test the system's terror
handling
capability.
Connection Errors While Sending Messages
When the FixSession.sendMsg() 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, FixSession.sendMsg()
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: sendMsg 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 FixSession.sendMsg()
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. FixSession.sendMsg() 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 FixSession.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 Fix Engine 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 AFI Fix Engine 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 FixSession.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 afisrv 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 afitest sample
program,
which simply connects to the afisrv on the local machine. You can then
send heartbeats and other fix messages to afitest from the
afisrv
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 afisrv as a dummy, replacing the actual Fix Engine you
will want your application to connect to.
afisrv 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 afitest 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...
afitest 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 afisrv, 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 afitest
program
- it will give you a small menu, choose option 0. In order to
give afitest
some work to do, return to afisrv 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 afitest,
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 afitest validates the file it
creates, and afisrv 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 afitest 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 afitest / afisrv Test Session
This session will involve connecting the afitest
program to the afisrv program via
a
fix session. They will exchange messages and verify that all messages
have
arrived successfully. afitest will
use the loopback
configuration
file, and afisrv will use the testsrvr
configuration file. Both thes config files are supplied with the
distribution,
in fact afisrvr can load any
configuration
file you choose, but afitest can
only
access the loopback
config.
(afitest)...(FixGatwWay,cfg:loopback)
-----//----- (FixGatwEay,cfg:testsrvr)...(afisrv)
Just follow the simple instructions bellow to run a test fix
session...
- Start afisrv and afitest. These
programs are both windows console applications.
- Select option (o) from
afisrv
and then just hit return at the next prompt.
- Select option(0) from
afitest
and enter Y at the next prompt
- In afitest, selectoption
(s) and enter 5 at the
next
prompt
- You should see messages scrolling in the afitest
window. After a few seconds you should see the message ORDER
FILES VALIDATED AND SAVED in the afitest
window, and [TEST LOG VERIFIED OK]in
the afisrv window
- Enter x in the afisrv
window to close the session.
- afitest will detect
that afisrv
has closed, enter a q to close afitest.
Using afitest and afisrv
To
Test The
System's Error Recovery Capabilities
Note: in following discussion afitest
is used to refer to the afitest client application and the
associated fixgw
process, and similarly afisrv
refers
to the afisrv 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 afitest and afisrv
to determine if all messages have arrived successfully.
Testing Recovery from failure in the User Application
(afitest)...(FixGatwWay,cfg:loopback)
----//----- (FixGatwEay,cfg:testsrvr)...(afisrv)
this side will
crash
this side will wait for a reconnect
Firstly start afisrv and open
a session. Start afitest in crash-simulation
testing mode (menu option 2). Use afisrv
to
run the 5LISTS.TXT script file (option S and option 5),
afitest
will crash half way through, it will either exit directly or give you
the
option to quit or reconnect, you should quit.
The afisrv program will wait for
a
reconnection, and then continue sending from where it left off, hence
you
should restart afitest 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 afisrv
and afitest should print out a
messages
indicating that validation has completed successfully.
Restart afitest in normal
mode,
it will re-received the orders already sent (but not processed) , and
then
continue to receive the rest of the messages. afitest
and afisrv 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.
(afitest)...(FixGatwWay,cfg:loopback)
----//----- (FixGatwEay,cfg:testsrvr)...(afisrv)
this
side dies
Firstly start afisrv and open
a session. Start afitest in
local gateway crash-simulation testing mode(menu option 3). Again,
use afisrv to run the 5LISTS.TXT
script file (option S and option 5). The gateway
used by afitest will die and afitest
will detect this it will either exit directly or give you the option to
quit
or reconnect, you should quit, The remote
gateway server(afisrv) will detect that its
fix client(afitest) has died, it will close down and
inform
the user application(afisrv), afisrv will
then wait for a reconnection. When afitest 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 afisrv
and afitest 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
- user application crash
- computer failure due to power loss or hardware fault
- 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, or occurs before the log-file name has been initialised,
there are 2 additional log-files that can help. Both files are located
in the start-up directory of your application.
.fgwtemp.log – This logfile is created by the
client
library
.AFItmp.log – This logfile is created by
the
actual Fix Engine
NOTE: You cannot copy AFI/J to another computer and expect it
to run,
it must be correctly installed and licensed. Further, if you rename you
computer, you will have to reinstall AFI/J, 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...
FixSession.beginBufferedOutput();
FixSession.abortOutputBuffer();
FixSession.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. 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 FixSession.setComplete()
When 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.
Note: you will have to use methods on the low
level
API to achieve this.
Now, 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 AFI Fix Engine 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.
Appendix III:
The low level
API
This API can be used on its own or accessed
via the
high-level API. In general, you should not use this API.
This API is encapsulated by the High Level API.
You should always use the High Level API, and use the
FixSession.getLowLevelApi()
to access the underlying FixClient object if you need low level API
methods. It
is extremely unlikely you will need to access this API, so if you
think
you need it, take another look at the high level API, the functionality
you need is probably there!
Note: Ths API is compatible with the
FixGateway
API used in in Octatec's C++ based FIX Engine.
Jar File: jfixgw.jar
import com.octatec.jfixgw.*
| Class com.octatec.jfixgw.FixClient |
new FixClient()
Create and initialize a FixClient object.
The
object is not connected to the fix gateway until Open() is
called.
Destruct()
You can call this method to close the
connection
and release any resources. If you just call Close(), some
resources
are held in case you want to Open() the connection again. If
you
don't call Destruct(), the resources will be released when
the
garbage collector runs and calls the objects finalize()
method.
int Open(LPCTSTR configFile)
int Open(LPCTSTR configFile,
CntrlInterface
ctrl)
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. 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). Use the ctrl parameter if you want to send
control
mesages to a worker thread in a Fix Message loop.
The same application can have many
FixClient objects,
and open multiple fix sessions if it wishes, however, it should only
Open
a configFile 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.
int 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.
boolean IsConnected()
This method returns true if the local Fix
Gateway
is connected to a remote Fix Engine.
int 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.
int SendFixMsg(String 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 defined in
the
in FixConst class, or any other string value
denoting
a locally agreed fix message type.
int
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.
int ResetLogLevel(int n, boolean
gatewayOnly)
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.
int ResetForwardHtBtFlag(boolean
flag)
This method can be used once a connection
is
established to reset the heartbeat forwarding strategy, if flag
istrue,
heartbeat messages are passd to the client app.
int
ResetRejectionTolerationLevel(ingt
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.
int
ResetForwardRejectionFlag(boolean flag)
This method can be used once a connection
is
established to reset the rejection forwarding strategy, if flag
istrue,
fix-protocol rejection messages are passd to the client app.
int
ResetManualSessionSwitchFlag(boolean
flag)
This method can be used once a connection
is
established to reset the ManulSessionReset flag (see the FixGateway
documentation for more details about this flag.) If flag
is
true, 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).
int BeginBufferedOutput()
After this method has been called, SendFixMsg()
merely records the message in a local persistent buffer.
int AbortOutputBuffer()
This method closes and discards the local
buffer.
int 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.
int 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.
boolean 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.
boolean SetComplete(int
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() //
implies mode==true
void DisableAutoRecovery(boolean
mode)
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.
int Close() // implies grace=15
int Close(int grace)
Close the fix session. If you do not close
an
open session, it will be closed eventually by the finalize method, but
because you don't know when this will run, you should
always Close sessions explicitly. 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. The Close method keeps some
resources
allocated in case you want to Open the connection again. If you don't
want
to open the session again, you can call Destruct() after
Close(),
or just call Destruct() without calling Close().
int 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.
int
RunScript(final
String path, OutputInt numberOfMessages) // implies reconnect=0
maxretries=0
int RunScript(final String path,
OutputInt
numberOfMessages, int reconnect, int maxretries)
Run a script, the number of messages
processed
is returned in numberOfMessages. See the FixGateway
documentationfor the format of a script file. If reconnect
is specified,the fix session is automatically reconnected after waitingreconnect
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)
int OverrideTargetSubId(final
String newId)
// implies permanent=true
int OverrideTargetSubId(final String
newId,
boolean permanent)
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)
int SetAddionalLoginTags(final
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.
int SetAddionalMsgTags(final
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).
int 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.
int ResetSequenceNumber(int 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(OutputShort &msg,
OutputString &s)
String GetControlMsgString()
short GetControlMsg()
These methods return the value of the control
message (and it's string parameter, if one was present)
OutputStream GetControlInterface()
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.
public Object []
DetachControlInterface()
Detach the ‘raw’ Control Interface. The
purpose
of doing this is so that the socket used by the Control Interface is
not
closed by the FixClient::Close() method. You can then
close
the FixClient and the Control Interface held by the UI
thread remains valid. Thus if you decide to open another FixClient
object, you can ‘reuse’ the Control Interface without having to inform
the GUI client.
public boolean
AttachControlInterface(Object
[] rawCtlIf)
Attach a previous detached ‘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.)
int SetRecoverySeqNos(long out)
// implies
in = -1
int SetRecoverySeqNos(long out, long
in)
This method can be used to recover a
connection
after complete sequence number failure. To achieve this you must call
this
method before 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.
boolean IsGmtOffsetInUse()
If a Virtual Timezone is being used
in
the Gateway process, this method returns true. (To find out more about Virtual
Timezones, see the FixGateway
documentation)
short GetGmtOffset()
If a Virtual Timezone is being used
in
the Gateway process, this method returns the offset from GMT of the Virtual
Timezone. If no Virtual Timezone is in use, a value
of Config.V_LOCAL_TIME
is returned. To find the time as viewed by the gateway process, use the
FixString.GetCurrentTime() method.
int
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. (To find out more about Confirmation
Requests, see the FixGateway
documentation)
FixString queryOutwardSeqNum(int
outwardSeqNum)
Given
a sequence number, this method finds the outbound message that was sent
with the given sequence number. It will return null if no message can
be
found.
| Class com.octatec.jfixgw.FixError |
FixError Static Constant 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.
FIX_NEVER_OPENED (-12)
you
are trying to call methods on the FixClient that require an open
session,
and one is not open
FIX_EMPTY_MSG (-13)
you
are attempting to send an empty Fix message.
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_2MANY (-993)
FIX_DISCONNECT_WHILE_LISTENING (-994)
FIX_SELECT_ERROR1 (-995)
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
boolean IsControlMsg(int errorCode)
Returns true if the input
errorCode represents
a control message. (I.e. errorCode==FixError.FIX_CONTROL_MSG).
boolean IsFixMsg(int errorCode)
Returns true if the input
errorCode represents
a FIX message. (I.e. errorCode==FixError.FIX_OK).
boolean IsError(int value)
Returns true if the input
errorCode represents
a an error state.
| Class
com.octatec.jfixgw.CntrlInterface |
Note: the functionality discussed
below is
encapsulated by the AfiThreadedApp
class, which you should use if you wish to create a FIX session in a
worker
thread, and send commands to it from a GUI (or similar) thread.
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 JFixSrv
program shows how the Control Interface can be used.
new CntrlInterface()
Create a new CntrlInterface object
(in the UI thread)
boolean InitControlSide();
Call this method first in the control (GUI)
thread
boolean WaitForActivation() //
implies
sendStartMsg=true
boolean WaitForActivation(bool
sendStartMsg);
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.
boolean 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.
boolean SendMsg(short iparam) //
implies
sparam=null
boolean SendMsg(short iparam, String
sparam);
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(),
a
return of FixError.FIX_CONTROL_MSG fromFixClient.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 boolean
SendResponse(OutputStream
sd, short iparam) // implies sparam=null
static boolean
SendResponse(OutputStream
sd, short iparam, String sparam)
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(OutputShort
iparam, OutputString
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.
Appendix IV - Installation Guide
AFI/J is a 100% pure Java application, and so should be able to run on
any operating system that has Java installed. However, to make
installation
easier, the application comes with 2
alternative
installation programs, one for UNIX and one for Windows.
These are discussed here.
Appendix
V
- Suport for SSL
SSL is not supported directly by AFI/J. However, you can ‘plug in’ your
own or a 3rd party SSL provider into the Engine.
You must specify the fully qualified name of a Socket class
and a ServerSocket
class in the properties file. (you only need to specify a ServerSocket
class if you are running AFI/J as a server)
Use the properties socketClass and serverSocketClass
in
session configuration properties file to do this. If these classes
begin
with a #, they will be ignored, otherwise they should specify a
valid class. Your class should be packaged in a .jar file, and the jar
should be specified in the client application properties file
(fixgw.properties)
by the SocketJar property. NOTE you specify the class names in
the session
properties file and the jar file that contains the classes in the client
application properties file – you use 2 different properties files.
The class you specify as a ServerSocket must implement the ServerSocketI
interface
public interface ServerSocketI {
public void init(int port) throws IOException;
public SocketI accept() throws IOException;
public void close() throws IOException;
}
And the class you specify as a Socket must implement the SocketI
interface.
public interface SocketI {
public void connect(InetAddress address, int
port)
throws IOException;
public InputStream getInputStream() throws
IOException
;
public OutputStream getOutputStream() throws
IOException;
public void shutdownInput() throws IOException;
public void shutdownOutput() throws
IOException;
public void close() throws IOException;
}
If you don’t specify any Socket/ServerSocket class in the properties
file,
default implementations are used that just delegate to the standard
Java
Socket and ServerSocket classes. The following is the code of the
default
implementations and can be used as a guide to creating your own
implementations.
import java.io.*;
import java.net.*;
public class DefaultServerSocket
implements ServerSocketI
{
private ServerSocket m_sd =
null;
public void init(int port)
throws IOException
{
m_sd = new
ServerSocket(port);
}
public SocketI accept()
throws IOException
{
Socket sd =
m_sd.accept();
DefaultSocket dsd
= new DefaultSocket(sd);
return dsd;
}
public void close() throws
IOException
{ m_sd.close(); }
}
import java.io.*;
import java.net.*;
public class DefaultSocket implements
SocketI {
private Socket m_sd = null;
DefaultSocket(Socket sd)
{m_sd = sd;
}
public void
connect(InetAddress address,
int port) throws IOException { m_sd = new Socket(address, port);
}
public InputStream
getInputStream()
throws IOException { return m_sd.getInputStream(); }
public OutputStream
getOutputStream()
throws IOException { return m_sd.getOutputStream(); }
public void shutdownInput()
throws IOException
{ m_sd.shutdownInput(); }
public void
shutdownOutput()throws IOException
{ m_sd.shutdownOutput(); }
public void close()throws
IOException
{ m_sd.close(); }
}
NIO Issues
If
you are running using java version 1.4 or above, AFI/J will, by
default,
use NIO. So if you are implementing these interfaces, you should
endeavour
to create your sockets in an NIO compatible manner. If you are using a
3rd party SSL socket library, this may not be possible. If
your
SSL providers socket sub-system does not support NIO, you can still use
it, but your must set the preferNIO parameter
to 0 in the configuration file. |