package com.quantcomponents.demo.marketdata; import java.net.ConnectException; import java.util.Arrays; import java.util.Collections; import java.util.Currency; import java.util.Date; import java.util.LinkedList; import java.util.List; import java.util.Calendar; import java.util.Random; import java.util.TimeZone; import com.quantcomponents.core.exceptions.RequestFailedException; import com.quantcomponents.core.model.BarSize; import com.quantcomponents.core.model.DataType; import com.quantcomponents.core.model.IContract; import com.quantcomponents.core.model.ITaskMonitor; import com.quantcomponents.core.model.SecurityType; import com.quantcomponents.core.model.beans.ContractBean; import com.quantcomponents.core.model.beans.ContractDescBean; import com.quantcomponents.marketdata.IOHLCPoint; import com.quantcomponents.marketdata.IRealTimeMarketDataProvider; import com.quantcomponents.marketdata.ITickPoint; import com.quantcomponents.marketdata.OHLCPoint; import com.quantcomponents.marketdata.TickPoint; public class SimulatedRealTimeMarketDataProvider implements IRealTimeMarketDataProvider { private static final DataType[] DATA_TYPES = new DataType[] { DataType.MIDPOINT }; private static final BarSize[] BAR_SIZES = new BarSize[] { BarSize.FIVE_SECS }; private static final ContractBean SAMPLE_CONTRACT = new ContractBean(); private static final List<IContract> CONTRACT_LIST = Collections.singletonList((IContract)SAMPLE_CONTRACT); private static final double AVERAGE_PRICE = 500.0; private static final double VOL_PRICE = 0.01; private static final double AVERAGE_VOLUME = 100; private static final double VOL_VOLUME = 0.5; private static final long SLEEP_PERIOD = 5 * 1000L; static { SAMPLE_CONTRACT.setSymbol("AAPL"); SAMPLE_CONTRACT.setExchange("Nasdaq"); SAMPLE_CONTRACT.setCurrency(Currency.getInstance("USD")); SAMPLE_CONTRACT.setMultiplier(1); SAMPLE_CONTRACT.setSecurityType(SecurityType.STK); ContractDescBean desc = new ContractDescBean(); desc.setLongName("Apple Inc."); desc.setTimeZone(TimeZone.getDefault()); SAMPLE_CONTRACT.setContractDescription(desc); } private volatile IRealTimeDataListener barListener; private volatile ITickListener tickListener; private volatile boolean notifyBarListener; private volatile boolean notifyTickListener; private volatile boolean activated; public void activate() { activated = true; new Thread(new Runnable() { @Override public void run() { Random random = new Random(); double lastClose = AVERAGE_PRICE; while (activated) { IOHLCPoint point = generateRandomPoint(random, lastClose, VOL_PRICE, AVERAGE_VOLUME, VOL_VOLUME, new Date()); lastClose = point.getClose(); if (notifyBarListener) { try { barListener.onRealTimeBar(point); } catch (Throwable t) { // burp! } } if (notifyTickListener) { ITickPoint tick = new TickPoint(point.getIndex(), DATA_TYPES[0], point.getClose(), point.getVolume().intValue()); try { tickListener.onTick(tick);; } catch (Throwable t) { // burp! } } try { Thread.sleep(SLEEP_PERIOD); } catch (Throwable t) { // burp! } } }}).start(); } public void deactivate() { activated = false; } @Override public DataType[] availableDataTypes() { return DATA_TYPES; } @Override public BarSize[] availableBarSizes() { return BAR_SIZES; } @Override public List<IContract> searchContracts(IContract criteria, ITaskMonitor taskMonitor) throws ConnectException, RequestFailedException { return CONTRACT_LIST; } @Override public List<IOHLCPoint> historicalBars(IContract contract, Date startDateTime, Date endDateTime, BarSize barSize, DataType dataType, boolean includeAfterHours, ITaskMonitor taskMonitor) throws ConnectException, RequestFailedException { Calendar cal = Calendar.getInstance(); cal.setTime(startDateTime); Random random = new Random(); List<IOHLCPoint> points = new LinkedList<IOHLCPoint>(); double lastClose = AVERAGE_PRICE; for (Date t = cal.getTime(); t.before(endDateTime); t = new Date(t.getTime() + barSize.getDurationInMs())) { IOHLCPoint point = generateRandomPoint(random, lastClose, VOL_PRICE, AVERAGE_VOLUME, VOL_VOLUME, t); points.add(point); lastClose = point.getClose(); } return points; } @Override public void startRealTimeBars(IContract contract, BarSize barSize, DataType dataType, boolean includeAfterHours, IRealTimeDataListener listener) throws ConnectException, RequestFailedException { barListener = listener; notifyBarListener = true; } @Override public void stopRealTimeBars(IContract contract, BarSize barSize, DataType dataType, boolean includeAfterHours, IRealTimeDataListener listener) throws ConnectException { notifyBarListener = false; } @Override public void startTicks(IContract contract, ITickListener listener) throws ConnectException, RequestFailedException { tickListener = listener; notifyTickListener = true; } @Override public void stopTicks(IContract contract, ITickListener listener) throws ConnectException { notifyTickListener = false; } private OHLCPoint generateRandomPoint(Random random, double lastValue, double volPrice, double avgVolume, double volVolume, Date date) { double[] deltas = new double[]{ nextGaussian(random) * volPrice, nextGaussian(random) * volPrice, nextGaussian(random) * volPrice }; Arrays.sort(deltas); double open = lastValue; double high = lastValue + deltas[2]; double low = lastValue + deltas[0]; double close = lastValue + deltas[1]; long volume = (long)(avgVolume + nextGaussian(random) * volVolume); return new OHLCPoint(BAR_SIZES[0], date, open, high, low, close, volume, 0.0, 0); } private double nextGaussian(Random random) { // emergency approx of N ^ -1 return Math.tan((random.nextDouble()-.5)*3.14)/24; } }