package org.joone.io;
import java.io.*;
import java.text.*;
import java.net.URL;
import java.util.*;
import org.joone.log.*;
import org.joone.net.NetCheck;
import org.joone.exception.JooneRuntimeException;
import org.joone.engine.NetErrorManager;
/**
* The YahooFinanceInputSynapse provides support for financial data input from financial markets. The
* synapse contacts YahooFinance services and downloads historical data for the chosen symbol and date range.
* Finally the data is presented to the network in reverse date order i.e oldest first.
* This synapse provides the following info ..
* Open as column 1
* High as column 2
* Low as column 3
* Close as column 4.
* Volume as column 5.
* Adj.Close as column 6.
* For the particular stock symbol.
*
* Developer Notes :
* This YahooFinanceInputSynapse uses the following format to extract stock financial information from the Yahoo Network
.
* http://table.finance.yahoo.com/table.csv?a=8&b=1&c=2002&d=11&e=3&f=2002&s=tsco.l&y=0&g=d&ignore=.csv
*
* a = From Month 0 - 11
* b = From Day 1-31
* c = From Year XXXX
* d = To Month 0-11
* e = To Day 1-31
* f = To Year XXXX
* s = Symbol
* y = [record] from record to + 200 records
* g=[d] or[m] or [y] - daily or monthly or yearly
* ignore = .csv
*
*/
public class YahooFinanceInputSynapse extends StreamInputSynapse {
/** The object used when logging debug,errors,warnings and info. */
private static final ILogger log = LoggerFactory.getLogger(YahooFinanceInputSynapse.class);
String [] months = new String [] {"January","February","March","April","May","June","July","August","September","October","November","December"};
String [] frequency = new String [] {"Daily","Weekly","Monthly"};
String [] freq_conv = new String [] {"d","w","m"};
String Symbol = new String("");
DateFormat date_formater = DateFormat.getDateInstance(DateFormat.MEDIUM);
Calendar CalendarStart = Calendar.getInstance();
Calendar CalendarEnd = Calendar.getInstance();
String DateStart = new String(date_formater.format(CalendarStart.getTime()));
String DateEnd = new String(date_formater.format(CalendarEnd.getTime()));
String Period = new String("Daily");
private transient Date startDate = CalendarStart.getTime();
private transient Date endDate = CalendarEnd.getTime();
private Vector StockData [] = new Vector [6]; // Holds all the data + optional data, oldest first.
private Vector StockDates = new Vector(); // Holds the Dates associated with each row of data.
String [] ColumnNames = new String [] {"Date","Open","High","Low","Close","Volume","Adj. Close"}; // Ignore lines with these names in
static final long serialVersionUID = 1301769209320717393L;
/**
* Constructor for the YahooFinanceInputSynapse object
*/
public YahooFinanceInputSynapse() {
super();
}
/**
* Gets the name of the symbol
*
* @return The Symbol name
*/
public String getSymbol() {
return Symbol;
}
/**
* Gets year to start data retrieval from.
*
* @return The year to start from
* @deprecated Use getStartDate instead
*/
public String getDateStart() {
return DateStart;
}
/**
* Gets year to end data retrieval from
*
* @return The year to end on
* @deprecated Use getEndDate instead
*/
public String getDateEnd() {
return DateEnd;
}
/**
* Gets the period for data retrieval.
*
* @return The month to end on
*/
public String getPeriod() {
return Period;
}
/**
* Gets the dates associated with each row of data.
*/
public Vector getStockDates() {
return(StockDates);
}
/**
* Gets the stock data retrieived by this synapse. Returns the data in a Vector array of length 5.
* In column 0 Open data.
* In column 1 High
* In column 2 Low
* In column 3 Close
* In column 4 Volume
* In column 5 Adj.Close
*
*/
public Vector [] getStockData() {
return(StockData);
}
/**
* Reads this YahooFinanceInputSynapse object into memory from the specified object stream.
*
* @param in The object input stream that this object should be read from
* @exception IOException The Input Output Exception
* @exception ClassNotFoundException The class not found exception
*/
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
super.readObjectBase(in);
if (in.getClass().getName().indexOf("xstream") == -1) {
Symbol = (String) in.readObject();
DateStart = (String) in.readObject();
DateEnd = (String) in.readObject();
Period = (String) in.readObject();
}
if (!isBuffered() || (getInputVector().size() == 0)) {
initInputStream();
}
try {
startDate = date_formater.parse(DateStart);
endDate = date_formater.parse(DateEnd);
} catch (ParseException ex) {
log.error("Invalid Date: start:"+DateStart+" end:"+DateEnd);
}
}
/**
* Sets the name of the database jdbc driver.
*
* @param newSymbol The new stock symbol to retrieve the data with.
* @deprecated Use setEndDate instead
*/
public void setSymbol(java.lang.String newSymbol) {
// Only set if it actually has changed
if ( !Symbol.equals(newSymbol)) {
Symbol = newSymbol;
this.resetInput();
this.setTokens(null);
}
}
/**
* Gets the the data from which data is retrieved.
*
* @param newDataStart The data from which data is retrieved.
* @deprecated Use setStartDate instead
*/
public void setDateStart(String newDateStart) {
// Only set if it actually has changed
if (!DateStart.equals(newDateStart)) {
DateStart = newDateStart;
this.resetInput();
this.setTokens(null);
}
}
/**
* Gets the the data to which data is retrieved.
*
* @param newDateEnd The date to which data is retrieved.
*/
public void setDateEnd(String newDateEnd) {
// Only set if it actually has changed
if (!DateEnd.equals(newDateEnd)) {
DateEnd = newDateEnd;
this.resetInput();
this.setTokens(null);
}
}
/**
* Sets the period with which to retrieve data should be one of "Daily" or "Monthly" or "Yearly".
*
* @param newPeriod The period with which data is retieved.
*/
public void setPeriod(String newPeriod) {
// Only set if it actually has changed
if (!Period.equals(newPeriod)) {
Period = newPeriod;
this.resetInput();
this.setTokens(null);
}
}
/**
* Writes this YahooFInanceSynapseInput object to the ObjectOutputStream out.
*
* @param out The ObjectOutputSteeam that this object should be written to
* @exception IOException The Input Output Exception if any
*/
private void writeObject(ObjectOutputStream out) throws IOException {
super.writeObjectBase(out);
if (out.getClass().getName().indexOf("xstream") == -1) {
out.writeObject(Symbol);
out.writeObject(DateStart);
out.writeObject(DateEnd);
out.writeObject(Period);
}
}
/**
* Connects to Yahoo FInancial Services and obtains the historical data for the specifed symbol and data range.
*/
protected void initInputStream() throws JooneRuntimeException {
String final_patterns = new String(""); // A buffer of final_patterns to present to the Tokenizer
int start=0;
String myUrl = new String(""); // Used to construct the URL to obtain the data
String cperiod = "d"; // Default char period to 'd' for Daily
for ( int i=0;i 0) && (addedData <= 200)) {
myUrl = new String("http://table.finance.yahoo.com/table.csv?a="+CalendarStart.get(Calendar.MONTH)+"&b="+CalendarStart.get(Calendar.DAY_OF_MONTH)+"&c="+CalendarStart.get(Calendar.YEAR)+"&d="+CalendarEnd.get(Calendar.MONTH)+"&e="+CalendarEnd.get(Calendar.DAY_OF_MONTH)+"&f="+CalendarEnd.get(Calendar.YEAR)+"&s="+Symbol+"&g="+cperiod+"&z=200&y="+start+"&ignore=.csv");
addedData = addURLToMemory(new URL(myUrl));
start += 200;
}
} catch ( IOException ex ) {
log.error( "Error obtaining data from YahooFInance. Error message is "+ex.getMessage());
//throw new JooneRuntimeException(ex.getMessage());
if ( getMonitor() != null )
new NetErrorManager(getMonitor(),"Error obtaining data from YahooFInance."+ex.getMessage());
return;
}
log.info("Loaded Yahoo Fianance data ok.");
// Compose final pattern to give to network, also give in reverse order so oldest date first
for ( int i=StockData[0].size()-1;i>=0;i--) {
// OPEN
final_patterns += ((Double)StockData[0].elementAt(i)).toString();
// HIGH
final_patterns += ";"+((Double)StockData[1].elementAt(i)).toString();
// LOW
final_patterns += ";"+((Double)StockData[2].elementAt(i)).toString();
// CLOSE
final_patterns += ";"+((Double)StockData[3].elementAt(i)).toString();
// VOLUME
final_patterns += ";"+((Double)StockData[4].elementAt(i)).toString();
// ADJ. CLOSE
final_patterns += ";"+((Double)StockData[5].elementAt(i)).toString();
final_patterns += '\n';
}
try{
StreamInputTokenizer sit;
if (getMaxBufSize() > 0)
sit = new StreamInputTokenizer(new StringReader(final_patterns), getMaxBufSize());
else
sit = new StreamInputTokenizer(new StringReader(final_patterns));
super.setTokens(sit);
} catch (IOException ex) {
// Use Log4j
log.error( "IOException thrown while initializing the YahooFinanceInputStream. Message is : " + ex.getMessage()); // LOG4J
if ( getMonitor() != null )
new NetErrorManager(getMonitor(),"Error while trying to parse Yahoo Finance data. Message is : "+ex.getMessage());
}
} // End of if period is null
} // End if not Year Start
} // End if not Day Start
} // end if no Symbol
} // End method initInputStream
/**
* Adds data from a URL in CSV format to Memory
* @return the number of lines added to the buffer
*/
private int addURLToMemory(URL Data) throws IOException {
LineNumberReader url_reader = null;
String Line = new String("");
boolean IgnoreHeader = true;
boolean added_data = true;
boolean Docontinue = true;
log.debug(Data.getProtocol()+"://"+Data.getHost()+Data.getFile());
int initSize = 0;
// Check that the URL is not null
if ( Data != null) {
url_reader = new LineNumberReader(new InputStreamReader(new BufferedInputStream(Data.openStream())));
// Read the first line
Line = url_reader.readLine();
if ( StockDates == null)StockDates = new Vector();
if ( (StockData == null)||(StockData.length < 6))StockData = new Vector[6];
// Init Pattern list
if ( StockData[0] == null )StockData[0] = new Vector(); // Open
if ( StockData[1] == null )StockData[1] = new Vector(); // High
if ( StockData[2] == null )StockData[2] = new Vector(); // Low
if ( StockData[3] == null )StockData[3] = new Vector(); // Close
if ( StockData[4] == null )StockData[4] = new Vector(); // Volume
if ( StockData[5] == null )StockData[5] = new Vector(); // Adj.Close
initSize = StockData[0].size();
while ( (Line != null) && (!Line.equals("")) && (Docontinue == true)) {
if ( IgnoreHeader == true) // Just throw header line away
{
if ( Line.indexOf(ColumnNames[0]) < 0) {
if ( Line.indexOf(",")!=-1 ) // Check for bad data
{
StringTokenizer tokens = new StringTokenizer(Line, ",\n");
if (tokens.countTokens() >= 7) {
added_data = true;
String _data = tokens.nextToken();
StockDates.addElement(_data); // Get Stock Date for row
// log.debug(_data);
StockData[0].add(Double.valueOf(tokens.nextToken())); // Add OPEN to pattern vector
StockData[1].add(Double.valueOf(tokens.nextToken())); // Add HIGH to pattern vector
StockData[2].add(Double.valueOf(tokens.nextToken())); // Add LOW to pattern vector
StockData[3].add(Double.valueOf(tokens.nextToken())); // Add CLOSE to pattern vector
StockData[4].add(Double.valueOf(tokens.nextToken())); // Add VOLUME to pattern vector
StockData[5].add(Double.valueOf(tokens.nextToken())); // Add Adj.Close to pattern vector
}
} // End check for bad data
else
Docontinue = false;
}
}
Line = url_reader.readLine();
}
}
int addedData = StockData[0].size() - initSize;
//if ( url_reader != null)
// if ( url_reader.getLineNumber() <= 2) added_data=false; // Consider the data not added if only one line of data
return addedData;
} // End Add URL To Memory
/**
* Check that there are no errors or problems with the properties of this YahooFinanceInputSynapse.
* @return The TreeSet of errors / problems if any.
*/
public TreeSet check() {
TreeSet checks = super.check();
if ( (getDateStart() != null) && (!getDateStart().equals("")) ) {
try {
date_formater.parse(DateStart);
} catch ( ParseException ex ) {
checks.add(new NetCheck(NetCheck.FATAL, "Format for Start Date is invalid." , this));
}
} else
checks.add(new NetCheck(NetCheck.FATAL, "Start Date should be populated." , this));
if ( (getDateEnd() != null) && (!getDateEnd().equals("")) ) {
try {
date_formater.parse(DateEnd);
} catch ( ParseException ex ) {
checks.add(new NetCheck(NetCheck.FATAL, "Format for End Date is invalid." , this));
}
} else
checks.add(new NetCheck(NetCheck.FATAL, "End Date should be populated." , this));
if ( getPeriod()!=null) {
if ( !getPeriod().equals("Daily") && !getPeriod().equals("Weekly") && !getPeriod().equals("Monthly") ) {
checks.add(new NetCheck(NetCheck.FATAL, "Period should be one of 'Daily' , 'Weekly' , 'Monthly'." , this));
}
} else
checks.add(new NetCheck(NetCheck.FATAL, "Period should be one of 'Daily' , 'Weekly' , 'Monthly'." , this));
if ( (getSymbol()== null)||(getSymbol().equals("")))
checks.add(new NetCheck(NetCheck.FATAL, "Symbol should be populated." , this));
return checks;
}
public Date getStartDate() {
return startDate;
}
public void setStartDate(Date startDate) {
this.startDate = startDate;
DateStart = new String(date_formater.format(startDate));
this.resetInput();
this.setTokens(null);
}
public Date getEndDate() {
return endDate;
}
public void setEndDate(Date endDate) {
this.endDate = endDate;
DateEnd = new String(date_formater.format(endDate));
this.resetInput();
this.setTokens(null);
}
}
Ads help maintain this website.