package com.activequant.utils.recorder; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.ConcurrentLinkedQueue; import org.apache.log4j.Logger; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.activequant.component.ComponentBase; import com.activequant.domainmodel.ETransportType; import com.activequant.domainmodel.TimeFrame; import com.activequant.domainmodel.exceptions.TransportException; import com.activequant.domainmodel.streaming.MarketDataSnapshot; import com.activequant.interfaces.archive.IArchiveFactory; import com.activequant.interfaces.archive.IArchiveWriter; import com.activequant.interfaces.dao.IDaoFactory; import com.activequant.interfaces.transport.ITransportFactory; import com.activequant.interfaces.utils.IEventListener; import com.activequant.messages.AQMessages; import com.activequant.messages.AQMessages.BaseMessage; import com.activequant.messages.AQMessages.BaseMessage.CommandType; import com.activequant.messages.Marshaller; /** * A market data snapshot recorder. * * @author GhostRider * */ public class MDSRecorder extends ComponentBase { private Logger log = Logger.getLogger(MDSRecorder.class); final Timer t = new Timer(true); final long collectionPhase = 5000l; private final ConcurrentLinkedQueue<MarketDataSnapshot> collectionList = new ConcurrentLinkedQueue<MarketDataSnapshot>(); // private SNMPReporter snmpReporter; private Marshaller marshaller = new Marshaller(); private IArchiveWriter rawWriter = null; class InternalTimerTask extends TimerTask { int counter; @Override public void run() { Object o = collectionList.poll(); counter = 0; while (o != null) { store((MarketDataSnapshot) o); o = collectionList.poll(); } log.info("Collected " + counter + " events. "); if (counter > 0) { try { rawWriter.commit(); log.info("Committed " + counter); // snmpReporter.addValue("MDSEVENTS", counter); } catch (Exception e) { e.printStackTrace(); log.warn("Error while committing. ", e); } } t.schedule(new InternalTimerTask(), (collectionPhase - System.currentTimeMillis() % collectionPhase)); } public void store(MarketDataSnapshot mds) { if (mds == null) return; counter++; String seriesId = mds.getMdiId(); if (mds.getBidSizes() != null && mds.getBidSizes().length > 0) { double bestBidPx = mds.getBidPrices()[0]; double bestBidQ = mds.getBidSizes()[0]; rawWriter.write(seriesId, mds.getTimeStamp(), "BID", bestBidPx); rawWriter.write(seriesId, mds.getTimeStamp(), "BIDQUANTITY", bestBidQ); if (log.isDebugEnabled()) log.debug("Wrote " + seriesId + ", " + mds.getTimeStamp() + ", " + bestBidPx +", "+ bestBidQ); // let's dump all layers available. for(int i=0;i<mds.getBidSizes().length;i++){ rawWriter.write(seriesId, mds.getTimeStamp(), "BID_"+i, mds.getBidPrices()[i]); rawWriter.write(seriesId, mds.getTimeStamp(), "BIDQUANTITY_"+i, mds.getBidSizes()[i]); } // } if (mds.getAskSizes() != null && mds.getAskSizes().length > 0) { double bestAskPx = mds.getAskPrices()[0]; double bestAskQ = mds.getAskSizes()[0]; rawWriter.write(seriesId, mds.getTimeStamp(), "ASK", bestAskPx); rawWriter.write(seriesId, mds.getTimeStamp(), "ASKQUANTITY", bestAskQ); if (log.isDebugEnabled()) log.debug("Wrote " + seriesId + ", " + mds.getTimeStamp() + ", " + bestAskPx +", "+ bestAskQ); // let's dump all layers available. for(int i=0;i<mds.getAskSizes().length;i++){ rawWriter.write(seriesId, mds.getTimeStamp(), "ASK_"+i, mds.getAskPrices()[i]); rawWriter.write(seriesId, mds.getTimeStamp(), "ASKQUANTITY_"+i, mds.getAskSizes()[i]); } } } } public MDSRecorder(ITransportFactory transFac, IArchiveFactory archFac, IDaoFactory daoFac, String mdiFile) throws Exception { super("MDSRecorder", transFac); rawWriter = archFac.getWriter(TimeFrame.RAW); subscribe(mdiFile); t.schedule( new InternalTimerTask(), (collectionPhase - System.currentTimeMillis() % collectionPhase)); // t.schedule(new InternalTimerTask(), (collectionPhase - // System.currentTimeMillis()%collectionPhase)); // t.schedule(new InternalTimerTask(), (collectionPhase - // System.currentTimeMillis()%collectionPhase)); // // snmpReporter = new SNMPReporter(InetAddress.getLocalHost() // .getHostAddress(), 65001); // snmpReporter.registerOID("MDSEVENTS", "1.3.6.1.1.0", ValueMode.VALUE); } private void subscribe(String mdiFile) throws IOException, TransportException { List<String> instruments = new ArrayList<String>(); BufferedReader br = new BufferedReader(new InputStreamReader( new FileInputStream(mdiFile))); String l = br.readLine(); while (l != null) { if (!l.startsWith("#") && !l.isEmpty()) { String symbol = l; // int depth = 1; if (l.indexOf(";") != -1) { String[] s = l.split(";"); symbol = s[0]; // depth = Integer.parseInt(s[1]); } instruments.add(symbol); } l = br.readLine(); } for (String s : instruments) { log.info("Subscribing to " + s); transFac.getReceiver(ETransportType.MARKET_DATA, s).getRawEvent() .addEventListener(new IEventListener<byte[]>() { @Override public void eventFired(byte[] event) { BaseMessage bm; try { bm = marshaller.demarshall(event); if(log.isDebugEnabled()) log.debug("Event type: " + bm.getType()); if (bm.getType().equals(CommandType.MDS)) { MarketDataSnapshot mds = marshaller .demarshall(((AQMessages.MarketDataSnapshot) bm .getExtension(AQMessages.MarketDataSnapshot.cmd))); if(!mds.isResend()) collectionList.add(mds); // else we drop it. } } catch (Exception e) { e.printStackTrace(); log.warn("Exception: ", e); } } }); } br.close(); } /** * @param args * @throws Exception */ public static void main(String[] args) throws Exception { ApplicationContext appContext = new ClassPathXmlApplicationContext( new String[] { args[0] }); IDaoFactory idf = (IDaoFactory) appContext.getBean("ibatisDao"); IArchiveFactory af = (IArchiveFactory) appContext.getBean("archiveFactory"); System.out.println("ARCH FAC: " + af); ITransportFactory transFac = appContext.getBean("jmsTransport", ITransportFactory.class); new MDSRecorder(transFac, af, idf, args[1]); } @Override public String getDescription() { return "MDSRecorder records market data snapshots. "; } }