/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.f1x.tools; import org.f1x.SessionIDBean; import org.f1x.api.FixAcceptorSettings; import org.f1x.api.FixVersion; import org.f1x.api.message.MessageBuilder; import org.f1x.api.message.MessageParser; import org.f1x.api.message.Tools; import org.f1x.api.message.fields.*; import org.f1x.api.message.types.ByteEnumLookup; import org.f1x.api.session.SessionID; import org.f1x.api.session.SessionStatus; import org.f1x.util.ByteArrayReference; import org.f1x.v1.FixSessionAcceptor; import org.f1x.v1.SingleSessionAcceptor; import java.io.IOException; import java.util.Timer; import java.util.TimerTask; public class SimpleFixAcceptor extends SingleSessionAcceptor { public SimpleFixAcceptor(int bindPort, SessionID sessionID) { this(bindPort, sessionID, new FixAcceptorSettings()); } public SimpleFixAcceptor(int bindPort, SessionID sessionID, FixAcceptorSettings settings) { super(null, bindPort, new SimpleFixSessionAcceptor(FixVersion.FIX44, sessionID, settings)); } public static void main (String [] args) throws InterruptedException, IOException { final SimpleFixAcceptor acceptor = new SimpleFixAcceptor(2508, new SessionIDBean("SERVER", "CLIENT"), new FixAcceptorSettings()); Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { acceptor.close(); LOGGER.info().append("Exiting...").commit(); } }); acceptor.run(); } private static class SimpleFixSessionAcceptor extends FixSessionAcceptor { private final ByteEnumLookup<Side> ordSideLookup = new ByteEnumLookup<>(Side.class); private final ByteArrayReference symbol = new ByteArrayReference(); private final MessageBuilder mb; private volatile int orderCount; public SimpleFixSessionAcceptor(FixVersion fixVersion, SessionID sessionID, FixAcceptorSettings settings) { super(fixVersion, sessionID, settings); //allocs//scheduleStats(15000); mb = createMessageBuilder(); } @Override protected void processInboundAppMessage(CharSequence msgType, int msgSeqNum, boolean possDup, MessageParser parser) throws IOException { if (Tools.equals(MsgType.ORDER_SINGLE, msgType)) { try { processInboundOrderSingle(parser); } catch (IOException e) { e.printStackTrace(); } } else super.processInboundAppMessage(msgType, msgSeqNum, possDup, parser); } private void scheduleStats(final int intervalInMillis) { TimerTask meter = new TimerTask() { private long lastOrderCount; private final int intervalInSeconds = intervalInMillis / 1000; public void run() { final long currentOrderCount = orderCount; // volatile //allocs//System.out.println("Average orders per second: " + (currentOrderCount-lastOrderCount) / intervalInSeconds); lastOrderCount = currentOrderCount; } }; new Timer("Global Timer", true).scheduleAtFixedRate(meter, intervalInMillis, intervalInMillis); } private void processInboundOrderSingle(MessageParser parser) throws IOException { long clOrdId = -1; double orderPrice = Double.NaN; double orderQty = Double.NaN; Side side = null; while (parser.next()) { switch (parser.getTagNum()) { case FixTags.ClOrdID: clOrdId = parser.getIntValue(); break; case FixTags.Side: side = ordSideLookup.get(parser.getByteValue()); break; case FixTags.Symbol: parser.getByteSequence(symbol); break; case FixTags.Price: orderPrice = parser.getDoubleValue(); break; case FixTags.OrderQty: orderQty = parser.getDoubleValue(); break; } } //LOG.info("Execution report: order " + clOrdId + " " + side + " " + orderQty + " " + symbol.toString() + " $" + orderPrice); orderCount++; sendExecutionReport(clOrdId, side, orderQty, symbol, orderPrice); } private void sendExecutionReport (long clOrdId, Side side, double orderQty, CharSequence symbol, double orderPrice) throws IOException { assert getSessionStatus() == SessionStatus.ApplicationConnected; synchronized (mb) { mb.clear(); mb.setMessageType(MsgType.EXECUTION_REPORT); mb.add(FixTags.ClOrdID, clOrdId); mb.add(FixTags.ExecType, ExecType.NEW); mb.add(FixTags.OrderQty, orderQty); mb.add(FixTags.OrdType, OrdType.LIMIT); mb.add(FixTags.Price, orderPrice); mb.add(FixTags.Side, side); mb.add(FixTags.Symbol, symbol); mb.add(FixTags.SecurityType, SecurityType.FOREIGN_EXCHANGE_CONTRACT); mb.addUTCTimestamp(FixTags.TransactTime, System.currentTimeMillis()); mb.add(FixTags.OrdStatus, OrdStatus.NEW); send(mb); } } } }