All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.marketcetera.marketdata.csv.CSVFeed Maven / Gradle / Ivy

There is a newer version: 4.1.1
Show newest version
package org.marketcetera.marketdata.csv;

import static org.marketcetera.marketdata.AssetClass.EQUITY;
import static org.marketcetera.marketdata.AssetClass.FUTURE;
import static org.marketcetera.marketdata.AssetClass.OPTION;
import static org.marketcetera.marketdata.Capability.LATEST_TICK;
import static org.marketcetera.marketdata.Capability.TOP_OF_BOOK;
import static org.marketcetera.marketdata.csv.Messages.CANCEL_REQUEST_FAILED_HANDLE_NOT_FOUND;
import static org.marketcetera.marketdata.csv.Messages.FAILED_TO_START_REQUEST;
import static org.marketcetera.marketdata.csv.Messages.REQUEST_FAILED;

import java.io.File;
import java.io.FileReader;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;

import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVStrategy;
import org.marketcetera.core.NoMoreIDsException;
import org.marketcetera.marketdata.*;
import org.marketcetera.util.log.SLF4JLoggerProxy;
import org.marketcetera.util.misc.ClassVersion;

/**
 * Implementation of the market data feed that reads from a CSV file.
 *
 * 

Market data is available in one or more CSV files. The market data * request specifies a symbol which is matched against a file of the same * name in the specified directory. Market data is read * from the file or files until exhausted. * * @author toli kuznets * @author Colin DuPlantis * @since 2.1.0 * @version $Id: CSVFeed.java 16154 2012-07-14 16:34:05Z colin $ */ @ClassVersion("$Id: CSVFeed.java 16154 2012-07-14 16:34:05Z colin $") public class CSVFeed extends AbstractMarketDataFeed { /** * Returns an instance of CSVFeed. * * @param inProviderName a String value * @return a CSVFeed value * @throws org.marketcetera.core.NoMoreIDsException if a unique identifier could not be generated to * be assigned */ public synchronized static CSVFeed getInstance(String inProviderName) throws NoMoreIDsException { if(sInstance != null) { return sInstance; } sInstance = new CSVFeed(inProviderName); return sInstance; } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return String.format("CSVFeed"); //$NON-NLS-1$ } /** * Create a new CSVFeed instance. * * @param inProviderName a String value * @throws NoMoreIDsException if a unique identifier could not be generated to * be assigned */ private CSVFeed(String inProviderName) throws NoMoreIDsException { super(FeedType.DELAYED, // technically, it's historical inProviderName); setLoggedIn(false); } /* (non-Javadoc) * @see org.marketcetera.marketdata.AbstractMarketDataFeed#start() */ @Override public synchronized void start() { if(getFeedStatus().isRunning()) { throw new IllegalStateException(); } SLF4JLoggerProxy.debug(CSVFeed.class, "CSVFeed starting"); //$NON-NLS-1$ requestExecutor = Executors.newCachedThreadPool(); super.start(); } /* (non-Javadoc) * @see org.marketcetera.marketdata.AbstractMarketDataFeed#stop() */ @Override public synchronized void stop() { SLF4JLoggerProxy.debug(CSVFeed.class, "CSVFeed stopping..."); //$NON-NLS-1$ requestExecutor.shutdownNow(); super.stop(); } /* (non-Javadoc) * @see org.marketcetera.marketdata.MarketDataFeed#getCapabilities() */ @Override public Set getCapabilities() { return capabilities; } /* (non-Javadoc) * @see org.marketcetera.marketdata.MarketDataFeed#getSupportedAssetClasses() */ @Override public Set getSupportedAssetClasses() { return assetClasses; } /* (non-Javadoc) * @see org.marketcetera.marketdata.AbstractMarketDataFeed#doCancel(java.lang.String) */ @Override protected final synchronized void doCancel(String inHandle) { CsvFeedRequest request = requests.remove(inHandle); if(request == null) { CANCEL_REQUEST_FAILED_HANDLE_NOT_FOUND.warn(CSVFeed.class, inHandle); return; } request.stop(); } /* (non-Javadoc) * @see org.marketcetera.marketdata.AbstractMarketDataFeed#doLevelOneMarketDataRequest(java.lang.Object) */ @Override protected final synchronized List doMarketDataRequest(MarketDataRequest inData) { List handleList = new ArrayList(); for(String filename : inData.getSymbols()) { CsvFeedRequest request = new CsvFeedRequest(filename, inData); String handle = request.getHandle(); handleList.add(handle); requests.put(handle, request); } return handleList; } /* (non-Javadoc) * @see org.marketcetera.marketdata.AbstractMarketDataFeed#doLogin(org.marketcetera.marketdata.AbstractMarketDataFeedCredentials) */ @Override protected final boolean doLogin(CSVFeedCredentials inCredentials) { setLoggedIn(true); credentials = inCredentials; return true; } /* (non-Javadoc) * @see org.marketcetera.marketdata.AbstractMarketDataFeed#doLogout() */ @Override protected final void doLogout() { setLoggedIn(false); } /* (non-Javadoc) * @see org.marketcetera.marketdata.AbstractMarketDataFeed#generateToken(quickfix.Message) */ @Override protected final CSVFeedToken generateToken(MarketDataFeedTokenSpec inTokenSpec) throws FeedException { return CSVFeedToken.getToken(inTokenSpec, this); } /* (non-Javadoc) * @see org.marketcetera.marketdata.AbstractMarketDataFeed#getEventTranslator() */ @Override protected final CSVFeedEventTranslator getEventTranslator() { return credentials.getEventTranslator(); } /* (non-Javadoc) * @see org.marketcetera.marketdata.AbstractMarketDataFeed#getMessageTranslator() */ @Override protected final CSVFeedMessageTranslator getMessageTranslator() { return CSVFeedMessageTranslator.getInstance(); } @Override protected final boolean isLoggedIn() { return mLoggedIn; } /* (non-Javadoc) * @see org.marketcetera.marketdata.AbstractMarketDataFeed#afterDoExecute(org.marketcetera.marketdata.AbstractMarketDataFeedToken, java.lang.Exception) */ @Override protected void afterDoExecute(CSVFeedToken inToken, List inHandles, Exception inException) { if(inException != null) { // this means the request failed, do nothing return; } try { for(String actualHandle : inHandles) { CsvFeedRequest request = requests.get(actualHandle); SLF4JLoggerProxy.debug(CSVFeed.class, "Found request {} for handle {}", //$NON-NLS-1$ request, actualHandle); if(request == null) { throw new NullPointerException(); } else { SLF4JLoggerProxy.debug(CSVFeed.class, "Submitting {}", //$NON-NLS-1$ request); requestExecutor.submit(request); } } } catch (Exception e) { throw new IllegalArgumentException(FAILED_TO_START_REQUEST.getText(), e); } } /** * Sets the loggedIn value. * * @param inLoggedIn Logged-in status of the feed */ private void setLoggedIn(boolean inLoggedIn) { mLoggedIn = inLoggedIn; } /** * indicates if the feed has been logged in to */ private boolean mLoggedIn; /** * the credentials object used to initiate the feed */ private CSVFeedCredentials credentials; /** * holds active market data requests */ private final Map requests = new HashMap(); /** * executes and manages market data requests */ private ExecutorService requestExecutor; /** * capabilities for CSVFeed - note that these are not dynamic as Bogus requires no provisioning */ private static final Set capabilities = Collections.unmodifiableSet(EnumSet.of(TOP_OF_BOOK,LATEST_TICK)); /** * supported asset classes */ private static final Set assetClasses = EnumSet.of(EQUITY,OPTION,FUTURE); /** * static instance of CSVFeed */ private static CSVFeed sInstance; /** * counter used to generate unique ids */ private static final AtomicLong counter = new AtomicLong(0); /** * Corresponds to a single market data request submitted to {@link CSVFeed}. * * @author Colin DuPlantis * @version $Id: CSVFeed.java 16154 2012-07-14 16:34:05Z colin $ * @since 1.5.0 */ @ClassVersion("$Id: CSVFeed.java 16154 2012-07-14 16:34:05Z colin $") private class CsvFeedRequest implements Runnable { /* (non-Javadoc) * @see java.lang.Runnable#run() */ @Override public void run() { SLF4JLoggerProxy.debug(CSVFeed.class, "Beginning request {}", //$NON-NLS-1$ this); isRunning.set(true); try { CSVParser parser = null; long start = System.currentTimeMillis(); long count = 0; long delay = credentials.getReplayRate(); if(delay < 0) { delay = 0; } while(isRunning.get()) { if(parser == null) { start = System.currentTimeMillis(); count = 0; parser = new CSVParser(new FileReader(new File(credentials.getMarketdataDirectory(), dataFilename)), CSVStrategy.EXCEL_STRATEGY); } String[] line = parser.getLine(); if(line == null) { Messages.END_OF_DATA_REACHED.debug(org.marketcetera.core.Messages.USER_MSG_CATEGORY, count, System.currentTimeMillis() - start); if(credentials.getReplayEvents() && isRunning.get()) { count = 0; parser = null; continue; } else { break; } } if(delay != 0) { Thread.sleep(delay); } count += 1; dataReceived(handle, CSVQuantum.getQuantum(line, request, credentials.getReplayRate())); } } catch (Exception e) { REQUEST_FAILED.warn(org.marketcetera.core.Messages.USER_MSG_CATEGORY, e, this); } finally { isRunning.set(false); } } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return String.format("CsvFeedRequest [handle=%s, request=%s ]", //$NON-NLS-1$ handle, request); } /** * Create a new CsvFeedRequest instance. * * @param inDataFilename a String value * @param inRequest a MarketDataRequest value */ private CsvFeedRequest(String inDataFilename, MarketDataRequest inRequest) { request = inRequest; dataFilename = inDataFilename; } /** * Stops the currently running request as soon as possible. */ private void stop() { if(!isRunning.get()) { return; } isRunning.set(false); } /** * Gets the request handle. * * @return a String value */ private String getHandle() { return handle; } /** * data filename */ private final String dataFilename; /** * the original request */ private final MarketDataRequest request; /** * the handle assigned to this request */ private final String handle = Long.toHexString(counter.incrementAndGet()); /** * indicates if the request is running or not */ private final AtomicBoolean isRunning = new AtomicBoolean(false); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy