Pages

Friday, January 1, 2010

Calculate Relative Strength Index (RSI) using Yahoo data

Last post I showed how to get the data from Yahoo, now I used the same data to calculate a index. I choose the RSI, below has the calculation:



The period for the average could be any, in my example has for 9, 14 and 25, the commons period used.

The code below is a BEAN class used to store the price data.

package yahoo;
import java.util.Date;

public class Price {
private final Date date;
private final double open;
private final double high;
private final double low;
private final double close;
private final double volume;

public Date getDate() {
return date;
}

public double getOpen() {
return open;
}

public double getHigh() {
return high;
}

public double getLow() {
return low;
}

public double getClose() {
return close;
}

public double getVolume() {
return volume;
}

public Price(Date date, double open, double high, double low, double close,
double volume) {
super();
this.date = date;
this.open = open;
this.high = high;
this.low = low;
this.close = close;
this.volume = volume;
}
}


The next code is my previous Yahoo Feeder code enhanced to populate a ArrayList using the Price class.


package yahoo;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;

public class YahooFeederUtil {
public static ArrayList getPrices(String symbol)
throws ParseException, IOException {
Calendar oneYearAgo = Calendar.getInstance();
oneYearAgo.add(Calendar.DATE, -366);

Date now = new Date();
URL yahoo = new URL(getFeederURL(symbol, new Date(oneYearAgo
.getTimeInMillis()), now));
URLConnection yc = yahoo.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(yc
.getInputStream()));
String line;

ArrayList prices = new ArrayList();
while ((line = in.readLine()) != null) {
if (!Character.isDigit(line.charAt(0))) {
continue;
}
String[] elements = line.split(",");
Date date = (Date) new SimpleDateFormat("yyyy-MM-dd")
.parse(elements[0]);

prices.add(new Price(date, new Double(elements[1]).doubleValue(),
new Double(elements[2]).doubleValue(), new Double(
elements[3]).doubleValue(), new Double(elements[4])
.doubleValue(), new Double(elements[5])
.doubleValue()));
}
in.close();
return prices;
}

private static String getFeederURL(String symbol, Date from, Date to) {

Calendar fromDate = Calendar.getInstance();
fromDate.setTime(from);

Calendar toDate = Calendar.getInstance();
toDate.setTime(to);
return "http://ichart.finance.yahoo.com/table.csv?s=" + symbol + "&a="
+ String.valueOf(fromDate.get(Calendar.MONTH)) + "&b="
+ String.valueOf(fromDate.get(Calendar.DAY_OF_MONTH)) + "&c="
+ String.valueOf(fromDate.get(Calendar.YEAR)) + "&d="
+ String.valueOf(toDate.get(Calendar.MONTH)) + "&e="
+ String.valueOf(toDate.get(Calendar.DAY_OF_MONTH)) + "&f="
+ String.valueOf(toDate.get(Calendar.YEAR)) + "&g=d"
+ "&ignore=.csv";

}
}



This is the principal code for our indicator, as you can see the constructor will receive the data from Yahoo and consequently calculates the RSI.

package yahoo;

import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Stack;

public class RSI {
private int periodLength;
private final Stack<Averages> avgList;
private final ArrayList<Price> prices;

public RSI(int periodLength, String symbol) throws ParseException, IOException {
super();
this.periodLength = periodLength;
avgList = new Stack<Averages>();
prices = YahooFeederUtil.getPrices(symbol);
}

public double calculate() {
double value = 0;
int pricesSize = prices.size();
int lastPrice = pricesSize - 1;
int firstPrice = lastPrice - periodLength + 1;

double gains = 0;
double losses = 0;
double avgUp = 0;
double avgDown = 0;

double delta = prices.get(lastPrice).getClose()
- prices.get(lastPrice - 1).getClose();
gains = Math.max(0, delta);
losses = Math.max(0, -delta);

if (avgList.isEmpty()) {
for (int bar = firstPrice + 1; bar <= lastPrice; bar++) {
double change = prices.get(bar).getClose()
- prices.get(bar - 1).getClose();
gains += Math.max(0, change);
losses += Math.max(0, -change);
}
avgUp = gains / periodLength;
avgDown = losses / periodLength;
avgList.push(new Averages(avgUp, avgDown));

} else {

Averages avg = avgList.pop();
avgUp = avg.getAvgUp();
avgDown = avg.getAvgDown();
avgUp = ((avgUp * (periodLength - 1)) + gains) / (periodLength);
avgDown = ((avgDown * (periodLength - 1)) + losses)
/ (periodLength);
avgList.add(new Averages(avgUp, avgDown));
}
value = 100 - (100 / (1 + (avgUp / avgDown)));

return Math.round(value);
}

private class Averages {

private final double avgUp;
private final double avgDown;

public Averages(double up, double down) {
this.avgDown = down;
this.avgUp = up;
}

public double getAvgUp() {
return avgUp;
}

public double getAvgDown() {
return avgDown;
}
}

public int getPeriodLength() {
return periodLength;
}
}



Finally, the last code is a simple JUnit class, that I used to test/calculate the RSI for known symbol.
package yahoo;

import java.io.IOException;
import java.text.ParseException;

import junit.framework.TestCase;

public class Test extends TestCase {
private String symbolForTest = "GOOG";
private int nineDaysPeriod = 9;
private int fourteenDaysPeriod = 14;
private int twentyFiveDaysPeriod = 25;

public void testGetPrices() throws Exception {
assertTrue(YahooFeederUtil.getPrices(symbolForTest).size() > 1);
}

public void testRSICalculate() throws Exception {
try {
RSI rsi = new RSI(nineDaysPeriod, symbolForTest);
System.out.println("RSI for a " + rsi.getPeriodLength()
+ " days period is: " + rsi.calculate());

rsi = new RSI(fourteenDaysPeriod, symbolForTest);
System.out.println("RSI for a " + rsi.getPeriodLength()
+ " days period is: " + rsi.calculate());

rsi = new RSI(twentyFiveDaysPeriod, symbolForTest);
System.out.println("RSI for a " + rsi.getPeriodLength()
+ " days period is: " + rsi.calculate());
} catch (ParseException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}

No comments :