In some diagrams of Bollinger Bands the highlows are colored in red or green depending on if it's in sell trend och buy trend. Is this possible to do in jfreechart?
Like in this picture but without the blue color (I'm only (interested in the green and the red color)
Highlow in several colors
The following code reproduces the chart in the image (the top price chart).
If you look around line 58 you can uncomment the line that will remove the blue line.
If you look around line 58 you can uncomment the line that will remove the blue line.
Code: Select all
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.SegmentedTimeline;
import org.jfree.chart.labels.HighLowItemLabelGenerator;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.CandlestickRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.general.DatasetChangeEvent;
import org.jfree.data.general.DatasetChangeListener;
import org.jfree.data.xy.*;
import java.awt.*;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.StringTokenizer;
public class CandlesticBBDemo{
public static void main(String[] args) {
ChartFrame chartFrame = new ChartFrame("Candlestick + Bollinger Bands", buildChart("IBM"));
chartFrame.setSize(600,360);
chartFrame.setVisible(true);
}
public static JFreeChart buildChart(String symbol) {
DateAxis domainAxis = new DateAxis();
NumberAxis rangeAxis = new NumberAxis("Price");
CandlestickRenderer priceRenderer = new CandlestickRenderer();
XYDataset priceDataset = getDataSet(symbol);
XYLineAndShapeRenderer bbRenderer = new XYLineAndShapeRenderer(true, false);
XYDataset bbDataset = new BollingerBandsDataset((OHLCDataset)priceDataset );
XYPlot mainPlot = new XYPlot(priceDataset, domainAxis, rangeAxis, priceRenderer);
//This is the code that adds the line data to the candlestick chart
mainPlot.setRenderer(1, bbRenderer);
mainPlot.setDataset (1, bbDataset);
//Do some setting up, see the API Doc
rangeAxis.setAutoRangeIncludesZero(false);
domainAxis.setTimeline( SegmentedTimeline.newMondayThroughFridayTimeline() );
priceRenderer.setSeriesPaint(0, Color.BLACK);
priceRenderer.setSeriesToolTipGenerator(0, new HighLowItemLabelGenerator());
priceRenderer.setDrawVolume(false);
bbRenderer.setSeriesPaint(0, Color.GREEN);
bbRenderer.setSeriesPaint(1, Color.BLUE);
bbRenderer.setSeriesPaint(2, Color.RED);
// bbRenderer.setSeriesVisible(1, false); //Uncomment this line to remove the moving average (center line)
return new JFreeChart(symbol, null, mainPlot, false);
}
protected static AbstractXYDataset getDataSet(String symbol) {
java.util.List<OHLCDataItem> dataItems = new ArrayList<OHLCDataItem>();
try {
String strUrl= "http://ichart.finance.yahoo.com/table.csv?s="+symbol+"&a=2&b=1&c=2005&d=6&e=22&f=2005&ignore=.csv";
URL url = new URL(strUrl);
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
DateFormat df = new SimpleDateFormat("y-M-d");
String inputLine;
in.readLine();
while ((inputLine = in.readLine()) != null) {
StringTokenizer st = new StringTokenizer(inputLine, ",");
Date date = df.parse( st.nextToken() );
double open = Double.parseDouble( st.nextToken() );
double high = Double.parseDouble( st.nextToken() );
double low = Double.parseDouble( st.nextToken() );
double close = Double.parseDouble( st.nextToken() );
double volume = Double.parseDouble( st.nextToken() );
double adjClose = Double.parseDouble( st.nextToken() );
OHLCDataItem item = new OHLCDataItem(date, open, high, low, close, volume);
dataItems.add(item);
}
in.close();
}
catch (Exception e) {
e.printStackTrace();
}
Collections.reverse(dataItems);
OHLCDataItem[] data = dataItems.toArray(new OHLCDataItem[dataItems.size()]);
return new DefaultOHLCDataset(symbol, data);
}
private static class BollingerBandsDataset extends AbstractXYDataset implements DatasetChangeListener {
protected OHLCDataset ohlcDataset;
protected int maxLength;
protected int upperBandwidth;
protected int lowerBandwidth;
Double[] upperValues;
Double[] lowerValues;
Double[] averageValues;
public BollingerBandsDataset(OHLCDataset ohlcDataset) {
this(ohlcDataset, 20, 2, 2);
}
public BollingerBandsDataset(OHLCDataset ohlcDataset, int maxLength, int upperBandwidth, int lowerbandwidth) {
this.maxLength = maxLength;
this.upperBandwidth = upperBandwidth;
this.lowerBandwidth = lowerbandwidth;
this.setOhlcDataset(ohlcDataset);
}
public OHLCDataset getOhlcDataset() {
return ohlcDataset;
}
public void setOhlcDataset(OHLCDataset ohlcDataset) {
if (this.ohlcDataset != null)
this.ohlcDataset.removeChangeListener(this);
this.ohlcDataset = ohlcDataset;
this.ohlcDataset.addChangeListener(this);
calculateBollingerBands();
fireDatasetChanged();
}
protected void calculateBollingerBands() {
int size = ohlcDataset.getItemCount(0);
upperValues = new Double[size];
averageValues = new Double[size];
lowerValues = new Double[size];
for(int i=maxLength, n = ohlcDataset.getItemCount(0) ; i<n ; i++){
double sma = this.calculateSMA( i );
double stdDev = this.calculateStdDev( i, sma);
averageValues[i] = sma;
upperValues [i] = sma+(stdDev * upperBandwidth);
lowerValues [i] = sma-(stdDev * lowerBandwidth);
}
}
protected double calculateSMA(int end) {
double total = 0.0;
for (int i = end-maxLength; i<end; i++) {
total += getSourceValue(i);
}
return total / maxLength;
}
protected double calculateStdDev(int end, double sma) {
double stdDev = 0.0;
double total = 0.0;
for (int i = end-maxLength; i<end; i++) {
double dev = getSourceValue(i) - sma;
total += (dev * dev);
}
total = (total / maxLength);
stdDev = Math.sqrt(total);
return stdDev;
}
protected double getSourceValue(int item){
return ohlcDataset.getCloseValue(0, item);
}
public int getSeriesCount() {
return 3;
}
public Comparable getSeriesKey(int series) {
switch (series) {
case 0: return "Bollinger Bands Lower";
case 1: return "Bollinger Bands Average";
case 2: return "Bollinger Bands Upper";
default : return null;
}
}
public int getItemCount(int series) {
return ohlcDataset.getItemCount(0);
}
public Number getX(int series, int item) {
return ohlcDataset.getX(0, item);
}
public Number getY(int series, int item) {
switch (series) {
case 0: return lowerValues[item];
case 1: return averageValues[item];
case 2: return upperValues[item];
default : return null;
}
}
public void datasetChanged(DatasetChangeEvent event) {
calculateBollingerBands();
fireDatasetChanged();
}
}
}
The answer does not come from thinking outside the box, rather the answer comes from realizing the truth; There is no Box. my js site
-
- Posts: 5
- Joined: Tue Apr 01, 2008 10:45 am
Hi!
I tried your code and it acts the way I want except that I would like HighLows instead of CandleSticks. If I implement highlows they are only shown in one color, i'd like it to be like this picture:
http://chart.ecovision.se/scripts/chart ... 0000108656
I tried your code and it acts the way I want except that I would like HighLows instead of CandleSticks. If I implement highlows they are only shown in one color, i'd like it to be like this picture:
http://chart.ecovision.se/scripts/chart ... 0000108656
Well, in that chart the color depends on a buy or sell signal. I don't know how to calculate a buy or sell signal but the following code will change the color of the high/low. You just have to figure out what to put in the method getBuySellColor().
Use this for your high/low renderer.
Use this for your high/low renderer.
Code: Select all
HighLowRenderer priceRenderer = new HighLowRenderer(){
public void drawItem(Graphics2D g2,
XYItemRendererState state,
Rectangle2D dataArea,
PlotRenderingInfo info,
XYPlot plot,
ValueAxis domainAxis,
ValueAxis rangeAxis,
XYDataset dataset,
int series,
int item,
CrosshairState crosshairState,
int pass) {
if (dataset instanceof OHLCDataset) {
Color color = getBuySellColor((OHLCDataset) dataset, series, item);
setSeriesPaint(series, color);
}
super.drawItem(g2, state, dataArea, info, plot, domainAxis, rangeAxis, dataset, series, item, crosshairState, pass);
}
protected Color getBuySellColor(OHLCDataset hld, int series, int item){
if(20 < item && item <50){
return Color.RED;
}else{
return Color.GREEN;
}
}
};
The answer does not come from thinking outside the box, rather the answer comes from realizing the truth; There is no Box. my js site
-
- Posts: 5
- Joined: Tue Apr 01, 2008 10:45 am