step协议
STEP(Securities trading exchange protocol )证券交易数据交换协议 ,规定了证券交易所交易系统与市场参与者系统之间进行证券交易所需的数据交换协议,规定了应用环境、会话机制、消息格式、安全与加密、数据完整性、扩展方式、消息定义、数据字典等内容。 具体内容参见:证券交易数据交换协议.pdf
quickfix
The Financial Information eXchange (FIX) protocol is a messaging standard developed specifically for the real-time electronic exchange of securities transactions. FIX is a public-domain specification owned and maintained by FIX Protocol, Ltd (FPL).
QuickFIX/J is a full featured messaging engine for the FIX protocol. It is a 100% Java open source implementation of the popular C++ QuickFIX engine.
参见网站https://www.quickfixj.org//
映射工具
需要将如下内容映射到quickfixj对应的message,和将message映射成tag串,如将如下tag串转成message
"8=FIX.5.0\0019=23\00135=D\0011180=010\00111=A0000001\00140=2\00154=1\001522=1\00160=2013022" +
"8-14:42:13\00148=000001\00122=102\001453=3\001448=000100\0014" +
"47=C\001452=1\001448=0100004698\001447=5\001452=5\001448=AA\001" +
"447=D\001452=4001\00138=1200.00\00144=17.4800\001544=1\001";
对应的工具代码如下:
package com.haiyi.tca.exchange.util.step;
import com.google.common.collect.Lists;
import com.haiyi.tca.exchange.model.exception.ExchangeRunTimeException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import quickfix.*;
import quickfix.field.BeginString;
import quickfix.field.CheckSum;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
/**
* @author: yujiakui
* @description: STEP tag消息到fix message对应的映射工具
* @date: 2018/7/14
* @Time: 上午8:59
*/
@Slf4j
public class StepTag2MsgUtil {
/**
* fix消息分割符号
*/
private static final char FIELD_SEPARATOR = '\001';
/**
* 会话数据字典路径
*/
private static final String SESSSION_DATA_DIC_PATH ;
// private static final String SESSSION_DATA_DIC_PATH = "D:\\workProject\\i2-tca-exchange\\i2-tca-exchange-biz\\src\\main\\resources\\quickfixj\\FIXT11.xml";
/**
* 应用程序数据字典路径
*/
private static final String APP_DATA_DIC_PATH ;
// private static final String APP_DATA_DIC_PATH = "D:\\workProject\\i2-tca-exchange\\i2-tca-exchange-biz\\src\\main\\resources\\quickfixj\\quickfixj-app.xml";
/**
* 消息工厂类
*/
public static MessageFactory messageFactory = new DefaultMessageFactory();
/**
* 会话数据字典
*/
public static DataDictionary sessionDataDictionary = null;
/**
* 应用数据字典
*/
public static DataDictionary appDataDictionary = null;
static {
try {
SESSSION_DATA_DIC_PATH = Class.class.getResource("/quickfixj/FIXT11.xml").getPath();
APP_DATA_DIC_PATH = Class.class.getResource("/quickfixj/quickfix-sse.xml").getPath();
sessionDataDictionary = new DataDictionary(SESSSION_DATA_DIC_PATH);
appDataDictionary = new DataDictionary(APP_DATA_DIC_PATH);
} catch (ConfigError configError) {
log.error("数据字典配置错误{}", configError);
throw new ExchangeRunTimeException("数据字典配置错误", configError);
}
}
/**
* tag 字符串转化为Message
*
* @param tagStr
* @return
*/
public static Message stepTag2Msg(String tagStr) throws InvalidMessage,
ConfigError, NoSuchMethodException,
IllegalAccessException, InvocationTargetException {
String beginString = MessageUtils.getStringField(tagStr
, BeginString.FIELD);
String tempTagStr = tagStr;
if (null == beginString) {
beginString = FixVersions.FIX50;
tempTagStr = BeginString.FIELD + "=" +
beginString + FIELD_SEPARATOR + tagStr;
}
String msgType = MessageUtils.getMessageType(tagStr);
String checkSumStr = MessageUtils.getStringField(tagStr, CheckSum.FIELD);
if (null == checkSumStr) {
String tempCheckTagStr = tempTagStr + CheckSum.FIELD + "=" + 0 + FIELD_SEPARATOR;
int checkSum = MessageUtils.checksum(tempCheckTagStr);
tempTagStr = tempTagStr + CheckSum.FIELD + "=" + checkSum + FIELD_SEPARATOR;
}
final quickfix.Message message = messageFactory.create(beginString, msgType);
message.fromString(tempTagStr,sessionDataDictionary,appDataDictionary,appDataDictionary!=null);
return message;
}
/**
* message 转为tagStr
*
* @param message
* @return
*/
public static String msg2TagStr(Message message) {
return msg2TagStr(message, null);
}
/**
* 根据应用字段对消息进行校验
*
* @param message
*/
private static void msgValidateByDataDict(Message message) {
try {
appDataDictionary.validate(message, true);
} catch (IncorrectTagValue incorrectTagValue) {
log.error("tag值不正确{}", incorrectTagValue);
throw new ExchangeRunTimeException("tag值不正确", incorrectTagValue);
} catch (FieldNotFound fieldNotFound) {
log.error("字段找不到{}", fieldNotFound);
throw new ExchangeRunTimeException("字段找不到", fieldNotFound);
} catch (IncorrectDataFormat incorrectDataFormat) {
log.error("数据格式不正确{}", incorrectDataFormat);
throw new ExchangeRunTimeException("数据格式不正确", incorrectDataFormat);
}
}
/**
* message 转为tagStr
*
* @param message
* @param removeTagLists
* @return
*/
public static String msg2TagStr(Message message, List<Integer> removeTagLists) {
// 消息校验
msgValidateByDataDict(message);
List<Integer> removeTags = Lists.newArrayList();
if(removeTagLists!=null){
removeTags = Lists.newArrayList(removeTagLists);
}
if (!message.getHeader().isSetField(BeginString.FIELD)) {
message.getHeader().setField(new BeginString(FixVersions.FIX50));
removeTags.add(BeginString.FIELD);
}
if (!message.getTrailer().isSetField(CheckSum.FIELD)) {
message.getTrailer().setField(new CheckSum("0"));
removeTags.add(CheckSum.FIELD);
}
String tagStr = message.toString();
return removeTagsFromStr(tagStr, removeTags);
}
/**
* 移除tag对应的列表
*
* @param sourceTagStr
* @param removeTags
* @return
*/
private static String removeTagsFromStr(String sourceTagStr, List<Integer> removeTags) {
if (CollectionUtils.isEmpty(removeTags)) {
return sourceTagStr;
}
StringBuilder resultStringBuilder = new StringBuilder(sourceTagStr);
for (Integer tag : removeTags) {
int tagIndex = resultStringBuilder.indexOf(tag + "=");
int tagValueEndIndex = resultStringBuilder.indexOf(String.valueOf(FIELD_SEPARATOR), tagIndex + 2);
resultStringBuilder.delete(tagIndex, tagValueEndIndex + 1);
}
return resultStringBuilder.toString();
}
public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException, InvalidMessage, ConfigError {
String tagStr = "8=FIX.5.0\0019=23\00135=D\0011180=010\00111=A0000001\00140=2\00154=1\001522=1\00160=2013022" +
"8-14:42:13\00148=000001\00122=102\001453=3\001448=000100\0014" +
"47=C\001452=1\001448=0100004698\001447=5\001452=5\001448=AA\001" +
"447=D\001452=4001\00138=1200.00\00144=17.4800\001544=1\001";
int index = tagStr.indexOf("\001");
System.out.println("index=" + index);
String result = String.valueOf(FIELD_SEPARATOR);
System.out.println(String.valueOf(FIELD_SEPARATOR));
//String replaceResult = tagStr.replaceAll("\\001", String.valueOf(FIELD_SEPARATOR));
System.out.println("=======>=====");
index = tagStr.indexOf(FIELD_SEPARATOR);
System.out.println("index1=" + index);
System.out.println(tagStr);
Message message = stepTag2Msg(tagStr);
System.out.println(message);
String tagStrResult = msg2TagStr(message, Lists.<Integer>newArrayList(8, 10));
System.out.println("-------------------------------");
System.out.println(tagStrResult);
}
}