[Banking-pm] FIX: Financial Information eXchange

Holzman, Benjamin BHolzman at iseoptions.com
Sun Dec 3 09:44:29 PST 2006


You're welcome!  I have to say that I don't quite understand why you'd want to use FIX for logging or IPC.  The protocol layer of FIX has some pretty complicated retransmission logic and although it's not as bad as XML, it's not a very compact format.  Recovering from a sequence number mismatch between the two sides of a FIX connection can be a real headache.
 
However, to answer your other questions, it is possible to deal with arbitrary FIX messages, but not if they have repeating groups.  It would be very painful to try to encode all your data without using repeating groups, so I don't think that helps you.  The syntax of FIX is really fairly simplistic.  It's either a simple tag => value or it's a repeating group.  Repeating groups can be nested, although the code I pasted below won't quite handle this case.  Repeating groups always have a starting tag that represents the count of elements in the group.  Confusingly, the FIX documentation always uses the prefix "No" for number in the mnemonic (e.g., NoCounterParties, which means "number of counter parties", not that there are no counter parties).  Anyway, following the starting tag, there's the contents of the repeating group, one instance after another, as tag => value pairs (or nested repeating groups).  Without telling the parser which tags start repeating groups, and what the contents of the repeating group will be, there can be parsing ambiguities.  Note, also, the verbosity here; every tag gets duplicated for every instance of a repeating group.
 
I know the FIX protocol organization has been working on something called FAST (FIX Adapted for Streaming) that would resolve some of these issues, but I think it's still in the proof-of-concept phase.  Anyway, under that model, you would certainly need to describe your message structure in detail to both sides of the connection.
 
Hope that helps...
 
Ben

________________________________

From: Montgomery Conner [mailto:montgomery.conner at gmail.com]
Sent: Sat 12/2/2006 11:21 PM
To: Holzman, Benjamin
Cc: banking-pm at pm.org
Subject: Re: [Banking-pm] FIX: Financial Information eXchange


Thank you for you very complete response! 

A few questions...

There's been a lot of talk at my job about using FIX to standardize the application infrastructure (logging, some kinds of IPC, etc. ), in which case many of these tags would likely be in the range of FIX tags that are reserved for vendor communications and are thus undocumented/undefined.  For a case such as this, in your experience, is there any simple (yet robust) way respond to tags that have not been encountered before?  That is, do you think that such a parser might need a more complete grammar specification than a simple hash, or is FIX itself simple enough that certain default responses could be engineered for ranges of tags regardless of whether they already resided in a local specification hash? 



Thanks again, your insight has been very helpful,
Montgomery



On 12/2/06, Holzman, Benjamin < BHolzman at iseoptions.com <mailto:BHolzman at iseoptions.com> > wrote: 

	> I would have assumed that FIX is so large that any generic 
	> implementation of it is likely to be incomplete.
	
	Yes and no, I think.  My experience with FIX has been that the
	application-level messages tend to be domain-specific, but the
	protocol-level is quite stable.  I have built FIX interfaces to allow 
	order entry and market data for our parimutuel matching engine.  I did
	it using the quickfix open source FIX engine (actually C++ libraries) to
	handle the protocol and wrote a minimal C++ bridge that shuttles FIX 
	application messages back and forth to a perl process over a socket.
	
	I then parse the FIX messages in perl with a custom FixMessage base
	class, run all of my application logic there, creating FixMessage
	objects as responses and then turn them back into a string to send back 
	to the C++ bridge.  I store the FIX messages as a hash mapping the fix
	tag number to the value.  I then have accessor methods named after the
	mnemonic for each tag number.  I actually just have a hash (%tagMapping) 
	in my base class with the mapping and use an AUTOLOAD to create the
	accessors on demand.  Parsing the FIX message is as simple as this code:
	
	
	    sub fromString {
	        my $string = shift;
	
	        my($class, %tags); 
	        foreach my $field (split /\001/, $string) {
	          my($tag, $value) = split /=/, $field, 2;
	          if ($tag == $tagMapping{'MsgType'}) {
	            $class = $msgType_2_class{$value};
	            next; 
	          }
	
	          next if defined $isHeaderTag{$tag};
	
	          $tags{$tag} = $value;
	        }
	
	        return $class->new(\%tags);
	    }
	
	I have sub-classes of FixMessage for each MsgType that I handle; the 
	%msgType_2_class hash has the mapping.
	
	Actually, there's an additional complication to handle repeating groups;
	the value of a repeating group is an array ref with one element for each
	instance of the group; because tag order in repeating groups matters, 
	each instance is represented with an array consisting of tag
	number/value pairs.  Something like this: [ [ 42 => 'value', 165 =>
	'another value' ], [ 42 => 'value2', 165 => 'yet another' ], ... ].  So 
	my actual fromString function has more logic to handle this.
	
	Anyway, converting an object back to a string isn't too hard; the only
	tricky parts are including the body length in the header and computing
	the checksum for the trailer.  My code looks like this: 
	
	    sub toString {
	        my $this = shift;
	
	        my $header = "8=FIX.4.4\0019=";
	        my $body = join("\001", "35=$class_2_msgType{ref $this}",
	                         map _toString($_, $this->{$_}), keys %$this) . 
	"\001";
	
	        my $msg = $header . length($body) . "\001$body";
	
	        my $cksum = 0;
	        $cksum += ord($_) for split //, $msg;
	
	        $cksum = sprintf "%03d", $cksum %256; 
	
	        return $msg . "10=$cksum\001";
	    }
	
	    sub _toString {
	        my($key, $value) = @_;
	        if (ref $value eq 'ARRAY') {
	          return unless @$value;
	
	          return join "\001", 
	                        "$key=" . @$value,
	                        map { my $val = $_;
	                                my @data;
	                                for (my $i = 0; $i < $#$val; $i+=2) { 
	                                  push @data, "$tagMapping{$val->[$i]}="
	.
	                                                  $val->[$i + 1];
	                                }
	                                @data; 
	                            } @$value;
	        } elsif ($value ne '') {
	          return "$key=$value";
	        } else {
	          return;
	        }
	    }
	
	That's pretty much my whole FIX message base class.  The constructor 
	allows objects to be constructed from a string or from tag mnemonic =>
	value pairs.
	
	I don't know if this helps you, but at least you see how simple it is to
	handle parsing and generation of FIX messages. 
	
	Benjamin Holzman
	


-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.pm.org/pipermail/banking-pm/attachments/20061203/ff318292/attachment-0001.html 


More information about the Banking-pm mailing list