[Banking-pm] FIX: Financial Information eXchange

Holzman, Benjamin BHolzman at iseoptions.com
Sat Dec 2 07:51:18 PST 2006


> 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


More information about the Banking-pm mailing list