Scrollable, autoadjustable financial chart

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Locked
dunabur
Posts: 19
Joined: Sat Jun 24, 2017 12:05 pm
antibot: No, of course not.

Scrollable, autoadjustable financial chart

Post by dunabur » Sat Jun 24, 2017 12:23 pm

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

paradoxoff
Posts: 1634
Joined: Sat Feb 17, 2007 1:51 pm

Re: Scrollable, autoadjustable financial chart

Post by paradoxoff » Sun Jun 25, 2017 3:24 pm

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?
I would let JFreeChart handle the scrolling. Can you post the code with the autoadjust issue?
dunabur wrote: Also, is there a way to only update the last data point of a chart?
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: Speaking of performance, I expect lots of parallel open charts, with in peak times updates in the ms timeframe.
Are we talking about a regular update, i.e. a new data points every few or few dozens of ms?

dunabur
Posts: 19
Joined: Sat Jun 24, 2017 12:05 pm
antibot: No, of course not.

Re: Scrollable, autoadjustable financial chart

Post by dunabur » Thu Jul 13, 2017 1:20 pm

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.

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);
    }
}
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.
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.
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?

EDIT: Fixed the code, it now should be runable.

dunabur
Posts: 19
Joined: Sat Jun 24, 2017 12:05 pm
antibot: No, of course not.

Re: Scrollable, autoadjustable financial chart

Post by dunabur » Thu Jul 13, 2017 2:22 pm

Here is the link for the data that the code uses: https://www.dropbox.com/s/rvsawn72dah2j ... g.csv?dl=0

paradoxoff
Posts: 1634
Joined: Sat Feb 17, 2007 1:51 pm

Re: Scrollable, autoadjustable financial chart

Post by paradoxoff » Thu Jul 13, 2017 6:35 pm

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.

dunabur
Posts: 19
Joined: Sat Jun 24, 2017 12:05 pm
antibot: No, of course not.

Re: Scrollable, autoadjustable financial chart

Post by dunabur » Thu Jul 13, 2017 7:57 pm

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.

paradoxoff
Posts: 1634
Joined: Sat Feb 17, 2007 1:51 pm

Re: Scrollable, autoadjustable financial chart

Post by paradoxoff » Sat Jul 15, 2017 2:30 pm

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.

dunabur
Posts: 19
Joined: Sat Jun 24, 2017 12:05 pm
antibot: No, of course not.

Re: Scrollable, autoadjustable financial chart

Post by dunabur » Sat Jul 15, 2017 7:09 pm

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.

paradoxoff
Posts: 1634
Joined: Sat Feb 17, 2007 1:51 pm

Re: Scrollable, autoadjustable financial chart

Post by paradoxoff » Sun Jul 16, 2017 8:45 am

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.

dunabur
Posts: 19
Joined: Sat Jun 24, 2017 12:05 pm
antibot: No, of course not.

Re: Scrollable, autoadjustable financial chart

Post by dunabur » Wed Aug 16, 2017 12:03 pm

@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

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
            }
        });
and also add the imports:

Code: Select all

import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
Now, when panning with ctrl- left mouse, y axis gets updated as well. What a beauty. :)

Locked