Scrollable, autoadjustable financial chart
Scrollable, autoadjustable financial chart
Hi everyone,
I am trying to build a financial chart with features just like can be found in any chart program, the basic ones that it can be updated when new data arrives, that it can be scrolled, and that the chart autoadjusts to the visible highs and lows.
The thing is that I am not sure what the basic approach is. Should I make a chart of all available data, and then zoom in - and let jfreechart handle the scolling(however, I did not get the y axis to autoadjust in that case)? Or should I just take the data I know will be visible, and just plot that(if thats the case, autoadjusting the y axis will be no problem)? Whats performance wise the best approach?
Also, is there a way to only update the last data point of a chart?
I`ve originally done all that in python with matplotlib but that library turned out to be so massively slow that I switched to java / jfreechart. Speaking of performance, I expect lots of parallel open charts, with in peak times updates in the ms timeframe.
Thanks for any pointers
I am trying to build a financial chart with features just like can be found in any chart program, the basic ones that it can be updated when new data arrives, that it can be scrolled, and that the chart autoadjusts to the visible highs and lows.
The thing is that I am not sure what the basic approach is. Should I make a chart of all available data, and then zoom in - and let jfreechart handle the scolling(however, I did not get the y axis to autoadjust in that case)? Or should I just take the data I know will be visible, and just plot that(if thats the case, autoadjusting the y axis will be no problem)? Whats performance wise the best approach?
Also, is there a way to only update the last data point of a chart?
I`ve originally done all that in python with matplotlib but that library turned out to be so massively slow that I switched to java / jfreechart. Speaking of performance, I expect lots of parallel open charts, with in peak times updates in the ms timeframe.
Thanks for any pointers
-
- Posts: 1634
- Joined: Sat Feb 17, 2007 1:51 pm
Re: Scrollable, autoadjustable financial chart
I would let JFreeChart handle the scrolling. Can you post the code with the autoadjust issue?dunabur wrote: Should I make a chart of all available data, and then zoom in - and let jfreechart handle the scolling(however, I did not get the y axis to autoadjust in that case)? Or should I just take the data I know will be visible, and just plot that(if thats the case, autoadjusting the y axis will be no problem)? Whats performance wise the best approach?
None that I know off. If you can make sure that data points are only added and not remove, you could write your own plot that initially draws all the data points to an image, draws new data points on the image, and only draws the image in its draw-method. You will have to recreate the image when the axis range or the size of the chart is changing.dunabur wrote: Also, is there a way to only update the last data point of a chart?
Are we talking about a regular update, i.e. a new data points every few or few dozens of ms?dunabur wrote: Speaking of performance, I expect lots of parallel open charts, with in peak times updates in the ms timeframe.
Re: Scrollable, autoadjustable financial chart
Thanks for your reply paradoxoff.
My code basically is candlestickdemo. I added some code to zoom into a subset of the data but Y axis values do not get updated to the visible min and max values on the chart. Now when I use ctrl-leftmouse drag, I can scroll horizontally, but again the Y axis does not get updated with y min and maxes. I've been going through lots of online resources, the manual and all the demos provided with it but still can't get it to work.
I´d be very grateful if you could show me both how to make the Y axis adjust to the min/max of the chart range that I set and how to autoupdate Y axis when using ctrl-left mouse drag.
EDIT: Fixed the code, it now should be runable.
My code basically is candlestickdemo. I added some code to zoom into a subset of the data but Y axis values do not get updated to the visible min and max values on the chart. Now when I use ctrl-leftmouse drag, I can scroll horizontally, but again the Y axis does not get updated with y min and maxes. I've been going through lots of online resources, the manual and all the demos provided with it but still can't get it to work.
Code: Select all
import org.jfree.chart.*;
import org.jfree.chart.axis.*;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.CandlestickRenderer;
import org.jfree.data.time.DateRange;
import org.jfree.data.xy.*;
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.net.URL;
import java.nio.file.Paths;
import java.text.*;
import java.util.*;
import java.util.List;
public class CandlestickDemo extends JFrame {
private long delta = 60 * 60 * 24 * 30 * 1000L;
public CandlestickDemo(String stockSymbol) {
super("CandlestickDemo");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DateAxis domainAxis = new DateAxis("Date");
NumberAxis rangeAxis = new NumberAxis("Price");
CandlestickRenderer renderer = new CandlestickRenderer();
XYDataset dataset = getDataSet(stockSymbol);
XYPlot mainPlot = new XYPlot(dataset, domainAxis, rangeAxis, renderer);
//Do some setting up, see the API Doc
renderer.setSeriesPaint(0, Color.BLACK);
renderer.setDrawVolume(false);
rangeAxis.setAutoRangeIncludesZero(false);
domainAxis.setTimeline( SegmentedTimeline.newMondayThroughFridayTimeline() );
//experimenting with setting an x range
long minimum = domainAxis.getMinimumDate().getTime();
long maximum = domainAxis.getMaximumDate().getTime();
minimum = minimum + delta * 100L;
maximum = maximum - delta * 100L;
DateRange range = new DateRange(minimum,maximum);
domainAxis.setRange(range);
rangeAxis.setAutoRangeIncludesZero(false);
mainPlot.setDomainPannable(true);
//Now create the chart and chart panel
JFreeChart chart = new JFreeChart(stockSymbol, null, mainPlot, false);
ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new Dimension(600, 300));
chart.getXYPlot().setDomainPannable(true);
this.add(chartPanel);
this.pack();
}
protected AbstractXYDataset getDataSet(String stockSymbol) {
//This is the dataset we are going to create
DefaultOHLCDataset result = null;
//This is the data needed for the dataset
OHLCDataItem[] data;
//This is where we go get the data, replace with your own data source
data = getData(stockSymbol);
//Create a dataset, an Open, High, Low, Close dataset
result = new DefaultOHLCDataset(stockSymbol, data);
return result;
}
//This method uses yahoo finance to get the OHLC data
protected OHLCDataItem[] getData(String stockSymbol) {
List<OHLCDataItem> dataItems = new ArrayList<OHLCDataItem>();
try {
/*
String strUrl= "https://query1.finance.yahoo.com/v7/finance/download/MSFT?period1=1493801037&period2=1496479437&interval=1d&events=history&crumb=y/oR8szwo.9";
URL url = new URL(strUrl);
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
*/
File f = new File("I:\\DATA\\Owncloud\\coding\\eclipse\\demodata\\MSFTlong.csv");
BufferedReader in = new BufferedReader(new FileReader(f));
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();
}
//Data from Yahoo is from newest to oldest. Reverse so it is oldest to newest
Collections.reverse(dataItems);
//Convert the list into an array
OHLCDataItem[] data = dataItems.toArray(new OHLCDataItem[dataItems.size()]);
return data;
}
public static void main(String[] args) {
new CandlestickDemo("MSFT").setVisible(true);
}
}
The problem is that the last dataitem, i.e. the current minute in a live candlestick graph of minutes where every candlestick represents one minute, can change its values until that minute is over. Is it maybe possible to remove the last datapoint and add a new one instead?None that I know off. If you can make sure that data points are only added and not remove, you could write your own plot that initially draws all the data points to an image, draws new data points on the image, and only draws the image in its draw-method. You will have to recreate the image when the axis range or the size of the chart is changing.
EDIT: Fixed the code, it now should be runable.
Re: Scrollable, autoadjustable financial chart
Here is the link for the data that the code uses: https://www.dropbox.com/s/rvsawn72dah2j ... g.csv?dl=0
-
- Posts: 1634
- Joined: Sat Feb 17, 2007 1:51 pm
Re: Scrollable, autoadjustable financial chart
Is the intial chart wrong, or does it get wrong after you try to update? I am asking because I am not seeing code that updates the chart.
Re: Scrollable, autoadjustable financial chart
The initial chart itself is wrong. The Y axis should autoadjust to the viewable min and max within the part of the data that I set with domainAxis.setRange() , however I do not know how. I suspect that once I start scrolling through the chart with ctrl-leftmouse drag, this needs to be set again for every movement, but I do not know how to do that, too.
Thanks for looking into this paradoxoff.
Thanks for looking into this paradoxoff.
-
- Posts: 1634
- Joined: Sat Feb 17, 2007 1:51 pm
Re: Scrollable, autoadjustable financial chart
Does the chart look ok bewfore you start the scrolling?
My assumption is that as soon as you start to pan the chart by dragging the mouse, the values of the range axis are set to fixed values. This, in turn, disables the auto range calculation mechanism.
Try callinf setRangePannable(false) on the XYPlot.
My assumption is that as soon as you start to pan the chart by dragging the mouse, the values of the range axis are set to fixed values. This, in turn, disables the auto range calculation mechanism.
Try callinf setRangePannable(false) on the XYPlot.
Re: Scrollable, autoadjustable financial chart
setRangePannable(false) did have no effect on the Y axis range (The Y range goes from 15 to 70, which are the high/lows of the whole dataset, while the range should go from 15 to aproximately 40, which is the aprox. high/low of the part of the dataset that is visible (using setRange()) on the chart right after executing the code). Unfortunately the Y axis fails to autoadjust before I start scrolling. The Y axis has the same range as if I never had called setRange() (I only set setRange() on the X axis). Well, "fails to" is probably the wrong definition.
I think I am missing the code to set the Y axis to the min/max range of the part of the dataset that is visible. Maybe the X axis does not know that Y has changed and therefore does not update it's range? Or do I have to set the X axis manually?
in TranslateDemo1 it works just fine - when the chart is moved left or right, the X axis autoadjusts. However in that source code, I only see DateAxis.setRange() being used on Y, with no code to update the X axis.
I think I am missing the code to set the Y axis to the min/max range of the part of the dataset that is visible. Maybe the X axis does not know that Y has changed and therefore does not update it's range? Or do I have to set the X axis manually?
in TranslateDemo1 it works just fine - when the chart is moved left or right, the X axis autoadjusts. However in that source code, I only see DateAxis.setRange() being used on Y, with no code to update the X axis.
-
- Posts: 1634
- Joined: Sat Feb 17, 2007 1:51 pm
Re: Scrollable, autoadjustable financial chart
I just dig around in the code opf XYPlot to find the origin of this behaviour, and I may have found the reason. When the range of an axis in an XYPlot is changing, the plot simply fires a PlotChangeEvent. No range adjustements of the other axes are carried out.
If the dataset is changing (as is probably the case in the TranslateDemo), the plot is configuring all ofg its axes. During the "configuration", those axes which have the autoRange flag set to true, recalculate the optimum value range to show all data points.
Unless you want to hack the source code of XYPlot, you can write your own AxisChangeListener, give that a reference to the range axis, and use it as a change listener for the domain axis. If the AxisChangeListener receives a change event, simply call configure() on the range axis.
If the dataset is changing (as is probably the case in the TranslateDemo), the plot is configuring all ofg its axes. During the "configuration", those axes which have the autoRange flag set to true, recalculate the optimum value range to show all data points.
Unless you want to hack the source code of XYPlot, you can write your own AxisChangeListener, give that a reference to the range axis, and use it as a change listener for the domain axis. If the AxisChangeListener receives a change event, simply call configure() on the range axis.
Re: Scrollable, autoadjustable financial chart
@paradoxoff
Thank you so much for your time. I haven't had the chance to implement your suggestions until now. It works! Below the code snippet to make it work on candlestickdemo, insert right after:
and also add the imports:
Now, when panning with ctrl- left mouse, y axis gets updated as well. What a beauty. 
Thank you so much for your time. I haven't had the chance to implement your suggestions until now. It works! Below the code snippet to make it work on candlestickdemo, insert right after
Code: Select all
ChartPanel chartPanel = new ChartPanel(chart);
Code: Select all
chartPanel.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
// process before
super.mouseDragged(e);
rangeAxis.configure();
// process after
}
});
Code: Select all
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
