JFreechart candlestick chart strano comportamento sulla resistenza

Questa è una domanda di follow-up da questa domanda .

Quello che succede è il seguente:

Quando lancio il grafico e trascino il grafico, accade qualcosa di strano: ad un certo intervallo, sembra ogni 7 periodi, le candele diventano sempre più piccole finché non sono solo una striscia. Poi, quando trascino ulteriormente, diventano di nuovo più spessi fino a tornare alla dimensione normale. Questo sembra accadere ogni 7 periodi.

Un esempio di questo fenomeno viene visualizzato nelle seguenti 3 immagini:

inserisci la descrizione dell'immagine quiinserisci la descrizione dell'immagine quiinserisci la descrizione dell'immagine qui

Il seguente codice mostrerà esattamente cosa intendo. Basta compilare ed eseguirlo. Quindi premere e tenere premuto CTRL e fare clic e tenere premuto con il mouse sul grafico. Ora prova a trascinare il grafico a destra oa sinistra. Dopo una certa “distanza di trascinamento” noterai il bug.

La mia domanda: come prevenire / soluzione temporanea?

Codice:

  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.xy.*; import javax.swing.*; import java.awt.*; import java.io.*; import java.net.URL; import java.text.*; import java.util.*; import java.util.List; public class CandlestickDemo2 extends JFrame { public CandlestickDemo2(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() ); //Now create the chart and chart panel JFreeChart chart = new JFreeChart(stockSymbol, null, mainPlot, false); ChartPanel chartPanel = new ChartPanel(chart, false); chartPanel.setPreferredSize(new Dimension(600, 300)); mainPlot.setDomainPannable(true); mainPlot.setRangePannable(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 dataItems = new ArrayList(); try { String strUrl= "http://ichart.yahoo.com/table.csv?s=GOOG&a=2&b=1&c=2013&d=4&e=24&f=2013&g=d&ignore=.csv"; URL url = new URL(strUrl); BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream())); DateFormat df = new SimpleDateFormat("yMd"); 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) { EventQueue.invokeLater(new Runnable() { @Override public void run() { new CandlestickDemo2("GOOG").setVisible(true); } }); } } 

Aggiornare

Questo bug è ora un problema segnalato nella pagina sourceforge di JFreeChart.

Questo bug può essere rintracciato qui .

Sono in grado di riprodurre l’effetto descritto. Come prima , l’effetto è visto solo con una SegmentedTimeline ; non è evidente con DefaultTimeline . Sembra co-incidere con il trascinamento attraverso i fine settimana “nascosti” di una lunedi-a-venerdì-timeline , ma non vedo un bug evidente.

Una soluzione alternativa potrebbe essere quella di consentire all’utente di scegliere il TimeLine utilizzando un controllo adiacente, come suggerito in questo esempio . Poiché DefaultTimeline è private , è necessario salvare il risultato da getTimeline() prima di chiamare setTimeline() nel gestore del controllo.

Addendum: ecco una variante del programma che usa un JCheckBox per triggersre la Timeline . Fare clic sulla casella di controllo per abilitare la SegmentedTimeline ; effettuare una panoramica orizzontale per vedere l’effetto (fare clic tenendo premuto il tasto Ctrl su Windows; scegliere Opzione-clic su Mac).

Cronologia predefinita

Cronologia segmentata

 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.xy.*; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.io.*; import java.net.URL; import java.text.*; import java.util.*; import java.util.List; /** * @see https://stackoverflow.com/a/18421887/230513 * @see http://www.jfree.org/forum/viewtopic.php?f=10&t=24521 */ public class CandlestickDemo2 extends JFrame { public CandlestickDemo2(String stockSymbol) { super("CandlestickDemo2"); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); final 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); //Now create the chart and chart panel JFreeChart chart = new JFreeChart(stockSymbol, null, mainPlot, false); ChartPanel chartPanel = new ChartPanel(chart, false); chartPanel.setPreferredSize(new Dimension(600, 300)); mainPlot.setDomainPannable(true); mainPlot.setRangePannable(true); this.add(chartPanel); // Add tiemline toggle final Timeline oldTimeline = domainAxis.getTimeline(); final Timeline newTimeline = SegmentedTimeline.newMondayThroughFridayTimeline(); this.add(new JCheckBox(new AbstractAction("Segmented Timeline") { @Override public void actionPerformsd(ActionEvent e) { JCheckBox jcb = (JCheckBox) e.getSource(); if (jcb.isSelected()) { domainAxis.setTimeline(newTimeline); } else { domainAxis.setTimeline(oldTimeline); } } }), BorderLayout.SOUTH); this.pack(); this.setLocationRelativeTo(null); } private AbstractXYDataset getDataSet(String stockSymbol) { //This is the dataset we are going to create DefaultOHLCDataset result; //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 dataItems = new ArrayList(); try { String strUrl = "http://ichart.yahoo.com/table.csv?s=" + stockSymbol + "&a=4&b=1&c=2013&d=6&e=1&f=2013&g=d&ignore=.csv"; URL url = new URL(strUrl); BufferedReader in = new BufferedReader( new InputStreamReader(url.openStream())); DateFormat df = new SimpleDateFormat("yMd"); 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(System.err); } //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) { EventQueue.invokeLater(new Runnable() { @Override public void run() { new CandlestickDemo2("AAPL").setVisible(true); } }); } }