/* * Copyright (c) 2012 Jeremy Goetsch * * 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 com.jgoetsch.tradeframework.yahoo; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.URL; import java.text.DateFormat; import java.text.NumberFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.jgoetsch.tradeframework.Contract; import com.jgoetsch.tradeframework.OHLC; import com.jgoetsch.tradeframework.SimpleOHLC; import com.jgoetsch.tradeframework.data.ContractDataSource; import com.jgoetsch.tradeframework.data.DataUnavailableException; import com.jgoetsch.tradeframework.data.FundamentalData; import com.jgoetsch.tradeframework.data.HistoricalDataSource; public class YahooFinanceWebClient implements ContractDataSource<FundamentalData>, HistoricalDataSource { private static Logger log = LoggerFactory.getLogger(YahooFinanceWebClient.class); private static final String fundamentalDataUrl = "http://finance.yahoo.com/d/quotes.csv"; private static final String historicalDataUrl = "http://ichart.finance.yahoo.com/table.csv"; private final DateFormat df = new SimpleDateFormat("y-M-d"); public FundamentalData getDataSnapshot(Contract contract) throws IOException, DataUnavailableException { StringBuilder reqUrl = new StringBuilder(fundamentalDataUrl); reqUrl.append("?s=").append(contract.getSymbol()); reqUrl.append("&f=va2j1r"); BufferedReader content = new BufferedReader(new InputStreamReader(new URL(reqUrl.toString()).openStream())); String fields[] = content.readLine().split(","); content.close(); FundamentalData data = new FundamentalData(); try { data.setVolume(NumberFormat.getNumberInstance().parse(fields[0]).longValue()); } catch (ParseException e) { log.warn("Volume parsing failed", e); } try { data.setAvgVolume(NumberFormat.getNumberInstance().parse(fields[1]).longValue()); } catch (ParseException e) { log.warn("Avg volume parsing failed", e); } try { data.setMarketCap(parseMillions(fields[2])); } catch (ParseException e) { log.warn("Market cap parsing failed", e); } try { data.setPeRatio(NumberFormat.getNumberInstance().parse(fields[2]).doubleValue()); } catch (ParseException e) { log.warn("P/E ratio parsing failed", e); } return data; } private double parseMillions(String num) throws ParseException { double n = NumberFormat.getNumberInstance().parse(num).doubleValue(); if (num.endsWith("M")) return n; else if (num.endsWith("B")) return n * 1000; else return n / 1000000; } public OHLC[] getHistoricalData(Contract contract, Date endDate, int numPeriods, int periodUnit) throws IOException { if (!(periodUnit == HistoricalDataSource.PERIOD_1_DAY || periodUnit == HistoricalDataSource.PERIOD_1_WEEK || periodUnit == HistoricalDataSource.PERIOD_1_MONTH)) throw new IllegalArgumentException("Must specify a period of day, week, or month."); GregorianCalendar start = new GregorianCalendar(); start.setTime(endDate); if (periodUnit == HistoricalDataSource.PERIOD_1_DAY) start.add(Calendar.DATE, -numPeriods); else if (periodUnit == HistoricalDataSource.PERIOD_1_WEEK) start.add(Calendar.WEEK_OF_YEAR, -numPeriods); else if (periodUnit == HistoricalDataSource.PERIOD_1_MONTH) start.add(Calendar.WEEK_OF_YEAR, -numPeriods); GregorianCalendar end = new GregorianCalendar(); end.setTime(endDate); StringBuilder reqUrl = new StringBuilder(historicalDataUrl); reqUrl.append("?s=").append(contract.getSymbol()); reqUrl.append("&a=").append(start.get(Calendar.MONTH)); reqUrl.append("&b=").append(start.get(Calendar.DAY_OF_MONTH)); reqUrl.append("&c=").append(start.get(Calendar.YEAR)); reqUrl.append("&d=").append(end.get(Calendar.MONTH)); reqUrl.append("&e=").append(end.get(Calendar.DAY_OF_MONTH)); reqUrl.append("&f=").append(end.get(Calendar.YEAR)); reqUrl.append("&g="); if (periodUnit == HistoricalDataSource.PERIOD_1_DAY) reqUrl.append("d"); else if (periodUnit == HistoricalDataSource.PERIOD_1_WEEK) reqUrl.append("w"); else reqUrl.append("m"); reqUrl.append("&ignore=.csv"); ArrayList<OHLC> prices = new ArrayList<OHLC>(); BufferedReader content = new BufferedReader(new InputStreamReader(new URL(reqUrl.toString()).openStream())); String line; for (line = content.readLine(); line != null; line = content.readLine()) { String fields[] = line.split(","); if (fields.length >= 7) { try { SimpleOHLC ohlc = new SimpleOHLC(); ohlc.setDate(df.parse(fields[0])); ohlc.setOpen(Double.parseDouble(fields[1])); ohlc.setHigh(Double.parseDouble(fields[2])); ohlc.setLow(Double.parseDouble(fields[3])); ohlc.setClose(Double.parseDouble(fields[4])); ohlc.setVolume(Long.parseLong(fields[5])); prices.add(ohlc); } catch (ParseException e) { } } } while (line != null); content.close(); return prices.toArray(new OHLC[0]); } public void close() throws IOException { } }