Version 2.32.0.0
Onix Solutions FIXForge .NET FIX Engine is a .NET class library (assembly) that will FIX-enable applications written in .NET supported languages (C#, Visual Basic (VB.NET), Managed C++, Delphi .NET, etc).
The Engine provides the following services:
.NET Framework 1.1, .NET Framework 2.0, .NET Framework 3.0 or .NET Framework 3.5.
Microsoft Visual Studio .NET 2003, Microsoft Visual Studio 2005 or Microsoft Visual Studio 2008.
All Engine classes are located in the FIXForge.NET.FIX namespace.
The typical way of using the Engine is as follows:
Exception handling is used as a fundamental error-reporting mechanism. In the event of any errors arising then the
EngineException is thrown.
To initialize the FIX Engine class library the Engine.Init method is used.
This method must be called before all other methods.
To shutdown the Engine the Engine.Shutdown method is used.
No other Engine methods must be called after this method.
using FIXForge.NET.FIX; try{ Engine fixEngine = Engine.Init(); // Session-related logic.. fixEngine.Shutdown(); }catch(Exception ex) Console.WriteLine("Exception: " + ex); }
Imports FIXForge.NET.FIX Try Dim fixEngine As Engine = Engine.Init() ' Session-related logic.. fixEngine.Shutdown() Catch ex As Exception Console.Out.WriteLine("EXCEPTION") Console.Out.WriteLine(ex) End Try
As the FIX protocol evolves its new versions will be released to you to extend the current functionality.
Supported FIX versions are: FIX 4.0, 4.1, 4.2, 4.3, 4.4 and 5.0. The ProtocolVersion
enum is used to identify them.
ProtocolVersion fixVersion = ProtocolVersion.FIX42;
Dim fixVersion As ProtocolVersion = ProtocolVersion.FIX42
Each FIX version has its own namespace that contains objects and definitions that are unique for the version, for example:
using FIXForge.NET.FIX.FIX42; Imports FIXForge.NET.FIX.FIX42
The general format of a FIX message is a stream of <tag>=<value> fields with a field delimiter (<SOH>) between fields in the stream (so-called "tag-value FIX format").
Below is an example of a FIX message:

It is represented with the Message class.
To create a FIX Message object the Message(String type, ProtocolVersion version) constructor is used.
To parse a message in the raw FIX format the Message(String rawMessage) constructor is used.
To validate a message the Message.Validate method is used.
This method checks for the presence of required fields.
There are several overloaded methods Message.ToString() to simplify debugging and monitoring.
// Creating a FIX Message object Message order_1 = new Message("D", ProtocolVersion.FIX40); // New Order - Single (MsgType = D) // Parsing a FIX message in the raw FIX format string rawFixMsg = "8=FIX.4.0\u00019=86\u000135=D\u000149=0\u000156=0\u000134=1\u000152=99990909-17:17:17\ u000111=90001008\u000121=1\u000155=IBM\u000154=1\u000138=10\u000140=1\u000159=0\u000110=191\u0001"; Message order_2 = new Message(rawFixMsg); order_2.Validate(); Console.WriteLine(order_2.ToString()); Console.WriteLine(order_2.ToString(' ')); Console.WriteLine(order_2.ToString(Message.StringFormat.TAG_NAME | Message.StringFormat.TAG_NUMBER, ' '));
' Creating a FIX Message object Dim order_1 As New Message("D", FIXForge.NET.FIX.ProtocolVersion.FIX40) ' New Order - Single (MsgType = D) ' Parsing a FIX message in the raw FIX format Dim rawFixMsg As String = "8=FIX.4.0" + ChrW(1) + "9=86" + ChrW(1) + "35=D" + ChrW(1) + "49=0" + ChrW(1) + "56=0" + ChrW(1) + "34=1" + ChrW(1) + "52=99990909-17:17:17" + ChrW(1) + "11=90001008" + ChrW(1) + "21=1" + ChrW(1) + "55=IBM" + ChrW(1) + "54=1" + ChrW(1) + "38=10" + ChrW(1) + "40=1" + ChrW(1) + "59=0" + ChrW(1) + "10=191" + ChrW(1) Dim order_2 As New Message(rawFixMsg) order_2.Validate() Console.WriteLine(order_2.ToString()) Console.WriteLine(order_2.ToString(" ")) Console.WriteLine(order_2.ToString(Message.StringFormat.TAG_NAME Or Message.StringFormat.TAG_NUMBER, " "))
To set a field value the Message.Set method is used.
To get a field value the Message.Get method is used.
It is also possible to get or set fields values using Message’s indexer.
string ClOrdID = order[11]; execReport[17] = "Unique identifier of execution message";
Dim ClOrdID As String = order.Get(11) execReport.Set(17, "Unique identifier of execution message")
To remove a field the Message.Remove method is used.
The Tags class contains the constants for the tag values. This class is defined for each FIX version namespace.
The use of these constants makes the source code more readable.
using FIXForge.NET.FIX; using FIXForge.NET.FIX.FIX42; Message order = new Message("D", ProtocolVersion.FIX42); // New Order – Single order.Set(Tags.ClOrdID, "90001008"); // or order[Tags.ClOrdID]= "90001008"; order.Set(Tags.Side, "1"); order.Set(Tags.TimeInForce, "0");
Imports FIXForge.NET.FIX Imports FIXForge.NET.FIX.FIX42 Dim order As New Message("D", FIXForge.NET.FIX.ProtocolVersion.FIX42) ' New Order Single order.Set(Tags.ClOrdID, "90001008") ' or order[Tags.ClOrdID]= "90001008"; order.Set(Tags.Side, "1") order.Set(Tags.TimeInForce, "0")
To iterate over all message fields the Message.Fields property is used.
using FIXForge.NET.FIX; using FIXForge.NET.FIX.FIX42; Message msg = new Message("D", ProtocolVersion.FIX42); foreach(Field field in msg.Fields){ Console.WriteLine("Tags=" + field.Tags +", value=" + field.Value); }
Imports FIXForge.NET.FIX Imports FIXForge.NET.FIX.FIX42 Dim msg As New Message("D", ProtocolVersion.FIX42) Dim field As Field For Each field In msg.Fields Console.WriteLine("Tags=") Console.WriteLine(field.Tags) Console.WriteLine(", value=") Console.WriteLine(field.Value) Next field
See also: FIX Repeating Group.
A FIX session is defined as a bi-directional stream of ordered messages between two parties within a continuous sequence number series.
It is represented by the Session class.
To create a session the Session constructors are used.
To terminate the session the Session.Dispose method is used.
A session has one of two possible roles: Acceptor or Initiator.
Acceptor is the receiving party of the FIX session. It listens for the incoming connection on the pre-defined port. The acceptor has responsibility to perform first level authentication and formally declare the connection request "accepted" through transmission of an acknowledgment Logon message.
Initiator establishes the telecommunications link and initiates the session via transmission of the initial Logon message.
To obtain the current role the Session.Role property is used.
To establish the FIX connection as Acceptor the Session.LogonAsAcceptor method is used.
To establish the FIX connection as Initiator the Session.LogonAsInitiator method is used.
To disconnect the session the Session.Logout method is used.
using FIXForge.NET.FIX; using FIXForge.NET.FIX.FIX42;
const string senderCompID = "SenderCompID"; const string targetCompID = "TargetCompID"; const ProtocolVersion version = ProtocolVersion.FIX42; const string TARGET_HOST = "localhost"; const int TARGET_PORT = Engine.Instance.Settings.ListenPort; // Target port is equal to acceptor's port to create a loopback FIX session.
Session acceptor = new Session(senderCompID, targetCompID, version); Session initiator = new Session(targetCompID, senderCompID, version);
acceptor.LogonAsAcceptor();
initiator.LogonAsInitiator(TARGET_HOST, TARGET_PORT); // Sends the Logon message and waits for the acknowledgment Logon
// Message exchange and processing..
acceptor.Logout(); // Sends the Logout message and waits for the confirming Logout initiator.Logout();
acceptor.Dispose(); // Free resources initiator.Dispose(); // Free resources
Imports FIXForge.NET.FIX Imports FIXForge.NET.FIX.FIX42 Dim senderCompID As String = "SenderCompID" Dim targetCompID As String = "TargetCompID" Dim fixVersion As FIXForge.NET.FIX.ProtocolVersion = FIXForge.NET.FIX.ProtocolVersion.FIX42 Dim TARGET_HOSTAs String = "localhost" Dim TARGET_PORT As Integer = Engine.Instance.Settings.ListenPort ' Target port is equal to acceptor's port to create a loopback FIX session. Dim acceptor As New Session(senderCompID, targetCompID, fixVersion) Dim initiator As New Session(targetCompID, senderCompID, fixVersion) acceptor.LogonAsAcceptor() initiator.LogonAsInitiator(TARGET_HOST, TARGET_PORT) ' Sends the Logon message and waits for the acknowledgment Logon ' Message exchange and processing.. acceptor.Logout() ' Sends the Logout message and waits for the confirming Logout initiator.Logout() acceptor.Dispose() ' Free resources initiator.Dispose() ' Free resources
See also: Session state, Custom Logon Message, Sequence Numbers.
To send a message to counterparty the Session.Send method is used.
This method is asynchronous. As soon as a session is created it is possible to start sending messages via the session.
If the session is not established, the messages will be sent when the connection is established with the counterparty.
To receive incoming application-level messages it is necessary to register for the
Session.InboundApplicationMsgEvent event.
using FIXForge.NET.FIX; using FIXForge.NET.FIX.FIX42; class SessionListener { public void OnInboundApplicationMsg(Object sender, Session.InboundApplicationMsgEventArgs e) { Console.WriteLine("Incoming application-level message: " + e.Msg); // processing of the application-level incoming message.. } } const string senderCompID = "Acceptor"; const string targetCompID = "Initiator"; const ProtocolVersion version = ProtocolVersion.FIX42; const string host = "localhost"; Engine engine = Engine.Init(); Session acceptor = new Session(senderCompID, targetCompID, version); acceptor.LogonAsAcceptor(); Session initiator = new Session(targetCompID, senderCompID, version); initiator.LogonAsInitiator(host, Engine.Instance.Settings.ListenPort); SessionListener listener = new SessionListener(); initiator.InboundApplicationMsgEvent += new Session.InboundApplicationMsgEventHandler(listener.OnInboundApplicationMsg); Message order = new Message(MsgType.Order_Single, version); order.Set(Tags.ClOrdID, "Unique identifier for Order as assigned by the buy-side"); order.Set(Tags.HandlInst, "1"); order.Set(Tags.Symbol, "Ticker symbol"); order.Set(Tags.Side, "1"); order.Set(Tags.TransactTime, DateTime.UtcNow.ToString("yyyyMMdd-HH:mm:ss")); order.Set(Tags.OrdType, "1"); order.Validate(); acceptor.Send(order); // continue the message exchange.. acceptor.Logout(); acceptor.Dispose(); initiator.Dispose(); engine.Shutdown();
Imports FIXForge.NET.FIX Imports FIXForge.NET.FIX.FIX42 Class SessionListener
Public Sub OnInboundApplicationMsg(ByVal sender As Object, ByVal args As Session.InboundApplicationMsgEventArgs)
Console.WriteLine("Incoming application-level message: ")
Console.WriteLine(args.Msg)
' processing of the application-level incoming message..
End Sub
End Class Dim senderCompID As String = "Acceptor" Dim targetCompID As String = "Initiator" Dim fixVersion As FIXForge.NET.FIX.ProtocolVersion = FIXForge.NET.FIX.ProtocolVersion.FIX42 Dim host As String = "localhost" Dim fixEngine As Engine = Engine.Init() Dim acceptor As Session = New Session(senderCompID, targetCompID, fixVersion) acceptor.LogonAsAcceptor() Dim initiator As Session = New Session(targetCompID, senderCompID, fixVersion) initiator.LogonAsInitiator(host, Engine.Instance.Settings.ListenPort) Dim listener As SessionListener = New SessionListener() AddHandler session.InboundApplicationMsgEvent, AddressOf listener.OnInboundApplicationMsg Dim order As Message = New Message("D", fixVersion) order.Set(Tags.ClOrdID, "Unique identifier for Order as assigned by the buy-side") order.Set(Tags.HandlInst, "1") order.Set(Tags.Symbol, "Ticker symbol") order.Set(Tags.Side, "1") order.Set(Tags.TransactTime, DateTime.UtcNow.ToString("yyyyMMdd-HH:mm:ss")) order.Set(Tags.OrdType, "1") order.Validate() acceptor.Send(order) 'continue the message exchange.. acceptor.Logout() acceptor.Dispose() initiator.Dispose() fixEngine.Shutdown()
All FIX messages are identified by a unique sequence number (the MsgSeqNum field).
Sequence numbers are initialized at the start of each FIX session starting at 1 (one) and increment throughout the session. Each session establishes an independent incoming and outgoing sequence series.
A single FIX session can exist across multiple sequential (not concurrent) physical connections. Parties can connect and disconnect multiple times while maintaining a single FIX session. In other words, FIX Session is comprised of one or more FIX Connections.
Resetting the inbound and outbound sequence numbers back to 1, for whatever reason, constitutes the beginning of a new FIX session.
Method Session.ResetSequenceNumbers could be used to backup the previous log files and reset the sequence numbers to 1.
Monitoring sequence numbers enables parties to gracefully synchronize applications when reconnecting during a FIX session.
To get or set the expected sequence number of the next incoming message the Session.InSeqNum property is used.
To get or set the sequence number of the next outgoing message the Session.OutSeqNum property is used.
Note: It is NOT recommended to use Session.InSeqNum and Session.OutSeqNum properties to reset session sequence numbers to 1. Method Session.ResetSequenceNumbers should be used instead.
To disconnect the FIX Connection while maintaining a single FIX Session the Session.Logout method is used.
It is possible to continue the session later using the Session.LogonAsAcceptor
or Session.LogonAsInitiator methods again.
To terminate a FIX Session the Session.Dispose() method is used.
The FIX Engine automatically synchronizes sequence numbers when reconnecting during a FIX session on the base of the information previously stored in log files.
To synchronize sequence numbers manually Session.InSeqNum and Session.OutSeqNum properties are used (before Session.LogonAsAcceptor() or
Session.LogonAsInitiator() method calls).

Some implementations of FIX protocol (FIX Dialects) expect that the FIX Session coincides with FIX Connection, in other words that the sequence numbers are reset back to 1 after the Logout messages exchange.
To interact with such FIX dialects, the keepSequenceNumbersAfterLogout parameter
of Session constructor should
be set to false. In this case after Session.Dispose() method sequence numbers are set back to 1. Next time when the Session object is created incoming and outgoing sequence numbers will start from 1 (in other words, a new FIX Session will be created).
See also: Sequence Number Reset, Sequence Number Reset via ResetSeqNumFlag field.
By default the license file (FIXForge.NET.FIX.Engine.lic) must be placed in the same directory as the FIX Engine assembly (FIXForge.NET.FIX.Engine-net-1.1.dll or FIXForge.NET.FIX.Engine-net-2.0.dll).
It is possible to specify the path to the license file using either
LicenseFile configuration setting or
EngineSettings.LicenseFile property.
The license expiration date is available via Engine.LicenseExpirationDate property.
The MsgStorage folder is created for storing log data. Incoming and outgoing messages, session’s state data and the FIX Engine log file (FixEngineLog.txt) are stored in this folder.
Unless the storageType parameter of Session’s constructor is set to SessionStorageType.MemoryBasedStorage a file-based session storage is used.
For each FIX session with a file-based session storage the following files are created:
SESSION_NAME is formed on the base of SenderCompID, TargetCompID, session's FIX version and a timestamp. During the run-time is it available via Session.StorageID property.
When the Session object with a file-based session storage is created anew after Engine's restart, FIX Session's state (the sequence numbers of last received and sent messages, previously sent messages, etc) is restored from these files.
To start a FIX session as a new one (so called "clean start"), it is necessary to remove the session files from the previous runs.
Connecting parties must bi-laterally agree as to when sessions are to be started/stopped and log files are backed up based upon individual system and time zone requirements.
When the FIX session is finished, the session files are not needed anymore. They can be backed up and later a new FIX session with the same SenderCompID and TargetCompID will start sequence numbers from 1. The usual practice is to backup the log files at the end of each business day (so called "End Of Day procedure") to start the sequence numbers from 1 at the beginning of the next day.
To reset the sequence numbers to 1 and backup the log files the Session.ResetSequenceNumbers method can be used.
This method can be called only when the session is disconnected.
See also: Memory Based Session Storage, Log.Directory, Log.FlushFileAfterEachMessage, Sequence Numbers, FIX Analyser.
The default values of FIX Engine settings can be changed using the <FixEngine> configuration section of
the standard .NET Framework application-level configuration file (App.config at design time or YourApplicationName.exe.config at run-time) or using the EngineSettings parameter of the Engine.Init method.
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="FixEngine" type="System.Configuration.NameValueSectionHandler"/> </configSections> <FixEngine> <add key="Dialect" value="LavaDialect.xml"/> <add key="ListenPort" value="4500"/> <add key="Reconnect.Attempts" value="3"/> <add key="Reconnect.Interval" value="30"/> <add key="Validate.NumberOfRepeatingGroupInstances" value="false"/> <add key="Validate.RequiredFields" value="true"/> <add key="Validate.UnknownFields" value="true"/> <add key="Validate.UnknownMessages" value="true"/> </FixEngine> </configuration>
EngineSettings settings = new EngineSettings(); settings.LogDirectory = "LogDirectoryValue"; Engine.Init(settings);
Dim settings As EngineSettings = New EngineSettings() settings.LogDirectory = "LogDirectoryValue" Engine.Init(settings)
|
It is permissible for fields to be repeated in the same message within a repeating group
(e.g. "215=2<SOH>216=2<SOH>217=Dest_1<SOH>216=4<SOH>217=Dest_2<SOH>"
represents a repeating group with two repeating instances "delimited" by tag 216 (first field in the repeating group.).
The NoRoutingIDs<215> field specifies the number of repeating group instances (2 in this case). This is so called "NumberOfInstances field". The NumberOfInstances field must immediately precede the repeating group contents (repeating group instances).

The FIX repeating group is represented with the Group class.
To get the Group object that represents the existing repeating group of the message the Message.GetGroup(int numberOfInstancesTag) method is used.
To create a new repeating group or modify the number of instances in the existing one the Message.SetGroup(int numberOfInstancesTag, int numberOfInstances) method is used.
To remove a repeating group method Message.Remove(int numberOfInstancesTag) is used.
The Group class works with fields and embedded repeating groups in the same manner as the Message class,
but each method has an additional parameter that defines the index of the repeating group instance (starting from 0).
Message request = new Message("V", ProtocolVersion.FIX42); // Market Data Request request.Set(Tags.MDReqID, "ABSD"); request.Set(Tags.SubscriptionRequestType, 1); request.Set(Tags.MarketDepth, 1); request.Set(Tags.MDUpdateType, 1); request.Set(Tags.AggregatedBook, "N"); // create a repeating group NoMDEntryTypes with two instances Group groupMDEntryTypes = request.SetGroup(Tags.NoMDEntryTypes, 2); groupMDEntryTypes.Set(Tags.MDEntryType, 0, "EntryType_0"); // first instance groupMDEntryTypes.Set(Tags.MDEntryType, 1, "EntryType_1"); // second instance // create a repeating group NoRelatedSym with two instances Group groupRelatedSym = request.SetGroup(Tags.NoRelatedSym, 2); groupRelatedSym.Set(Tags.Symbol, 0, "EURUSD_0"); // first instance groupRelatedSym.Set(Tags.Symbol, 1, "EURUSD_1"); // second instance request.Validate(); Console.WriteLine(request.ToString());
Dim request As Message = New Message("V", FIXForge.NET.FIX.ProtocolVersion.FIX42) ' Market Data Request request.Set(Tags.MDReqID, "ABSD") request.Set(Tags.SubscriptionRequestType, 1) request.Set(Tags.MarketDepth, 1) request.Set(Tags.MDUpdateType, 1) request.Set(Tags.AggregatedBook, "N") ' create a repeating group NoMDEntryTypes with two instances Dim groupMDEntryTypes As Group = request.SetGroup(Tags.NoMDEntryTypes, 2) groupMDEntryTypes.Set(Tags.MDEntryType, 0, "EntryType_0") ' first instance groupMDEntryTypes.Set(Tags.MDEntryType, 1, "EntryType_1") ' second instance ' create a repeating group NoRelatedSym with two instances Dim groupRelatedSym As Group = request.SetGroup(Tags.NoRelatedSym, 2) groupRelatedSym.Set(Tags.Symbol, 0, "EURUSD_0") ' first instance groupRelatedSym.Set(Tags.Symbol, 1, "EURUSD_1") ' second instance request.Validate() Console.WriteLine(request.ToString())
See also: FIX Dialects.
To obtain the current session state the Session.State property is used.
The states of the FIX session are listed below.
To be notified about the changes in the session state register for the Session.StateChangeEvent event.
void OnStateChange(Object sender, Session.StateChangeEventArgs e) { Console.WriteLine("New session state: " + e.NewState); } void run() { Engine.Init(); Session session = new Session("SenderCompID", "TargetCompID", ProtocolVersion.FIX42); session.StateChangeEvent += new Session.StateChangeEventHandler(OnStateChange); // ... }
Sub OnStateChange(ByVal sender As Object, ByVal e As Session.StateChangeEventArgs) Console.WriteLine("New session state: ") Console.WriteLine(e.NewState) End Sub Sub Run() Engine.Init() Dim session As New Session("SenderCompID", "TargetCompID", FIXForge.NET.FIX.ProtocolVersion.FIX42) AddHandler session.StateChangeEvent, AddressOf OnStateChange End Sub
The events of the Session class are listed below.
|
Note: It is important not perform time-consuming tasks inside event handlers.
void OnStateChange(object sender, Session.StateChangeEventArgs e) { Console.WriteLine("New session state: " + e.NewState); } void OnInboundApplicationMsg(object sender, Session.InboundApplicationMsgEventArgs e) { Console.WriteLine("Incoming application-level message: " + e.Msg); } void OnInboundSessionMsg(object sender, Session.InboundSessionMsgEventArgs e) { Console.WriteLine("Incoming session-level message: " + e.Msg); } void OnOutboundApplicationMsg(object sender, Session.OutboundApplicationMsgEventArgs e) { Console.WriteLine("Outgoing application-level message: " + e.Msg); } void OnOutboundSessionMsg(object sender, Session.OutboundSessionMsgEventArgs e) { Console.WriteLine("Outbound session-level message: " + e.Msg); } void OnMessageResending(object sender, Session.MessageResendingEventArgs e) { Console.WriteLine("OnMessageResending: " + e.Msg); e.AllowResending = false; } void OnSessionWarning(object sender, Session.WarningEventArgs e) { Console.WriteLine("Session warning: " + e.Reason); } void OnSessionError(object sender, Session.ErrorEventArgs e) { Console.WriteLine("Session error: " + e.Reason); } void run() { Session session = new Session("SenderCompID", "TargetCompID", ProtocolVersion.FIX44); session.StateChangeEvent += new Session.StateChangeEventHandler(OnStateChange); session.InboundSessionMsgEvent += new Session.InboundSessionMsgEventHandler(OnInboundSessionMsg); session.InboundApplicationMsgEvent += new Session.InboundApplicationMsgEventHandler(OnInboundApplicationMsg); session.OutboundSessionMsgEvent += new Session.OutboundSessionMsgEventHandler(OnOutboundSessionMsg); session.OutboundApplicationMsgEvent += new Session.OutboundApplicationMsgEventHandler(OnOutboundApplicationMsg); session.MessageResending += new Session.MessageResendingEventHandler(OnResendRequest); session.WarningEvent += new Session.WarningEventHandler(OnSessionWarning); session.ErrorEvent += new Session.ErrorEventHandler(OnSessionError); // ... }
Sub OnStateChange(ByVal sender As Object, ByVal e As Session.StateChangeEventArgs) Console.WriteLine("New session state: " + e.NewState.ToString()) End Sub Sub OnInboundApplicationMsg(ByVal sender As Object, ByVal e As Session.InboundApplicationMsgEventArgs) Console.WriteLine("Incoming application-level message: " + e.Msg.ToString()) End Sub Sub OnInboundSessionMsg(ByVal sender As Object, ByVal e As Session.InboundSessionMsgEventArgs) Console.WriteLine("Incoming session-level message: " + e.Msg.ToString()) End Sub Sub OnOutboundApplicationMsg(ByVal sender As Object, ByVal e As Session.OutboundApplicationMsgEventArgs) Console.WriteLine("Outgoing application-level message: " + e.Msg.ToString()) End Sub Sub OnOutboundSessionMsg(ByVal sender As Object, ByVal e As Session.OutboundSessionMsgEventArgs) Console.WriteLine("Outbound session-level message: " + e.Msg.ToString()) End Sub Sub OnMessageResending(ByVal sender As Object, ByVal e As Session.ResendRequestEventArgs, ByRef allowResend As System.ValueType) Console.WriteLine("OnMessageResending: " + e.Msg.ToString()) e.AllowResending = False End Sub Sub OnSessionWarning(ByVal sender As Object, ByVal e As Session.WarningEventArgs) Console.WriteLine("Session warning: " + e.Reason.ToString()) End Sub Sub OnSessionError(ByVal sender As [Object], ByVal e As Session.ErrorEventArgs) Console.WriteLine("Session error: " + e.Reason.ToString()) End Sub Sub MainRun() Engine.Init() Dim session As New Session("SenderCompID", "TargetCompID", FIXForge.NET.FIX.ProtocolVersion.FIX42) AddHandler session.StateChangeEvent, AddressOf OnStateChange AddHandler session.InboundSessionMsgEvent, AddressOf OnInboundSessionMsg AddHandler session.InboundApplicationMsgEvent, AddressOf OnInboundApplicationMsg AddHandler session.OutboundSessionMsgEvent, AddressOf OnOutboundSessionMsg AddHandler session.OutboundApplicationMsgEvent, AddressOf OnOutboundApplicationMsg AddHandler session.MessageResending, AddressOf OnMessageResending AddHandler session.WarningEvent, AddressOf OnSessionWarning AddHandler session.ErrorEvent, AddressOf OnSessionError End Sub
Sometimes it is required to accept an incoming FIX session 'on the fly', without the prior creation of the Session object and connecting it as TargetCompID of the incoming session is not known in advance). To perform this task, subscribe to
Engine.UnknownIncomingConnection event.
An automatically created Session object that corresponds to the incoming FIX connection is available via the
CreatedSession property of the
UnknownIncomingConnectionEventArgs object passed to your event handler.
To accept the incoming connection, set the
Accept property of the
UnknownIncomingConnectionEventArgs object to true. Otherwise the incoming connection will be rejected and the created Session object will be disposed by the FIX Engine.
void run() { Engine.Init(); Engine.Instance.UnknownIncomingConnection += new Engine.UnknownIncomingConnectionEventHandler(OnUnknownIncomingConnection); // ... } void OnUnknownIncomingConnection(Object sender, Engine.UnknownIncomingConnectionEventArgs e) { Console.WriteLine("Unknown incoming session: " + e.Session); e.Accept = true; // Otherwise the connection will be rejected! }
Session events are fired from the FIX Engine thread of execution.
In order to safely update GUI Controls it is necessary to use Control.BeginInvoke, otherwise the application could hang.
delegate void UpdateSessionStateDelegate(string state); void UpdateSessionState(string state) { statusBar.Panels[0].Text = state; } void OnStateChange(Object sender, Session.StateChangeEventArgs e) { statusBar.BeginInvoke(new UpdateSessionStateDelegate(UpdateSessionState), new object[] {e.NewState.ToString()}); }
Dim formStatusBar As StatusBar = New StatusBar Delegate Sub UpdateSessionStateDelegate(ByVal state As String) Sub UpdateSessionState(ByVal state As String) formStatusBar.Panels.Item(0).Text = state End Sub Sub OnStateChange(ByVal sender As Object, ByVal e As Session.StateChangeEventArgs) formStatusBar.BeginInvoke(New UpdateSessionStateDelegate(AddressOf Me.UpdateSessionState), New Object() {e.NewState.ToString()}) End Sub
Sometime there is need to set additional fields (e.g. Username <553>, Password <554>) in the initiation Logon message.
In this case the Session.LogonAsInitiator(string host, int port, int heartBtInt, Message customLogonMsg) method must be used.
using FIXForge.NET.FIX; using FIXForge.NET.FIX.FIX43; const string senderCompID = "CustomLogonMessage_SND"; const string targetCompID = "CustomLogonMessage_TRG"; const ProtocolVersion version = ProtocolVersion.FIX43; const int HBI = 30; const string USERNAME = "USER_NAME"; const string PASSWORD = "PASSWORD"; Session acceptor = new Session(senderCompID, targetCompID, version); acceptor.LogonAsAcceptor(); Session initiator = new Session(targetCompID, senderCompID, version); Message customLogonMsg = new Message("A", FIXForge.NET.FIX.ProtocolVersion.FIX43); customLogonMsg[Tags.Username] = USERNAME; customLogonMsg[Tags.Password] = PASSWORD; initiator.LogonAsInitiator("localhost", Engine.Instance.Settings.ListenPort, HBI, customLogonMsg); // message exchange and processing.. acceptor.Logout(); initiator.Logout(); acceptor.Dispose(); initiator.Dispose();
Imports FIXForge.NET.FIX Imports FIXForge.NET.FIX.FIX43 Dim senderCompID As String = "CustomLogonMessage_SND" Dim targetCompID As String = "CustomLogonMessage_TRG" Dim fixVersion As FIXForge.NET.FIX.ProtocolVersion = FIXForge.NET.FIX.ProtocolVersion.FIX43 Dim HBI = 30 Dim USERNAME As String = "USER_NAME" Dim PASSWORD As String = "PASSWORD" Dim acceptor As New Session(senderCompID, targetCompID, fixVersion) acceptor.LogonAsAcceptor() Dim initiator As New Session(targetCompID, senderCompID, fixVersion) Dim customLogonMsg As New Message("A", FIXForge.NET.FIX.ProtocolVersion.FIX43) customLogonMsg.Set(Tags.Username, USERNAME) customLogonMsg.Set(Tags.Password, PASSWORD) initiator.LogonAsInitiator("localhost", Engine.Instance.Settings.ListenPort, HBI, customLogonMsg) ' message exchange and processing.. acceptor.Logout() initiator.Logout() acceptor.Dispose() initiator.Dispose()
Method Session.ResetSequenceNumbers is used to reset the sequence numbers to 1 and backup the previous log files. This method can be called only when the session is disconnected.
See also: Sequence Numbers.
ResetSeqNumFlag (141) field in the Logon (A) message indicates that the both sides of the FIX session should reset sequence numbers.
To send a Logon message with this field during FIX Connection establishment, use the setResetSeqNumFlag parameter of the Session.LogonAsInitiator(string host, int port, bool setResetSeqNumFlag) method.
It is also possible to send a Logon message with the ResetSeqNumFlag set when the FIX Session is established (e.g. to maintain 24 hour connectivity) using Session.ResetSeqNumViaLogonExchange method.
It is not uncommon for firms to implement slightly different interpretations of the FIX protocol (FIX dialects).
Due to the design of the FIX protocol such deviations from the FIX specification should be described to the FIX Engine, otherwise it will not be able to parse or create the corresponding FIX messages correctly.
The Dialect configuration setting specifies the path to the description of FIX dialects in XML file.
This description must confirm to the Dialect.xsd XML Schema.
Ready to use FIX dialect description files as well as exchange-specific trading and market data client samples are available for many FIX destinations (Hotspot, Currenex, CME, EFX, etc) upon request.
To add a new user-defined field to a FIX Message add the corresponding <Field> entity to the FIX Dialect description file.
For example:
<?xml version="1.0" encoding="utf-8"?> <Dialect xmlns="http://tempuri.org/Dialect.xsd" name="DialectID"> <FIX version="4.0"> <Message type="D"> <Field tag="526" name="SecondaryClOrdID"/> <!-- Does not belong to Standard FIX 4.0 --> </Message> </FIX> </Dialect>
To add a new user-defined repeating group to a FIX Message add the corresponding <Group> entity to the FIX Dialect description file.
For example:
<?xml version="1.0" encoding="utf-8"?> <Dialect xmlns="http://tempuri.org/Dialect.xsd" name="DialectID"> <FIX version="4.0"> <Message type="D"> <Group numberOfInstancesTag="78" name="NoAllocs"> <!-- Number of repeating groups for pre-trade allocation, does not belong to Standard FIX 4.0 --> <Field tag="79" name="AllocAccount"/> <!-- Does not belong to Standard FIX 4.0 --> <Field tag="661" name="AllocAcctIDSource"/> <!-- Does not belong to Standard FIX 4.0 --> <Field tag="736" name="AllocSettlCurrency"/> <!-- Does not belong to Standard FIX 4.0 --> <!-- Other group fields --> </Group> </Message> </FIX> </Dialect>
To make a field, which is required according to the FIX Protocol specification, optional, and visa-versa, add the corresponding <Field> entity to the FIX Dialect description and set the isRequired attribute accordingly.
For example:
<?xml version="1.0" encoding="utf-8"?> <Dialect xmlns="http://tempuri.org/Dialect.xsd" name="DialectID"> <FIX version="4.0"> <Message type="D"> <Field tag="21" isRequired="false" name="HandlInst"/> <!-- Required in Standard FIX 4.0, but optional in this FIX dialect --> <Field tag="109" isRequired="true" name="ClientID"/> <!-- Optional in Standard FIX 4.0, but required in this FIX dialect --> </Message> </FIX> </Dialect>
To define a User Defined Message add the corresponding <Message> entity to the FIX Dialect description.
For example:
<?xml version="1.0" encoding="utf-8"?> <Dialect xmlns="http://tempuri.org/Dialect.xsd" name="DialectID"> <FIX version="4.0"> <Message type="UserDefinedMessage_1"> <Field tag="100"/> <Field tag="101"/> </Message> </FIX> </Dialect>
Such a user-defined message can be used exactly the same way as the standard FIX Message:
Message userDefinedMsg = new Message("UserDefinedMessage_1", ProtocolVersion.FIX40); userDefinedMsg.Set(100, "Field 100"); userDefinedMsg.Set(101, "Field 101"); userDefinedMsg.Validate(); Console.WriteLine("UDM: " + userDefinedMsg);
Dim userDefinedMsg As New Message("UserDefinedMessage_1", FIXForge.NET.FIX.ProtocolVersion.FIX42) userDefinedMsg.Set(100, "Field 100") userDefinedMsg.Set(101, "Field 101") userDefinedMsg.Validate() Console.WriteLine("UDM: " + userDefinedMsg.ToString())
Example of a FIX Dialect description file:
<?xml version="1.0" encoding="utf-8"?> <Dialect xmlns="http://tempuri.org/Dialect.xsd" name="Lava"> <FIX version="4.2"> <Message type="N"> <Group numberOfInstancesTag="73" name="RefAllocID"> <!-- An additional field in the existing repeating group --> <Field tag="37" name="OrderID"/> </Group> </Message> </FIX> <FIX version="4.3"> <Message type="y"> <Group numberOfInstancesTag="146" name="NoRelatedSym"> <!-- An additional field in the existing repeating group --> <Field tag="64" isRequired="true" name="FutSettDate"/> </Group> </Message> <Message type="W"> <Group numberOfInstancesTag="268" name="NoMDEntries"> <!-- An additional field in the existing repeating group --> <Field tag="278" name="MDEntryID"/> </Group> <Field tag="64" name="FutSettDate"/> </Message> <Message type="X"> <!-- An additional field --> <Field tag="55" name="Symbol"/> <!-- An additional field --> <Field tag="64" name="FutSettDate"/> </Message> </FIX> </Dialect>
See also: the Dialect configuration setting.
The Dictionary namespace contains information about the structure of FIX versions (dialects), messages and fields.
To get the field name by the given tag number the Dialect.TagNameByNumber method is used.
using FIXForge.NET.FIX; using FIXForge.NET.FIX.Dictionary; Dialect dialect = new Dialect(ProtocolVersion.FIX42); string name = dialect.TagNameByNumber(34);
Imports FIXForge.NET.FIX Imports FIXForge.NET.FIX.Dictionary Dim dialectInstance As New Dialect(FIXForge.NET.FIX.ProtocolVersion.FIX42) Dim name As String = dialectInstance.TagNameByNumber(34)
To get the collection of valid field values the Dialect.GetValidFieldValues method is used.
using FIXForge.NET.FIX; using FIXForge.NET.FIX.Dictionary; Dialect dialect = new Dialect(ProtocolVersion.FIX42); ValidFieldValue[] values = dialect.GetValidFieldValues(54); foreach(ValidFieldValue vfv in values){ Console.WriteLine(vfv.Value + " = " + vfv.Description); }
Imports FIXForge.NET.FIX Imports FIXForge.NET.FIX.Dictionary Dim dialectInstance As New Dialect(FIXForge.NET.FIX.ProtocolVersion.FIX42) Dim values As ValidFieldValue() = dialectInstance.GetValidFieldValues(54) Dim vfv As ValidFieldValue For Each vfv In values Console.WriteLine(vfv.Value + " = " + vfv.Description) Next vfv
To traverse the message structure the Dialect.GetMessageFields method is used.
using FIXForge.NET.FIX; using FIXForge.NET.FIX.Dictionary; Dialect dialect = new Dialect(ProtocolVersion.FIX42); void TraverseChildFields(FieldInfo[] childFields, int shift) { if(0 == childFields.Length){ return; } String spaces = new String(' ', shift); foreach(FieldInfo fInfo in childFields){ Console.WriteLine(spaces + fInfo.Tags + ", " + fInfo.IsRequired); TraverseChildFields(fInfo.ChildFields, shift*2); } } public void GetMessageFields() { FieldInfo[] fields = dialect.GetMessageFields("i"); foreach (FieldInfo fInfo in fields) { Console.WriteLine(fInfo.Tags + ", " + fInfo.IsRequired); TraverseChildFields(fInfo.ChildFields, 3); } }
Imports FIXForge.NET.FIX Imports FIXForge.NET.FIX.Dictionary Dim dialectInstance As New Dialect(FIXForge.NET.FIX.ProtocolVersion.FIX42) Sub TraverseChildFields(ByVal childFields() As FieldInfo, ByVal shift As Integer) If 0 = childFields.Length Then Return End If Dim spaces As New String(" "c, shift) Dim fInfo As FieldInfo For Each fInfo In childFields Console.WriteLine(spaces + fInfo.Tags + ", " + fInfo.IsRequired) TraverseChildFields(fInfo.ChildFields, shift * 2) Next fInfo End Sub Public Sub GetMessageFields() Dim fields As FieldInfo() = dialectInstance.GetMessageFields("i") Dim fInfo As FieldInfo For Each fInfo In fields Console.WriteLine(fInfo.Tags + ", " + fInfo.IsRequired) TraverseChildFields(fInfo.ChildFields, 3) Next fInfo End Sub
When the Resend Request (2) message is received from the counterparty (e.g due to the sequence numbers mismatch) and the application has subscribed to the SequenceReset-GapFill (MsgType 4) message will be sent instead of the requested message.
If the sent application-level message should be resent to the counterparty then the AllowResending property of Session.MessageResendingEventArgs parameter should be set to True in the corresponding Sequence Reset-GapFill (4) message will be sent instead (e.g. in case of an aged order).
The message that is about to be resent is available via MessageResendingEventArgs.Msg property of Session.MessageResendingEventArgs parameter.
public void OnMessageResending(object sender, Session.MessageResendingEventArgs e) { Console.WriteLine("Message " + e.Msg + " is about to be resent to the counterpart"); e.AllowResending = true; // false - to skip (GapFill) this message } public void Run() { Session session = new Session("SenderCompID", "TargetCompID", ProtocolVersion.FIX50); session.MessageResending += new Session.MessageResendingEventHandler(OnMessageResending); // ... }
Memory based session storage could be used to maintain a high-performance FIX session when persisting of session’s state and messages in the file system is not required.
To create such a session storageType parameter of Session’s constructor should be set to SessionStorageType.MemoryBasedStorage.
Boolean keepSequenceNumbersAfterLogout = false;
Session session = new Session("SenderCompID", "TargetCompID", ProtocolVersion.FIX42, keepSequenceNumbersAfterLogout, Session.SessionStorageType.MemoryBasedStorage);
To accept (listen for) incoming connections on multiple ports simultaneously these ports should be specified during FIX Engine initialization using either the ListenPort FIX Engine configuration setting or EngineSettings.ListenPorts property.
If a session-acceptor should be bound to a specific listen port then this port is explicitly defined via the Session.ListenPort property.
If there is an incoming FIX connection on one of the configured listen ports and the corresponding FIX session-acceptor is found without the specified listen port or with the same specified listen ports as the 'active' listen port the incoming FIX connection is accepted.
If the corresponding FIX session-acceptor is found, but the specified session listen port is not the same as the 'active' listen port then the incoming FIX connection is terminated.
EngineSettings settings = new EngineSettings();
settings.ListenPorts = new int[] { 9001, 9002 };
Engine.Init(settings);
Session firstAcceptor = new Session("Acceptor_1", "Initiator_1", ProtocolVersion.FIX42);
firstAcceptor.LogonAsAcceptor();
Session secondAcceptor = new Session("Acceptor_2", "Initiator_2", ProtocolVersion.FIX42);
secondAcceptor.LogonAsAcceptor();
Session firstInitiator = new Session( "Initiator_1", "Acceptor_1", ProtocolVersion.FIX42);
firstInitiator.LogonAsInitiator("localhost", 9001);
Session secondInitiator = new Session( "Initiator_2", "Acceptor_2", ProtocolVersion.FIX42);
secondInitiator.LogonAsInitiator("localhost", 9002);
// Message exchange ...
firstInitiator.Logout();
secondInitiator.Logout();
To use the Ssl (Secure Sockets Layer) connectivity the following steps should be taken:
Session.Encryption property to
Session.EncryptionMethod.SSL right after the creation of the
Session object.EngineSettings settings = new EngineSettings();
// the next two assignments are only needed if the counterparty requires client-side SSL certificate:
settings.SslCertificateFile = "SSL_Certificate_File.pem";
settings.SslPrivateKeyFile = "SSL_PrivateKey_File.pem"; // could be the same file as above
Engine.Init(settings);
Session session = new Session("SenderCompID", "TargetCompID", ProtocolVersion.FIX42);
session.Encryption = Session.EncryptionMethod.SSL;
session.LogonAsInitiator("localhost", 443, true);
// Message exchange ...
session.Logout("SSL connection is finished.");
Dim settings As New EngineSettings()
' the next two assignments are only needed if the counterparty requires client-side SSL certificate:
settings.SslCertificateFile = "SSL_Certificate_File.pem"
settings.SslPrivateKeyFile = "SSL_PrivateKey_File.pem" ' could be the same file as above
Engine.Init(settings)
Dim session As New Session("SenderCompID", "TargetCompID", ProtocolVersion.FIX42)
session.Encryption = Session.EncryptionMethod.SSL
session.LogonAsInitiator("localhost", 443, True)
' Message exchange ...
session.Logout("SSL connection is finished.")
See also: Settings.SSL.CertificateFile, Settings.SSL.ListenPort, Settings.SSL.PrivateKeyFile, Settings.SSL.PrivateKeyPassword, and Settings.SSL.VerifyPeer configuration settings.
The (Privacy Enhanced Mail) Base 64 Encoded (.pem) SSL certificates are supported.
To convert into this format from other format types, the openssl command-line tool could be used (http://www.openssl.org).
For example, to convert from "Personal Information Exchange - PKCS#12 (.pfx)" to "Base64 Encoded (.pem)", the following command is run on the PFX file:
openssl pkcs12 -in <file_name>.pfx -out <file_name>.pem -nodesPer-session SSL settings ara available via Session.Ssl property.
Example in C# :
Engine.Init();
string targetCompID = "CNX";{ // Stream FIX Session
string streamSenderCompID = "str";
Session streamSession = new Session(streamSenderCompID, targetCompID, ProtocolVersion.FIX42);string streamSslCertificateAndPrivateKeyFile = "str.pem"; // If your counterpart performs the verification of your SSL certificate you need to set both SSL Certificate File and SSL Private Key File.
streamSession.Ssl.CertificateFile = streamSslCertificateAndPrivateKeyFile;
streamSession.Ssl.PrivateKeyFile = streamSslCertificateAndPrivateKeyFile;
int streamPort = 442;
streamSession.LogonAsInitiator(host, streamPort, 30, true);
Console.WriteLine("Stream session is established");
streamSession.Logout();
}
{ // Trading FIX Session
string tradingSenderCompID = "tr";
Session tradingSession = new Session(tradingSenderCompID, targetCompID, ProtocolVersion.FIX42);
tradingSession.Encryption = Session.EncryptionMethod.SSL;
string tradingSslCertificateAndPrivateKeyFile = "tr.pem";
// If your counterpart performs the verification of your SSL certificate you need to set both SSL Certificate File and SSL Private Key File.
tradingSession.Ssl.CertificateFile = tradingSslCertificateAndPrivateKeyFile;
tradingSession.Ssl.PrivateKeyFile = tradingSslCertificateAndPrivateKeyFile;
int tradingPort = 443;
tradingSession.LogonAsInitiator(host, tradingPort, 30, true);
Console.WriteLine("Trading session is established");
tradingSession.Logout();
}
FAST (FIX Adapted for Streaming) is a binary encoding method for message oriented data streams.
FAST-related classes can be found in the FIXForge.NET.FIX.FAST namespace.
To encode a FIX message into a FAST stream the Encoder class is used.
To decode a part of a FAST stream back into a FIX message the Decoder class is used.
Both Encoder and Decoder constructors require the string that contains XML-based FAST templates.
A FAST Template specifies the encoding and decoding rules in accordance with the FAST specification.
<?xml version="1.0" encoding="utf-8"?> <templates> <template name="Market Data - Incremental Refresh (X)" id="88"> <uInt32 name="BodyLength" id="9"/> <string name="MessageType" id="35"> <constant value="X" /> </string> <string name="SenderCompID" id="49"> <copy/> </string> <string name="TargetCompID" id="56"> <copy/> </string> <uInt64 name="MsgSeqNum" id="34"> <increment value="1"/> </uInt64> <string name="SendingTime" id="52"> <tail/> </string> <string name="PosDupFlag" id="43" presence="optional"> <default/> </string> <sequence name="MDEntries"> <length name="NoMDEntries" id="268"/> <string name="MDUpdateAction" id="279"/> <string name="Symbol" id="55"/> </sequence> <string name="CheckSum" id="10"/> </template> <templates>
The following field types are supported:
|
The optional presence attribute indicates whether the field is mandatory or optional. If the attribute is not specified, the field is mandatory.
The required name attribute identifies the corresponding field in the current FIX message type by the field name.
The optional id attribute identifies the corresponding field in the current FIX message type by the tag number.
A field that is not a Sequence can have a field operator. The Field Operator specifies an optimization operation for the field.
The following field operators are supported:
|
Each FAST Template is assigned a Template Identifier which uniquely describes the encoding/decoding rules.
More than one FAST template can be used to encode the same FIX message type, so the Template ID is supplied as an argument of the
Encoder.Encode method.
Some Field Operators rely on a previous value. Previous values are maintained in named dictionaries.
To reset the state of dictionaries (set the state of the previous values to undefined)
the Encoder.Reset and
Decoder.Reset methods are used.
Session.InSeqNum
and Session.OutSeqNum properties to set the start sequence numbers before
establishing the session. See also: Sequence Numbers. Control.Invoke instead. See also: Updating GUI Controls on Session event.
Message customLogonMsg = new Message("A", FIXForge.NET.FIX.ProtocolVersion.FIX42); customLogonMsg[Tags.SenderSubID] = "SenderSubID_Value"; customLogonMsg[Tags.OnBehalfOfSubID] = "OnBehalfOfSubID_Value";
Dim customLogonMsg As New Message("A", FIXForge.NET.FIX.ProtocolVersion.FIX42) customLogonMsg.Set(Tags.SenderSubID, "SenderSubID_Value") customLogonMsg.Set(Tags.OnBehalfOfSubID, "OnBehalfOfSubID_Value")
"Invalid FIX Engine settings: Cannot open the persistent storage folder ('MsgStorage')" error (exception) when I try to run my FIX application as a Windows service? When I run my application as a standalone one, all work perfectly OK.SenderSubID,
TargetSubID,
SenderLocationID,
Session object.EngineException is thrown during the call of the
Error Reporting.