java quickfix_QuickFix Java 讲解(三)客户端的搭建与解析

本系列力求手把手教你怎样利用 QuickFix Java 搭建自己的 FIX 协议收法平台,以及其中的注意事项。

所有源码的地址(免费):

这次我们讨论怎样搭建Initiator端。

4. Initiator 端的搭建

Initiator,也可以称作为 Client,就是分散在各个地方的交易机。业务员在上面操作以后,客户端会向服务器发送请求。请求多种多样,基本常用的有:行情请求(35=V),新建订单(35=D),撤销订单(35=F)。

搭建一个客户端非常的简单,只需要两个类:一个类负责初始化、启动和关停服务(起个名字叫FixInitiator);另一个类负责服务,即收发消息(起个名字叫FixInitiatorApplication)。

4.1. Property设置

Property在上一节已经做了大致讲解,在这里先贴上源码:

#quickfix-server.properties

[default]

# 这些字段记得改成你的设置

FileStorePath=fileStore

SocketConnectHost=10.176.125.79

SocketConnectPort=10003

TargetCompID=QUICKFIX_ACCEPTOR

# 以下字段可以不改

ConnectionType=initiator

HeartBtInt=30

ReconnectInterval=10

FileLogPath=log

UseDataDictionary=N

DataDictionary=src/main/resources/FIX44.modified.xml

ContinueInitializationOnError=Y

BeginString=FIX.4.4

StartTime=00:00:00

EndTime=23:00:00

ResetOnLogon=Y

ResetSeqNumFlag=Y

MaxMessagesInResendRequest=1

[session]

SenderCompID=QUICKFIX_INITIATOR1

[session]

SenderCompID=QUICKFIX_INITIATOR2

对于Initiator 来说,一定要写ConnectionType=initiator,否则在启动的时候会报错,因为对应的session setting 没有找到。

4.2. FixInitiator

这个类也是Initiator程序的主入口。除了标准化的startServer 和 stopServer,关键部分就是对SocketInitiator 的声明和初始化,初始化需要上面提到的property文件,如果没有的话会报错。

另外需要注意的是在quickfix 包 和quickfix.fix44 里有一些名字相同的包,不要导错了。有时候他们是extend 关系,编译不会报错,但是运行会突然报错。

package foo.zongzhe.quickfix.initiator;

import quickfix.*;

public class FixInitiator {

private static SocketInitiator initiator;

private static SessionSettings settings;

private static FixInitiatorApplication application;

public static SocketInitiator getInitiator() {

return initiator;

}

public FixInitiator() {

try {

settings = new SessionSettings("src/main/resources/quickfix.properties");

} catch (ConfigError configError) {

System.out.println("Warning: config error!" + configError);

}

application = new FixInitiatorApplication();

MessageStoreFactory storeFactory = new FileStoreFactory(settings);

LogFactory logFactory = new FileLogFactory(settings);

MessageFactory messageFactory = new DefaultMessageFactory(); // 不是quickfix.fix44.MessageFactory try {

initiator = new SocketInitiator(application, storeFactory, settings, logFactory, messageFactory);

} catch (ConfigError configError) {

System.out.println("Warning: config error! " + configError);

}

}

private void startServer() {

try {

initiator.start();

} catch (ConfigError configError) {

configError.printStackTrace();

}

}

private void stopServer() {

initiator.stop();

}

public static void main(String[] args) {

FixInitiator fixInitiator = new FixInitiator();

fixInitiator.startServer();

// 启动一个Session,记得参考你的quickfix.properties设定 SessionID sessionID = new SessionID("FIX.4.4", "QUICKFIX_INITIATOR1", "QUICKFIX_ACCEPTOR");

// 开始发点消息 try {

application.sendMarketDataRequest(sessionID);

Thread.sleep(5000);

application.sendNewOrderRequest(sessionID);

Thread.sleep(5000);

} catch (SessionNotFound | InterruptedException exception) {

exception.printStackTrace();

}

}

}

4.3. FixInitiatorApplication

这里就是用来收发消息、解析消息的具体服务类。一方面要extends MessageCracker, 用来解析消息。另一方面要 implements Application,用来收法消息。

一旦implements Application,就要实现固定的几个功能,里面可以什么也不写,打印输出,有个概念即可。

在extends MessageCracker后,可以重写onMessage方法,针对不同的消息做不同的本地化处理。

详见以下源码:

package foo.zongzhe.quickfix.initiator;

import quickfix.*;

import quickfix.field.*;

import quickfix.fix44.ExecutionReport;

import quickfix.fix44.MarketDataRequest;

import quickfix.fix44.MessageCracker;

import quickfix.fix44.NewOrderSingle;

import java.time.LocalDateTime;

public class FixInitiatorApplication extends MessageCracker implements Application {

// 以下是Application的固定七件套 @Override

public void onCreate(SessionID sessionId) {

System.out.println("onCreate is called");

}

@Override

public void onLogon(SessionID sessionId) {

System.out.println("onLogon is called");

}

@Override

public void onLogout(SessionID sessionId) {

System.out.println("onLogout is called");

}

@Override

public void toAdmin(Message message, SessionID sessionId) {

System.out.println("toAdmin is called");

}

@Override

public void fromAdmin(Message message, SessionID sessionId) throws FieldNotFound, IncorrectDataFormat, IncorrectTagValue, RejectLogon {

System.out.println("fromAdmin is called");

}

@Override

public void toApp(Message message, SessionID sessionId) throws DoNotSend {

System.out.println("toApp is called: " + message);

}

@Override

public void fromApp(Message message, SessionID sessionId) throws FieldNotFound, IncorrectDataFormat, IncorrectTagValue, UnsupportedMessageType {

System.out.println("fromApp is called");

}

// 以下是你可以自定义的消息接收器,来自MessageCracker @Override

public void onMessage(ExecutionReport message, SessionID sessionID) throws FieldNotFound, UnsupportedMessageType, IncorrectTagValue {

System.out.println("Received ExecutionReport: " + message + ", sessionID: " + sessionID);

// 收都收了,解析一下 System.out.println(String.format("clOrderID: %s, symbol: %s, side: %s",

message.getClOrdID().getValue(),

message.getSymbol().getValue(),

message.getSide().getValue()));

}

// 以下是发消息的功能

/*** 订阅行情消息** @param sessionID* @throws SessionNotFound*/

public void sendMarketDataRequest(SessionID sessionID) throws SessionNotFound {

// 具体set哪些字段,参考你的FIX44.modified.xml MarketDataRequest req = new MarketDataRequest();

req.set(new MDReqID("mockedMDReqID"));

req.set(new SubscriptionRequestType('1'));

// 重复组的设置 MarketDataRequest.NoRelatedSym symGroup1 = new MarketDataRequest.NoRelatedSym();

symGroup1.set(new Symbol("mockedSymbol1"));

req.addGroup(symGroup1);

MarketDataRequest.NoRelatedSym symGroup2 = new MarketDataRequest.NoRelatedSym();

symGroup2.set(new Symbol("mockedSymbol2"));

req.addGroup(symGroup2);

System.out.println("Sending MarketDataRequest");

Session.sendToTarget(req, sessionID);

}

/*** 下单* @param sessionID* @throws SessionNotFound*/

public void sendNewOrderRequest(SessionID sessionID) throws SessionNotFound {

NewOrderSingle order = new NewOrderSingle();

LocalDateTime date = LocalDateTime.now();

order.set(new ClOrdID("mockedClOrdID"));

order.set(new Account("mockedAccount"));

order.set(new HandlInst('1'));

order.set(new OrderQty(45.00));

order.set(new Price(25.88));

order.set(new Symbol("mockedSymbol"));

order.set(new Side(Side.BUY)); // 对于枚举型对象也可以这么设置 order.set(new OrdType(OrdType.LIMIT));

Session.sendToTarget(order, sessionID);

}

}

4.4. 运行及结果

运行以后,如果看到“onCreate is called”的字样,就说明已经通了,准备开始给服务器发消息了。

而“toApp is called” 标明你已经向服务器发送了消息,正在等回应。(注意上节文章说的要修改的配置,比如IP地址!)

下节讲怎么搭建服务器端,下课。

你可能感兴趣的:(java,quickfix)