OnixS C++ FIX Engine  3.25.0
API Documentation
CME Specific Settings

Session Settings

Option to specify the LastMsgSeqNumProcessed (tag 369) field, on every message sent. This is the required tag for the CME iLink system, so the option should be true.

Option to turn on/off the alternative algorithm of the resend logic, which is compatible with the CME Enhanced Resend Logic. CME highly recommends using this logic, so the option should be true.

Option to set the maximum number of messages to be requested in one Resend Request (MsgType=2) message. For all resend requests, CME requires that the client system request the maximum limit of 2500 messages.

By default, the FIX Engine disconnects the session when the "Session Level Reject" message is received in reply on the "Resend Request" message. However, CME services (e.g. Drop Copy) send the "Session Level Reject" message in some cases, in which the session should not be disconnected. Therefore, in such cases, the option should be true.

Migration to MSGW

CME MSGW does not require any new functionalities from the FIX Engine. There is only one main change on the application level. For MSGW, if you want to trade two different products on different Market Segment Gateways, then you need to create two FIX sessions with the same SenderCompId, SenderSubId and TargetCompId, but with different TargetSubId in accordance with the particular Market Segment Gateway. After that, FIX sessions need to be connected to the corresponding IP address and port of the particular Market Segment Gateway. With the old CGW you could do it by the one FIX session.

Note
In order to create two FIX sessions with the same SenderCompId and TargetCompId, you should use the constructor with the additional customSessionKey parameter.

Secure Logon

CME Globex implemented secure authentication for iLink and Drop Copy sessions on Convenience Gateway (CGW) and Market Segment Gateway (MSGW). The new logon procedure secures the client system logon with:

Customers must create secure key pairs for iLink and Drop Copy Sessions in the CME Customer Center.

CME Secure Logon requires to add several specific tags to Logon message, so our FIX Engine is ready to implement Secure Logon procedure. We have updated our CME Trading Client sample to help implementing Secure Logon.

Implementing Secure Logon consist of two parts:

  1. Creating canonical request string.
  2. Calculating HMAC.

Canonical request string is just a union of several tags from Logon message. Please note, that Session fills values of some fields like SendingTime right before message send, so its values can be taken from onOutboundSessionMsg callback.

There are the following functions that can help to produce required tag values:

The client system should send a keyed-hash message authentication code (HMAC) generated from the combination of the Logon FIX tag values. When CME receives the Logon message, it uses the identical inputs to calculate the HMAC value to validate against the Logon request. If values do not match, CME rejects the Logon.

The detailed description of the CME Secure Logon procedure can be found on the CME Globex API Secure Logon page.

Secure Logon Implementation Example

The sample below demonstrates basics of implementing CME Secure Logon.

void onOutboundSessionMsg(Message& msg, Session* session)
{
if (OnixS::FIX::FIX42::Values::MsgType::Logon != msg.type())
return;
if (accessKeyId_.empty() || secretKey_.empty())
return;
msg.set(OnixS::FIX::FIX42::Tags::EncodedTextLen, static_cast<int>(accessKeyId_.length()));
msg.set(OnixS::FIX::FIX42::Tags::EncodedText, accessKeyId_);
msg.set(CME::Tags::EncryptedPasswordMethodTag, "CME-1-SHA-256");
msg.erase(OnixS::FIX::FIX42::Tags::EncryptMethod);
std::string hash = calculateHmac(createCanonicalRequest(*session, msg));
msg.set(CME::Tags::EncryptedPasswordTag, hash);
msg.set(CME::Tags::EncryptedPasswordLenTag, static_cast<int>(hash.size()));
}
std::string createCanonicalRequest(const OnixS::FIX::Session& session, const OnixS::FIX::Message& msg)
{
const char delimiter = '\n';
const Timestamp sendingTime = msg.getTimestamp(FIX42::Tags::SendingTime);
std::stringstream ss;
ss << session.outSeqNum() << delimiter
<< msg.senderCompId().toStringRef() << delimiter
<< session.senderSubId() << delimiter
<< sendingTime.toString(TimestampFormat::YYYYMMDDHHMMSSMsec) << delimiter
<< session.targetSubId() << delimiter
<< session.heartbeatIntervalSec() << delimiter
<< session.senderLocationId() << delimiter
<< msg.getInt32(FIX42::Tags::LastMsgSeqNumProcessed) << delimiter
<< msg.getStringRef(CME::Tags::TradingSystemNameTag) << delimiter
<< msg.getStringRef(CME::Tags::TradingSystemVersionTag) << delimiter
<< msg.getStringRef(CME::Tags::TradingSystemVendorTag);
return ss.str();
}
std::string calculateHmac(const std::string& data)
{
using namespace OnixS::Cryptography;
ByteArray key;
Base64Encoding::decodeUrl(key, secretKey_);
ByteArray hmac;
return Base64Encoding::encodeUrl(hmac.data(), hmac.size());
}