quickFix Java Demo

来源:互联网 发布:js 函数对象的构造函数 编辑:程序博客网 时间:2024/05/16 16:14

废话少说,开撸!

依赖包:
log4j-1.2.16.jar
quickFix/*.jar
quickFix/lib/*.jar

quickFix包官网链接:http://www.quickfixj.org/downloads/

项目结构:注意log4j配置直接放在项目根目录,而不是src目录

<YOUR_APP>\    |--log4j.properties    |--src\        |--quickfix-server.properties        |--com.<YOUR_COMPANY>\            |--FIXServer.java            +--FixServerApplication.java

本文原文地址:http://blog.csdn.net/caib1109/article/details/76145264

//FIXServer.javapackage com.paic.quickfix;import java.net.InetSocketAddress;import java.util.ArrayList;import java.util.HashMap;import java.util.Iterator;import java.util.List;import java.util.Map;import org.apache.log4j.PropertyConfigurator;import quickfix.Application;import quickfix.ConfigError;import quickfix.DefaultMessageFactory;import quickfix.FieldConvertError;import quickfix.FileLogFactory;import quickfix.FileStoreFactory;import quickfix.LogFactory;import quickfix.MessageFactory;import quickfix.MessageStoreFactory;import quickfix.RuntimeError;import quickfix.SessionID;import quickfix.SessionSettings;import quickfix.ThreadedSocketAcceptor;import quickfix.mina.acceptor.DynamicAcceptorSessionProvider;import quickfix.mina.acceptor.DynamicAcceptorSessionProvider.TemplateMapping;/** * 服务启动主类(线程) *  * @author FLY.ZHANG */public class FIXServer {    private static ThreadedSocketAcceptor acceptor = null;    private static final String SETTING_ACCEPTOR_TEMPLATE = "AcceptorTemplate";    private static final String SETTING_SOCKET_ACCEPT_ADDRESS = "SocketAcceptAddress";    private static final String SETTING_SOCKET_ACCEPT_PORT = "SocketAcceptPort";    public static ThreadedSocketAcceptor getAcceptor() {        return acceptor;    }    private final Map<InetSocketAddress, List<TemplateMapping>> dynamicSessionMappings = new HashMap<InetSocketAddress, List<TemplateMapping>>();    public Map<InetSocketAddress, List<TemplateMapping>> getDynamicSessionMappings() {        return dynamicSessionMappings;    }    /**     * 指定配置文件启动     *      * @param propFile     * @throws ConfigError     * @throws FieldConvertError     */    public FIXServer(String propFile) throws ConfigError, FieldConvertError {        // 设置配置文件        SessionSettings settings = new SessionSettings(propFile);        // 设置一个APPlication        Application application = new FixServerApplication();        /**         *          * quickfix.MessageStore 有2种实现。 quickfix.JdbcStore,quickfix.FileStore .         * JdbcStoreFactory 负责创建JdbcStore , FileStoreFactory 负责创建FileStorequickfix         * 默认用文件存储,因为文件存储效率高。         */        MessageStoreFactory storeFactory = new FileStoreFactory(settings);        LogFactory logFactory = new FileLogFactory(settings);        MessageFactory messageFactory = new DefaultMessageFactory();        acceptor = new ThreadedSocketAcceptor(application, storeFactory, settings, logFactory, messageFactory);        configureDynamicSessions(settings, application, storeFactory, logFactory, messageFactory);    }    private void startServer() throws RuntimeError, ConfigError {        acceptor.start();    }    public void stop() {        acceptor.stop();    }    /**     * 被调用的start方法     *      * @throws ConfigError     * @throws FieldConvertError     */    public static void start() throws ConfigError, FieldConvertError {        FIXServer servercom = new FIXServer("quickfix-server.properties");        servercom.startServer();    }    /**     * 测试本地使用的main方法     *      * @param args     * @throws FieldConvertError     * @throws ConfigError     * @throws ProxoolException     */    public static void main(String[] args) throws ConfigError, FieldConvertError {        // 配置LOG日记        PropertyConfigurator.configure("log4j.properties");        FIXServer fixServer = new FIXServer("quickfix-server.properties");        fixServer.startServer();    }    /**     *      * 以下几个方法是配置动态SessionProvider FIX 支持同时支持不同的SessionTemple,使用不同的数据处理Provider     * 体现在配置文件中的[session]标签     *      * @param settings     * @param application     * @param messageStoreFactory     * @param logFactory     * @param messageFactory     * @throws ConfigError     * @throws FieldConvertError     */    private void configureDynamicSessions(SessionSettings settings, Application application,            MessageStoreFactory messageStoreFactory, LogFactory logFactory, MessageFactory messageFactory)            throws ConfigError, FieldConvertError {        // 获取配置文件中的[session]标签集合        Iterator<SessionID> sectionIterator = settings.sectionIterator();        while (sectionIterator.hasNext()) {            SessionID sessionID = sectionIterator.next();            if (isSessionTemplate(settings, sessionID)) {                // 判断是否使用了AcceptorTemplate                InetSocketAddress address = getAcceptorSocketAddress(settings, sessionID);                getMappings(address).add(new TemplateMapping(sessionID, sessionID));            }        }        for (Map.Entry<InetSocketAddress, List<TemplateMapping>> entry : dynamicSessionMappings.entrySet()) {            acceptor.setSessionProvider(entry.getKey(), new DynamicAcceptorSessionProvider(settings, entry.getValue(),                    application, messageStoreFactory, logFactory, messageFactory));        }    }    private boolean isSessionTemplate(SessionSettings settings, SessionID sessionID)            throws ConfigError, FieldConvertError {        return settings.isSetting(sessionID, SETTING_ACCEPTOR_TEMPLATE)                && settings.getBool(sessionID, SETTING_ACCEPTOR_TEMPLATE);    }    private List<TemplateMapping> getMappings(InetSocketAddress address) {        List<TemplateMapping> mappings = dynamicSessionMappings.get(address);        if (mappings == null) {            mappings = new ArrayList<TemplateMapping>();            dynamicSessionMappings.put(address, mappings);        }        return mappings;    }    private InetSocketAddress getAcceptorSocketAddress(SessionSettings settings, SessionID sessionID)            throws ConfigError, FieldConvertError {        String acceptorHost = "0.0.0.0";        if (settings.isSetting(sessionID, SETTING_SOCKET_ACCEPT_ADDRESS)) {            acceptorHost = settings.getString(sessionID, SETTING_SOCKET_ACCEPT_ADDRESS);        }        int acceptorPort = (int) settings.getLong(sessionID, SETTING_SOCKET_ACCEPT_PORT);        InetSocketAddress address = new InetSocketAddress(acceptorHost, acceptorPort);        return address;    }}
package com.paic.quickfix;import quickfix.Application;import quickfix.DoNotSend;import quickfix.FieldNotFound;import quickfix.IncorrectDataFormat;import quickfix.IncorrectTagValue;import quickfix.Message;import quickfix.MessageCracker;import quickfix.RejectLogon;import quickfix.Session;import quickfix.SessionID;import quickfix.UnsupportedMessageType;import quickfix.field.MsgType;/** * /** *  * MessageCracker是一个工具类,通过继承MessageCracker可以覆盖onMessage方法 * 通过调用crack回调onMessage中的业务逻辑。所以所有的业务逻辑可以直接写在onMessage 方法中。 *  *     *  *      onCreate –>当一个Fix Session建立是调用 *  *      onLogon –>当一个Fix Session登录成功时候调用 *       *      onLogout –>当一个Fix Session退出时候调用 *       *      fromAdmin–>当收到一个消息,经过一系列检查,合格后,属于Admin 类型时候调用 *       *      fromApp–>当收到一个消息,经过一系列检查,合格后,不属于Admin 类型时候调用 *       *      toAdmin–>当发送一个admin类型消息调用toApp—>当发送一个非admin(业务类型)消息调用 *  * * @author CAISHUXIAO719 * */public class FixServerApplication extends MessageCracker implements Application {    @Override    protected void onMessage(Message message, SessionID sessionID) {        try {            System.out.println("业务逻辑实现统一写在此方法中");            String msgType = message.getHeader().getString(35);            Session session = Session.lookupSession(sessionID);            System.out.println("服务器接收到用户信息订阅==" + msgType);            switch (msgType) {            case MsgType.LOGON: // 登陆                session.logon();                session.sentLogon();                break;            case MsgType.HEARTBEAT: // 心跳                session.generateHeartbeat();                break;            }        } catch (FieldNotFound e) {            e.printStackTrace();        }    }    @Override    public void onCreate(SessionID sessionId) {        System.out.println(" 服务器启动时候调用此方法创建");    }    @Override    public void onLogon(SessionID sessionId) {        System.out.println("客户端登陆成功时候调用此方法");    }    @Override    public void onLogout(SessionID sessionId) {        System.out.println("客户端断开连接时候调用此方法");    }    @Override    public void toAdmin(Message message, SessionID sessionId) {        System.out.println("发送会话消息时候调用此方法");    }    @Override    public void toApp(Message message, SessionID sessionId) throws DoNotSend {        System.out.println("发送业务消息时候调用此方法");    }    @Override    public void fromAdmin(Message message, SessionID sessionId)            throws FieldNotFound, IncorrectDataFormat, IncorrectTagValue, RejectLogon {        System.out.println("接收会话类型消息时调用此方法");        try {            crack(message, sessionId);        } catch (UnsupportedMessageType | FieldNotFound | IncorrectTagValue e) {            e.printStackTrace();        }    }    @Override    public void fromApp(Message message, SessionID sessionId)            throws FieldNotFound, IncorrectDataFormat, IncorrectTagValue, UnsupportedMessageType {        System.out.println("接收业务消息时调用此方法");        crack(message, sessionId);    }}
#quickfix-server.properties[default]SocketAcceptAddress=127.0.0.1SocketAcceptPort=9880FileStorePath=conf/target/data/storeFileLogPath=conf/target/data/logConnectionType=acceptorSenderCompID=FILZHANGTargetCompID=*StartTime=00:00:00EndTime=00:00:00HeartBtInt=30ValidOrderTypes=1,2,FValidOrderSymbol=CNY,USDUseDataDictionary=YDataDictionary=quickfix/FIX44.xmlTimeZone=Asia/ChongqingResetOnLogon=YResetOnLogout=YResetOnDisconnect=YResetOnError=Y[session]AcceptorTemplate=YBeginString=FIX.4.4
#file name: log4j.propertiesapp.log.home=/wls/apache/applogs/Pagi_qerapp.name=PAGI-QERlog4j.appender.CONSOLE=org.apache.log4j.ConsoleAppenderlog4j.appender.CONSOLE.Threshold=INFOlog4j.appender.CONSOLE.Encoding=UTF-8log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayoutlog4j.appender.CONSOLE.layout.ConversionPattern=[%d{yyyy-MM-dd HH\:mm\:ss\:SSS} [%p]][${app.name}] %X{module}-%X{random}: %m%nlog4j.appender.PRODUCT=org.apache.log4j.DailyRollingFileAppenderlog4j.appender.PRODUCT.Append=truelog4j.appender.PRODUCT.DatePattern='.'yyyy-MM-ddlog4j.appender.PRODUCT.File=${app.log.home}/info.loglog4j.appender.PRODUCT.Threshold=INFOlog4j.appender.PRODUCT.Encoding=UTF-8log4j.appender.PRODUCT.layout=org.apache.log4j.PatternLayoutlog4j.appender.PRODUCT.layout.ConversionPattern=[%d{yyyy-MM-dd HH\:mm\:ss\:SSS} [%p]][${app.name}] %X{module}-%X{random}: %m%nlog4j.appender.PRODUCT-ERROR=org.apache.log4j.DailyRollingFileAppenderlog4j.appender.PRODUCT-ERROR.Append=truelog4j.appender.PRODUCT-ERROR.DatePattern='.'yyyy-MM-ddlog4j.appender.PRODUCT-ERROR.File=${app.log.home}/error.loglog4j.appender.PRODUCT-ERROR.Threshold=ERRORlog4j.appender.PRODUCT-ERROR.Encoding=UTF-8log4j.appender.PRODUCT-ERROR.layout=org.apache.log4j.PatternLayoutlog4j.appender.PRODUCT-ERROR.layout.ConversionPattern=[%d{yyyy-MM-dd HH\:mm\:ss\:SSS} [%p]][${app.name}] %X{module}-%X{random}: %m%nlog4j.logger.org.hibernate=INFOlog4j.logger.org.hibernate.SQL=tracelog4j.logger.org.hibernate.HQL=tracelog4j.category.org.hibernate.type=tracelog4j.logger.org.springframework=INFOlog4j.rootLogger=INFO, CONSOLE ,PRODUCT,PRODUCT-ERROR

适应度测试(Accept Test)

To run the acceptance tests:
1) open Eclipse,
2) right-click on the quickfix.test.acceptance.AcceptanceTestSuite class and select the “Run as… -> JUnit Test” option.

This will start an acceptance test program with an embedded QuickFIX/J server, load the AT definition files and convert them to JUnit tests, and run those tests in the embedded JUnit test view.

Writing your own Acceptance Test Scripts

Below is an example of a test script that tests the engines behavior when it receives a NewSeqNo value that is less than the expected MsgSeqNum.

  iCONNECT  I8=FIX.4.235=A34=149=TW52=<time>56=ISLD98=0108=30  E8=FIX.4.29=5735=A34=149=ISLD52=00000000-00:00:0056=TW98=0108=3010=0  # sequence reset without gap fill flag (default to N)  I8=FIX.4.235=434=049=TW52=<time>56=ISLD36=1  E8=FIX.4.29=11235=334=249=ISLD52=00000000-00:00:0056=TW45=058=Value is incorrect (out of range) for this tag372=4373=510=0  I8=FIX.4.235=134=249=TW52=<time>56=ISLD112=HELLO  E8=FIX.4.29=5535=034=349=ISLD52=00000000-00:00:0056=TW112=HELLO10=0  # sequence reset without gap fill flag (default to N)  I8=FIX.4.235=434=049=TW52=<time>56=ISLD36=1123=N  E8=FIX.4.29=11235=334=449=ISLD52=00000000-00:00:0056=TW45=058=Value is incorrect (out of range) for this tag372=4373=510=0  I8=FIX.4.235=134=349=TW52=<time>56=ISLD112=HELLO  E8=FIX.4.29=5535=034=549=ISLD52=00000000-00:00:0056=TW112=HELLO10=0  iDISCONNECT

In these script there are two types of commands, action commands and messages commands. Action commands begin with lowercase letters while message command begin with uppercase letters.
Action Commands

i - initiates an action
e - expect (wait for) an action

Supported actions are:

iCONNECT - initiate connection to a FIX acceptor
eCONNECT - expect a connection from a FIX initiator
iDISCONNECT - initiate a disconnect
eDISCONNECT - expect a disconnect

Message Commands

I - initiate (send) a message
E - expect (wait for) a message

When using the I command, you do not need to add the Length(9) or the CheckSum(10) fields, they will be added for you with the correct values in the appropriate locations. The only time you would add these fields is if you intentionally wish to make them incorrect.

The I command also provides a TIME macros for fields. By setting a field equal to

股票交易指令的 TIF(Time in Force)

DAY 此单当天有效
IOC immediate or cancel
GTC 此单将一直有效,除非取消;
GTD 到点前有效
GAT 到点后有效
GTX
OPG
GTM Good This Month

股票交易指令的四种形式

市价指令(Market Order)
限价指令(Limit Order)
止损指令(Stop Order)
止损限价指令(Stop Limit Order)

其中,前两种指令多用于现货市场,而后两种指令多用于期货和期权市场。

拓展阅读
[1] Time in Force. 投资百科网. http://www.investopedia.com/terms/t/timeinforce.asp