// ==========================================================================
// Author: Yee Hsu
// Date: 9/30/2013
// File: FixString.cpp
//
// Desc: An implementation of the FIX protocol. The FixString class allows
// you to create a FIX string that is exchange compatible according
// to the standards as describe in the FIX protocol. FIX is use to
// communicate between institutions, brokers/dealers, and exchange
// for financial interchange to help facilitate market orders. This
// particular implementation is very fast and is suitable to plug
// into any FIX engine for Ultra-Low Latency Direct-to-Market Orders
// ==========================================================================
#include "StdAfx.h"
#include "FixString.h"
namespace FixEngine
{
FixString::FixString()
: m_fixvec(), m_fixmap()
{
memset(m_fixstr, 0, sizeof(m_fixstr));
}
FixString::~FixString(void)
{}
void FixString::BeginFix( const String& msgtype, const String& senderCompId, const String& targetCompId, const String& applVerId )
{
m_fixvec.clear();
m_fixmap.clear();
SetTag(TAG_BEGIN_STRING, FIX_VERSION_5_0);
SetTag(TAG_BODY_LENGTH, 0);
SetTag(TAG_MESSAGE_TYPE, msgtype);
SetTag(TAG_SENDER_COMP_ID, senderCompId);
SetTag(TAG_TARGET_COMP_ID, targetCompId);
if (!applVerId.empty())
SetTag(TAG_APPLICATION_VERSION_ID, applVerId);
}
void FixString::SetTag( FixTag tag, const String& value )
{
if (m_fixmap.find(tag) == m_fixmap.end())
{
m_fixmap.insert(std::make_pair(tag, value));
m_fixvec.push_back(tag);
}
else
{
m_fixmap[tag] = value;
}
}
void FixString::SetTag( FixTag tag, int value )
{
char buffer[32] = {0};
sprintf(buffer, "%d", value);
SetTag(tag, buffer);
}
void FixString::SetTag( FixTag tag, float value )
{
char buffer[32] = {0};
sprintf(buffer, "%f", value);
SetTag(tag, buffer);
}
void FixString::EndFix()
{
int offset = 0;
// calculate and set body length
// 2nd element is always tag/value pair after TAG_BODY_LENGTH
// assume TAG_CHECKSUM has not been added into the struct, so we can sum up the length
char body[FIX_MAX_STR_LEN] = {0};
for (size_t i = 2; i < m_fixvec.size(); i++)
{
String str;
FixTag tag = m_fixvec[i];
if (GetFixValuebyTag(tag, str))
offset += sprintf(body + offset, "%d=%s%c", tag, str.c_str(), FIX_SOH_DELIMITER);
}
int len = strlen(body);
SetTag(TAG_BODY_LENGTH, len);
// combine head + body with the calculated length
memset(m_fixstr, 0, sizeof(m_fixstr));
offset = sprintf(m_fixstr, "8=%s%c9=%d%c%s",
GetFixValuebyTagFast(TAG_BEGIN_STRING), FIX_SOH_DELIMITER,
len, FIX_SOH_DELIMITER, body);
long buflen = strlen(m_fixstr);
// calculate and set checksum
unsigned int cks = 0;
for( int idx = 0; idx < buflen; cks += (unsigned int) m_fixstr[idx++] );
sprintf( m_fixstr + offset, "10=%03d%c", (unsigned int)( cks % 256 ), FIX_SOH_DELIMITER);
SetTag(TAG_CHECKSUM, (int)( cks % 256 ));
}
bool FixString::GetFixValuebyTag( FixTag tag, String& value )
{
value.clear();
if (m_fixmap.find(tag) != m_fixmap.end())
{
value = m_fixmap[tag];
return true;
}
return false;
}
const char* FixString::GetFixValuebyTagFast( FixTag tag )
{
return m_fixmap[tag].c_str();
}
}
// Belongs in another file...
int _tmain(int argc, _TCHAR* argv[])
{
FixString fs;
/*
// 8=FIX.4.2|9=42|35=0|49=A|56=B|34=12|52=20100304-07:59:30|10=185|
fs.BeginFix("0", "A", "B", "");
fs.SetTag(TAG_MESSAGE_SEQ_NUM, 12);
fs.SetTag(TAG_SENDING_TIME, "20100304-07:59:30");
fs.EndFix();
*/
// 8=FIX.4.2|9=65|35=A|49=SERVER|56=CLIENT|34=177|52=20090107-18:15:16|98=0|108=30|10=062|
fs.BeginFix("A", "SERVER", "CLIENT", "");
fs.SetTag(TAG_MESSAGE_SEQ_NUM, 177);
fs.SetTag(TAG_SENDING_TIME, "20090107-18:15:16");
fs.SetTag(TAG_ENCRYPTION_METHOD, 0);
fs.SetTag(TAG_HEARTBEAT_INTERVAL, 30);
fs.EndFix();
/*
// 8=FIX.4.2 | 9=178 | 35=8 | 49=PHLX | 56=PERS | 52=20071123-05:30:00.000 | 11=ATOMNOCCC9990900 | 20=3 | 150=E | 39=E | 55=MSFT | 167=CS | 54=1 | 38=15 | 40=2 | 44=15 | 58=PHLX EQUITY TESTING | 59=0 | 47=C | 32=0 | 31=0 | 151=15 | 14=0 | 6=0 | 10=128 |
fs.BeginFix("8", "PHLX", "PERS", "");
fs.SetTag(TAG_SENDING_TIME, "20071123-05:30:00.000");
fs.SetTag(TAG_CLIENT_ORDERID, "ATOMNOCCC9990900");
fs.SetTag(TAG_EXECUTION_TRANSACTION_TYPE, 3);
fs.SetTag(TAG_EXECUTION_TYPE, "E");
fs.SetTag(TAG_ORDER_STATUS, "E");
fs.SetTag(TAG_SYMBOL, "MSFT");
fs.SetTag(TAG_SECURITY_TYPE, "CS");
fs.SetTag(TAG_SIDE, 1);
fs.SetTag(TAG_ORDER_QTY, 15);
fs.SetTag(TAG_ORDER_TYPE, 2);
fs.SetTag(TAG_PRICE, 15);
fs.SetTag(TAG_FREE_TEXT, "PHLX EQUITY TESTING");
fs.SetTag(TAG_TIME_IN_FORCE, 0);
fs.SetTag(TAG_RULE_80A, "C");
fs.SetTag(TAG_LAST_QTY, 0);
fs.SetTag(TAG_LAST_PRICE, 0);
fs.SetTag(TAG_LEAVES_QTY, 15);
fs.SetTag(TAG_CUMMULATIVE_QTY, 0);
fs.SetTag(TAG_AVERAGE_PRICE, 0);
fs.EndFix();
*/
// In Linux, you can replace SOH char with pipe, display using
// $ ./a.out | tr '\1' '|'
//printf("%s", fs.GetFixStr());
// printf in human readable format
FixVec& fv = fs.GetFixVec();
printf("FixString:\n");
for (FixVec::iterator iter = fv.begin(); iter != fv.end(); ++iter)
printf("%5d : [%s]\n", *iter, fs.GetFixValuebyTagFast(*iter));
return 0;
}