package jtrade.io; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.NavigableMap; import java.util.TreeMap; import java.util.zip.GZIPInputStream; import jtrade.Symbol; import jtrade.SymbolFactory; import jtrade.marketfeed.MarketDepth; import jtrade.marketfeed.MarketFeed; import jtrade.marketfeed.Tick; import jtrade.util.Util; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; public class CsvTickFileReader extends BufferedReader implements TickReader { MarketFeed marketFeed; Symbol symbol; DateTimeZone tz; DateTimeFormatter dateFormatter; boolean skipMarketDepth; String[] tmp; public CsvTickFileReader(File file) throws IOException { this(file, null, false); } public CsvTickFileReader(File file, boolean skipMarketDepth) throws IOException { this(file, null, skipMarketDepth); } public CsvTickFileReader(File file, MarketFeed marketFeed) throws IOException { this(file, marketFeed, false); } public CsvTickFileReader(File file, MarketFeed marketFeed, boolean skipMarketDepth) throws IOException { super(file.getPath().endsWith(".gz") ? new InputStreamReader(new GZIPInputStream(new FileInputStream(file), 8192)) : new FileReader(file)); this.marketFeed = marketFeed; this.skipMarketDepth = skipMarketDepth; this.tmp = new String[45]; readHeader(); } private void readHeader() throws IOException { tz = DateTimeZone.getDefault(); dateFormatter = DateTimeFormat.forPattern("yyyyMMdd HH:mm:ss"); String line = null; while ((line = readLine()) != null) { if (line.startsWith("# symbol")) { symbol = SymbolFactory.getSymbol(line.substring(9).trim()); continue; } if (line.startsWith("# timeZone")) { tz = DateTimeZone.forID(line.substring(11).trim()); dateFormatter = dateFormatter.withZone(tz); continue; } if (line.startsWith("# dateFormat")) { dateFormatter = DateTimeFormat.forPattern(line.substring(13).trim()).withZone(tz); continue; } if (line.startsWith("#")) { continue; } if (line.startsWith("date,")) { if (!line.endsWith(",bidsize9")) { skipMarketDepth = true; } return; } } } @Override public Tick readTick() throws IOException { String line = readLine(); if (line == null) { return null; } String[] values = Util.split(line, ',', tmp); try { if (skipMarketDepth || values[8] == null) { return parseTick(values); } return parseTickMarketDepth(values); } catch (Exception e) { throw new IOException("Failed to read tick, unknown format: " + line, e); } } private Tick parseTick(String[] values) { Tick tick = new Tick(symbol, dateFormatter.parseDateTime(values[0]), Double.parseDouble(values[1]), Integer.parseInt(values[2]), Double.parseDouble(values[3]), Integer.parseInt(values[4]), Double.parseDouble(values[5]), Integer.parseInt(values[6]), Integer.parseInt(values[7]), null); return tick; } private Tick parseTickMarketDepth(String[] values) { MarketDepth md = new MarketDepth(10); double[] askPrices = md.getAskPrices(); int[] askSizes = md.getAskSizes(); double askPrice = askPrices[0] = Double.parseDouble(values[1]); int askSize = askSizes[0] = Integer.parseInt(values[2]); for (int i = 8, p = 1; p < 10; i++, p++) { if (values[i].length() == 0) { continue; } double price = Double.parseDouble(values[i]); if (price <= 0.0) { continue; } i++; if (values[i].length() == 0) { continue; } int size = Integer.parseInt(values[i]); if (size <= 0) { continue; } askPrices[p] = price; askSizes[p] = size; } double[] bidPrices = md.getBidPrices(); int[] bidSizes = md.getBidSizes(); double bidPrice = bidPrices[0] = Double.parseDouble(values[3]); int bidSize = bidSizes[0] = Integer.parseInt(values[4]); for (int i = 26, p = 1; p < 10; i++, p++) { if (values[i].length() == 0) { continue; } double price = Double.parseDouble(values[i]); if (price <= 0.0) { continue; } i++; if (values[i].length() == 0) { continue; } int size = Integer.parseInt(values[i]); if (size <= 0) { continue; } bidPrices[p] = price; bidSizes[p] = size; } Tick tick = new Tick(symbol, dateFormatter.parseDateTime(values[0]), askPrice, askSize, bidPrice, bidSize, Double.parseDouble(values[5]), Integer.parseInt(values[6]), Integer.parseInt(values[7]), md); return tick; } @Override public NavigableMap<DateTime, Tick> readTicks() throws IOException { try { NavigableMap<DateTime, Tick> ticks = new TreeMap<DateTime, Tick>(); Tick t = null; while ((t = readTick()) != null) { ticks.put(t.getDateTime(), t); } return ticks; } finally { try { close(); } catch (IOException e) { } } } }